Changeset 36401 in webkit for trunk/JavaScriptCore/VM/CTI.cpp


Ignore:
Timestamp:
Sep 14, 2008, 1:18:49 AM (17 years ago)
Author:
[email protected]
Message:

Bug 20821: Cache property transitions to speed up object initialization
https://bugs.webkit.org/show_bug.cgi?id=20821

Reviewed by Cameron Zwarich.

Implement a transition cache to improve the performance of new properties
being added to objects. This is extremely beneficial in constructors and
shows up as a 34% improvement on access-binary-trees in SunSpider (0.8%
overall)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/VM/CTI.cpp

    r36327 r36401  
    585585            emitPutArg(X86::edx, 8); // leave the base in edx
    586586            emitCall(i, Machine::cti_op_put_by_id);
    587             i += 6;
     587            i += 8;
    588588            break;
    589589        }
     
    13051305        case op_put_by_id_generic:
    13061306        case op_put_by_id_replace:
     1307        case op_put_by_id_transition:
    13071308            ASSERT_NOT_REACHED();
    13081309        }
     
    18351836}
    18361837
     1838extern "C" {
     1839
     1840static JSValue* SFX_CALL transitionObject(StructureID* newStructureID, size_t cachedOffset, JSObject* baseObject, JSValue* value)
     1841{
     1842    StructureID* oldStructureID = newStructureID->previousID();
     1843
     1844    baseObject->transitionTo(newStructureID);
     1845
     1846    if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
     1847        baseObject->allocatePropertyStorage(oldStructureID->propertyMap().storageSize(), oldStructureID->propertyMap().size());
     1848
     1849    baseObject->putDirectOffset(cachedOffset, value);
     1850    return baseObject;
     1851}
     1852
     1853}
     1854
     1855static inline bool transitionWillNeedStorageRealloc(StructureID* oldStructureID, StructureID* newStructureID)
     1856{
     1857    if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
     1858        return true;
     1859
     1860    if (oldStructureID->propertyMap().storageSize() < JSObject::inlineStorageCapacity)
     1861        return false;
     1862
     1863    if (oldStructureID->propertyMap().size() != newStructureID->propertyMap().size())
     1864        return true;
     1865
     1866    return false;
     1867}
     1868
     1869void* CTI::privateCompilePutByIdTransition(StructureID* oldStructureID, StructureID* newStructureID, size_t cachedOffset, StructureIDChain* sIDC)
     1870{
     1871    Vector<X86Assembler::JmpSrc, 16> failureCases;
     1872    // check eax is an object of the right StructureID.
     1873    m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
     1874    failureCases.append(m_jit.emitUnlinkedJne());
     1875    m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(oldStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
     1876    failureCases.append(m_jit.emitUnlinkedJne());
     1877    Vector<X86Assembler::JmpSrc> successCases;
     1878
     1879    //  ecx = baseObject
     1880    m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::eax, X86::ecx);
     1881    // proto(ecx) = baseObject->structureID()->prototype()
     1882    m_jit.cmpl_i32m(ObjectType, OBJECT_OFFSET(StructureID, m_type), X86::ecx);
     1883    failureCases.append(m_jit.emitUnlinkedJne());
     1884    m_jit.movl_mr(OBJECT_OFFSET(StructureID, m_prototype), X86::ecx, X86::ecx);
     1885   
     1886    // ecx = baseObject->m_structureID
     1887    for (RefPtr<StructureID>* it = sIDC->head(); *it; ++it) {
     1888        // null check the prototype
     1889        m_jit.cmpl_i32r(reinterpret_cast<intptr_t> (jsNull()), X86::ecx);
     1890        successCases.append(m_jit.emitUnlinkedJe());
     1891
     1892        // Check the structure id
     1893        m_jit.cmpl_i32m(reinterpret_cast<uint32_t>(it->get()), OBJECT_OFFSET(JSCell, m_structureID), X86::ecx);
     1894        failureCases.append(m_jit.emitUnlinkedJne());
     1895       
     1896        m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::ecx, X86::ecx);
     1897        m_jit.cmpl_i32m(ObjectType, OBJECT_OFFSET(StructureID, m_type), X86::ecx);
     1898        failureCases.append(m_jit.emitUnlinkedJne());
     1899        m_jit.movl_mr(OBJECT_OFFSET(StructureID, m_prototype), X86::ecx, X86::ecx);
     1900    }
     1901
     1902    failureCases.append(m_jit.emitUnlinkedJne());
     1903    for (unsigned i = 0; i < successCases.size(); ++i)
     1904        m_jit.link(successCases[i], m_jit.label());
     1905
     1906    X86Assembler::JmpSrc callTarget;
     1907    // Fast case, don't need to do any heavy lifting, so don't bother making a call.
     1908    if (!transitionWillNeedStorageRealloc(oldStructureID, newStructureID)) {
     1909        // Assumes m_refCount can be decremented easily, refcount decrement is safe as
     1910        // codeblock should ensure oldStructureID->m_refCount > 0
     1911        m_jit.subl_i8m(1, reinterpret_cast<void*>(oldStructureID));
     1912        m_jit.addl_i8m(1, reinterpret_cast<void*>(newStructureID));
     1913        m_jit.movl_i32m(reinterpret_cast<uint32_t>(newStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
     1914
     1915        // write the value
     1916        m_jit.movl_mr(OBJECT_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
     1917        m_jit.movl_rm(X86::edx, cachedOffset * sizeof(JSValue*), X86::eax);
     1918    } else {
     1919        // Slow case transition -- we're going to need to quite a bit of work,
     1920        // so just make a call
     1921        m_jit.pushl_r(X86::edx);
     1922        m_jit.pushl_r(X86::eax);
     1923        m_jit.movl_i32r(cachedOffset, X86::eax);
     1924        m_jit.pushl_r(X86::eax);
     1925        m_jit.movl_i32r(reinterpret_cast<uint32_t>(newStructureID), X86::eax);
     1926        m_jit.pushl_r(X86::eax);
     1927        callTarget = m_jit.emitCall();
     1928        m_jit.addl_i32r(4 * sizeof(void*), X86::esp);
     1929    }
     1930    m_jit.ret();
     1931    void* code = m_jit.copy();
     1932    ASSERT(code);
     1933   
     1934    for (unsigned i = 0; i < failureCases.size(); ++i)
     1935        X86Assembler::link(code, failureCases[i], reinterpret_cast<void*>(Machine::cti_op_put_by_id_fail));
     1936
     1937    if (transitionWillNeedStorageRealloc(oldStructureID, newStructureID))
     1938        X86Assembler::link(code, callTarget, reinterpret_cast<void*>(transitionObject));
     1939   
     1940    m_codeBlock->structureIDAccessStubs.append(code);
     1941   
     1942    return code;
     1943}
     1944
    18371945void* CTI::privateArrayLengthTrampoline()
    18381946{
Note: See TracChangeset for help on using the changeset viewer.