2008-10-17 Maciej Stachowiak <mjs@apple.com>
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Oct 2008 11:55:09 +0000 (11:55 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Oct 2008 11:55:09 +0000 (11:55 +0000)
        Reviewed by Cameron Zwarich.

        - speed up transitions that resize the property storage a fair bit

        ~3% speedup on v8 RayTrace benchmark, ~1% on DeltaBlue

        * VM/CTI.cpp:
        (JSC::resizePropertyStorage): renamed from transitionObject, and reduced to just resize
        the object's property storage with one inline call.
        (JSC::CTI::privateCompilePutByIdTransition): Use a separate function for property storage
        resize, but still do all the rest of the work in assembly in that case, and pass the known
        compile-time constants of old and new size rather than structureIDs, saving a bunch of
        redundant memory access.
        * kjs/JSObject.cpp:
        (JSC::JSObject::allocatePropertyStorage): Just call the inline version.
        * kjs/JSObject.h:
        (JSC::JSObject::allocatePropertyStorageInline): Inline version of allocatePropertyStorage
        * masm/X86Assembler.h:
        (JSC::X86Assembler::):
        (JSC::X86Assembler::pushl_i32): Add code to assmeble push of a constant; code originally by Cameron Zwarich.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@37653 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/kjs/JSObject.cpp
JavaScriptCore/kjs/JSObject.h
JavaScriptCore/masm/X86Assembler.h

index 5a505e6db603023422015e991ff4a423cf5a2872..4ac3cba9e7a16c52ca8dadb189326f78db7afdba 100644 (file)
@@ -1,3 +1,26 @@
+2008-10-17  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Cameron Zwarich.
+        
+        - speed up transitions that resize the property storage a fair bit
+        
+        ~3% speedup on v8 RayTrace benchmark, ~1% on DeltaBlue
+
+        * VM/CTI.cpp:
+        (JSC::resizePropertyStorage): renamed from transitionObject, and reduced to just resize
+        the object's property storage with one inline call.
+        (JSC::CTI::privateCompilePutByIdTransition): Use a separate function for property storage
+        resize, but still do all the rest of the work in assembly in that case, and pass the known
+        compile-time constants of old and new size rather than structureIDs, saving a bunch of
+        redundant memory access.
+        * kjs/JSObject.cpp:
+        (JSC::JSObject::allocatePropertyStorage): Just call the inline version.
+        * kjs/JSObject.h:
+        (JSC::JSObject::allocatePropertyStorageInline): Inline version of allocatePropertyStorage
+        * masm/X86Assembler.h:
+        (JSC::X86Assembler::):
+        (JSC::X86Assembler::pushl_i32): Add code to assmeble push of a constant; code originally by Cameron Zwarich.
+
 2008-10-17  Cameron Zwarich  <zwarich@apple.com>
 
         Reviewed by Maciej Stachowiak.
index 93b8af366cd4d44dec4d5e4595ec73fa69f539cf..3c4c3bbf9df09357cc01a80ec2d0fd2d582be083 100644 (file)
@@ -2875,12 +2875,11 @@ void CTI::privateCompilePutByIdReplace(StructureID* structureID, size_t cachedOf
 
 extern "C" {
 
-static JSValue* transitionObject(StructureID* newStructureID, size_t cachedOffset, JSObject* baseObject, JSValue* value)
-{
-    baseObject->transitionTo(newStructureID);
-    baseObject->putDirectOffset(cachedOffset, value);
-    return baseObject;
-}
+    static JSValue* resizePropertyStorage(JSObject* baseObject, size_t oldSize, size_t newSize)
+    {
+        baseObject->allocatePropertyStorageInline(oldSize, newSize);
+        return baseObject;
+    }
 
 }
 
@@ -2927,29 +2926,28 @@ void CTI::privateCompilePutByIdTransition(StructureID* oldStructureID, Structure
         m_jit.link(successCases[i], m_jit.label());
 
     X86Assembler::JmpSrc callTarget;
-    // Fast case, don't need to do any heavy lifting, so don't bother making a call.
-    if (!transitionWillNeedStorageRealloc(oldStructureID, newStructureID)) {
-        // Assumes m_refCount can be decremented easily, refcount decrement is safe as 
-        // codeblock should ensure oldStructureID->m_refCount > 0
-        m_jit.subl_i8m(1, reinterpret_cast<void*>(oldStructureID));
-        m_jit.addl_i8m(1, reinterpret_cast<void*>(newStructureID));
-        m_jit.movl_i32m(reinterpret_cast<uint32_t>(newStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
-
-        // write the value
-        m_jit.movl_mr(OBJECT_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
-        m_jit.movl_rm(X86::edx, cachedOffset * sizeof(JSValue*), X86::eax);
-    } else {
-        // Slow case transition -- we're going to need to quite a bit of work,
-        // so just make a call
+
+    // emit a call only if storage realloc is needed
+    if (transitionWillNeedStorageRealloc(oldStructureID, newStructureID)) {
         m_jit.pushl_r(X86::edx);
-        m_jit.pushl_r(X86::eax);
-        m_jit.movl_i32r(cachedOffset, X86::eax);
-        m_jit.pushl_r(X86::eax);
-        m_jit.movl_i32r(reinterpret_cast<uint32_t>(newStructureID), X86::eax);
+        m_jit.pushl_i32(newStructureID->propertyStorageCapacity());
+        m_jit.pushl_i32(oldStructureID->propertyStorageCapacity());
         m_jit.pushl_r(X86::eax);
         callTarget = m_jit.emitCall();
-        m_jit.addl_i32r(4 * sizeof(void*), X86::esp);
+        m_jit.addl_i32r(3 * sizeof(void*), X86::esp);
+        m_jit.popl_r(X86::edx);
     }
+
+    // Assumes m_refCount can be decremented easily, refcount decrement is safe as 
+    // codeblock should ensure oldStructureID->m_refCount > 0
+    m_jit.subl_i8m(1, reinterpret_cast<void*>(oldStructureID));
+    m_jit.addl_i8m(1, reinterpret_cast<void*>(newStructureID));
+    m_jit.movl_i32m(reinterpret_cast<uint32_t>(newStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
+
+    // write the value
+    m_jit.movl_mr(OBJECT_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
+    m_jit.movl_rm(X86::edx, cachedOffset * sizeof(JSValue*), X86::eax);
+
     m_jit.ret();
     
     X86Assembler::JmpSrc failureJump;
@@ -2967,7 +2965,7 @@ void CTI::privateCompilePutByIdTransition(StructureID* oldStructureID, Structure
         X86Assembler::link(code, failureJump, reinterpret_cast<void*>(Machine::cti_op_put_by_id_fail));
 
     if (transitionWillNeedStorageRealloc(oldStructureID, newStructureID))
-        X86Assembler::link(code, callTarget, reinterpret_cast<void*>(transitionObject));
+        X86Assembler::link(code, callTarget, reinterpret_cast<void*>(resizePropertyStorage));
     
     m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
     
index a7548150f9ae707c8782e00e113468f89a8364e9..010429eff22c5bd0a59b4b8f3da07458874b9b35 100644 (file)
@@ -511,16 +511,7 @@ StructureID* JSObject::createInheritorID()
 
 void JSObject::allocatePropertyStorage(size_t oldSize, size_t newSize)
 {
-    ASSERT(newSize > oldSize);
-
-    JSValue** oldPropertStorage = m_propertyStorage;
-    m_propertyStorage = new JSValue*[newSize];
-
-    for (unsigned i = 0; i < oldSize; ++i)
-        m_propertyStorage[i] = oldPropertStorage[i];
-
-    if (oldPropertStorage != m_inlineStorage)
-        delete [] oldPropertStorage;
+    allocatePropertyStorageInline(oldSize, newSize);
 }
 
 JSObject* constructEmptyObject(ExecState* exec)
index 241cee830f566c086b59127dfe7791627a149572..f690fc11878484ca197dbca3bd6caf12f40e9e15 100644 (file)
@@ -177,6 +177,7 @@ namespace JSC {
         virtual bool isNotAnObjectErrorStub() const { return false; }
 
         void allocatePropertyStorage(size_t oldSize, size_t newSize);
+        void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
         bool usingInlineStorage() const { return m_propertyStorage == m_inlineStorage; }
 
         static const size_t inlineStorageCapacity = 2;
@@ -506,6 +507,20 @@ inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue* value)
     asCell()->put(exec, propertyName, value);
 }
 
+ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize)
+{
+    ASSERT(newSize > oldSize);
+
+    JSValue** oldPropertStorage = m_propertyStorage;
+    m_propertyStorage = new JSValue*[newSize];
+
+    for (unsigned i = 0; i < oldSize; ++i)
+        m_propertyStorage[i] = oldPropertStorage[i];
+
+    if (oldPropertStorage != m_inlineStorage)
+        delete [] oldPropertStorage;
+}
+
 } // namespace JSC
 
 #endif // JSObject_h
index 6112df88d6320ebf130bd5d489f40fda948458bb..dd08d38ef093aa69e8c14c030a4826ec72e9b878 100644 (file)
@@ -196,6 +196,7 @@ public:
         OP_POP_EAX                      = 0x58,
         PRE_OPERAND_SIZE                = 0x66,
         PRE_SSE_66                      = 0x66,
+        OP_PUSH_Iz                      = 0x68,
         OP_IMUL_GvEvIz                  = 0x69,
         OP_GROUP1_EvIz                  = 0x81,
         OP_GROUP1_EvIb                  = 0x83,
@@ -292,6 +293,12 @@ public:
         m_buffer->putByte(OP_GROUP5_Ev);
         emitModRm_opm(GROUP5_OP_PUSH, base, offset);
     }
+
+    void pushl_i32(int imm)
+    {
+        m_buffer->putByte(OP_PUSH_Iz);
+        m_buffer->putInt(imm);
+    }
     
     void popl_r(RegisterID reg)
     {