Inlined activation tear-off in the DFG
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 24 Sep 2012 23:12:00 +0000 (23:12 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 24 Sep 2012 23:12:00 +0000 (23:12 +0000)
https://bugs.webkit.org/show_bug.cgi?id=97487

Reviewed by Filip Pizlo.

* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h: Activation tear-off is always inlined now, so I
removed its out-of-line implementation.

* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile): Inlined the variable copy and update
of JSVariableObject::m_registers. This usually turns into < 10 instructions,
which is close to pure win as compared to the operation function call.

* runtime/JSActivation.h:
(JSActivation):
(JSC::JSActivation::registersOffset):
(JSC::JSActivation::tearOff):
(JSC::JSActivation::isTornOff):
(JSC):
(JSC::JSActivation::storageOffset):
(JSC::JSActivation::storage): Tiny bit of refactoring so the JIT can
share the pointer math helper functions we use internally.

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/runtime/JSActivation.h

index f751bff..001cd2d 100644 (file)
@@ -1,3 +1,31 @@
+2012-09-24  Geoffrey Garen  <ggaren@apple.com>
+
+        Inlined activation tear-off in the DFG
+        https://bugs.webkit.org/show_bug.cgi?id=97487
+
+        Reviewed by Filip Pizlo.
+
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h: Activation tear-off is always inlined now, so I
+        removed its out-of-line implementation.
+
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile): Inlined the variable copy and update
+        of JSVariableObject::m_registers. This usually turns into < 10 instructions,
+        which is close to pure win as compared to the operation function call.
+
+        * runtime/JSActivation.h:
+        (JSActivation):
+        (JSC::JSActivation::registersOffset):
+        (JSC::JSActivation::tearOff):
+        (JSC::JSActivation::isTornOff):
+        (JSC):
+        (JSC::JSActivation::storageOffset):
+        (JSC::JSActivation::storage): Tiny bit of refactoring so the JIT can
+        share the pointer math helper functions we use internally.
+
 2012-09-24  Balazs Kilvady  <kilvadyb@homejinni.com>
 
         MIPS: store8 functions added to MacroAssembler.
index 3452b2f..eaa0f47 100644 (file)
@@ -1167,13 +1167,6 @@ JSCell* DFG_OPERATION operationCreateInlinedArguments(
     return result;
 }
 
-void DFG_OPERATION operationTearOffActivation(ExecState* exec, JSCell* activationCell)
-{
-    JSGlobalData& globalData = exec->globalData();
-    NativeCallFrameTracer tracer(&globalData, exec);
-    jsCast<JSActivation*>(activationCell)->tearOff(exec->globalData());
-}
-
 void DFG_OPERATION operationTearOffArguments(ExecState* exec, JSCell* argumentsCell, JSCell* activationCell)
 {
     ASSERT(exec->codeBlock()->usesArguments());
index f86f5cf..3b947ec 100644 (file)
@@ -177,7 +177,6 @@ char* DFG_OPERATION operationLinkConstruct(ExecState*) WTF_INTERNAL;
 JSCell* DFG_OPERATION operationCreateActivation(ExecState*) WTF_INTERNAL;
 JSCell* DFG_OPERATION operationCreateArguments(ExecState*) WTF_INTERNAL;
 JSCell* DFG_OPERATION operationCreateInlinedArguments(ExecState*, InlineCallFrame*) WTF_INTERNAL;
-void DFG_OPERATION operationTearOffActivation(ExecState*, JSCell*) WTF_INTERNAL;
 void DFG_OPERATION operationTearOffArguments(ExecState*, JSCell*, JSCell*) WTF_INTERNAL;
 void DFG_OPERATION operationTearOffInlinedArguments(ExecState*, JSCell*, JSCell*, InlineCallFrame*) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationGetArgumentsLength(ExecState*, int32_t) WTF_INTERNAL;
index 8039ad2..70709b5 100644 (file)
@@ -30,7 +30,7 @@
 #if ENABLE(DFG_JIT)
 
 #include "DFGSlowPathGenerator.h"
-#include "JSVariableObject.h"
+#include "JSActivation.h"
 
 namespace JSC { namespace DFG {
 
@@ -4070,16 +4070,38 @@ void SpeculativeJIT::compile(Node& node)
         
     case TearOffActivation: {
         JSValueOperand activationValue(this, node.child1());
+        GPRTemporary scratch(this);
         
         GPRReg activationValueTagGPR = activationValue.tagGPR();
         GPRReg activationValuePayloadGPR = activationValue.payloadGPR();
+        GPRReg scratchGPR = scratch.gpr();
 
-        JITCompiler::Jump created = m_jit.branch32(JITCompiler::NotEqual, activationValueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
-
-        addSlowPathGenerator(
-            slowPathCall(
-                created, this, operationTearOffActivation, NoResult, activationValuePayloadGPR));
+        JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, activationValueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
+
+        SharedSymbolTable* symbolTable = m_jit.symbolTableFor(node.codeOrigin);
+        int registersOffset = JSActivation::registersOffset(symbolTable);
+
+        int captureEnd = symbolTable->captureEnd();
+        for (int i = symbolTable->captureStart(); i < captureEnd; ++i) {
+            m_jit.loadPtr(
+                JITCompiler::Address(
+                    GPRInfo::callFrameRegister, i * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
+                scratchGPR);
+            m_jit.storePtr(
+                scratchGPR, JITCompiler::Address(
+                    activationValuePayloadGPR, registersOffset + i * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+            m_jit.loadPtr(
+                JITCompiler::Address(
+                    GPRInfo::callFrameRegister, i * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
+                scratchGPR);
+            m_jit.storePtr(
+                scratchGPR, JITCompiler::Address(
+                    activationValuePayloadGPR, registersOffset + i * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+        }
+        m_jit.addPtr(TrustedImm32(registersOffset), activationValuePayloadGPR, scratchGPR);
+        m_jit.storePtr(scratchGPR, JITCompiler::Address(activationValuePayloadGPR, JSActivation::offsetOfRegisters()));
         
+        notCreated.link(&m_jit);
         noResult(m_compileIndex);
         break;
     }
index 8488d26..d7cec27 100644 (file)
@@ -4041,14 +4041,28 @@ void SpeculativeJIT::compile(Node& node)
         ASSERT(!node.codeOrigin.inlineCallFrame);
 
         JSValueOperand activationValue(this, node.child1());
+        GPRTemporary scratch(this);
         GPRReg activationValueGPR = activationValue.gpr();
+        GPRReg scratchGPR = scratch.gpr();
 
-        JITCompiler::Jump created = m_jit.branchTestPtr(JITCompiler::NonZero, activationValueGPR);
-        
-        addSlowPathGenerator(
-            slowPathCall(
-                created, this, operationTearOffActivation, NoResult, activationValueGPR));
-        
+        JITCompiler::Jump notCreated = m_jit.branchTestPtr(JITCompiler::Zero, activationValueGPR);
+
+        SharedSymbolTable* symbolTable = m_jit.symbolTableFor(node.codeOrigin);
+        int registersOffset = JSActivation::registersOffset(symbolTable);
+
+        int captureEnd = symbolTable->captureEnd();
+        for (int i = symbolTable->captureStart(); i < captureEnd; ++i) {
+            m_jit.loadPtr(
+                JITCompiler::Address(
+                    GPRInfo::callFrameRegister, i * sizeof(Register)), scratchGPR);
+            m_jit.storePtr(
+                scratchGPR, JITCompiler::Address(
+                    activationValueGPR, registersOffset + i * sizeof(Register)));
+        }
+        m_jit.addPtr(TrustedImm32(registersOffset), activationValueGPR, scratchGPR);
+        m_jit.storePtr(scratchGPR, JITCompiler::Address(activationValueGPR, JSActivation::offsetOfRegisters()));
+
+        notCreated.link(&m_jit);
         noResult(m_compileIndex);
         break;
     }
index 4429413..fa22918 100644 (file)
@@ -84,6 +84,8 @@ namespace JSC {
         bool isValidIndex(int) const;
         bool isValid(const SymbolTableEntry&) const;
         bool isTornOff();
+        int registersOffset();
+        static int registersOffset(SharedSymbolTable*);
 
     protected:
         static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags;
@@ -99,8 +101,8 @@ namespace JSC {
         NEVER_INLINE PropertySlot::GetValueFunc getArgumentsGetter();
 
         static size_t allocationSize(SharedSymbolTable*);
+        static size_t storageOffset();
 
-        int registerOffset();
         WriteBarrier<Unknown>* storage(); // captureCount() number of registers.
     };
 
@@ -141,17 +143,17 @@ namespace JSC {
         return false;
     }
 
-    inline int JSActivation::registerOffset()
+    inline int JSActivation::registersOffset(SharedSymbolTable* symbolTable)
     {
-        return -symbolTable()->captureStart();
+        return storageOffset() - (symbolTable->captureStart() * sizeof(WriteBarrier<Unknown>));
     }
 
     inline void JSActivation::tearOff(JSGlobalData& globalData)
     {
         ASSERT(!isTornOff());
 
-        int registerOffset = this->registerOffset();
-        WriteBarrierBase<Unknown>* dst = storage() + registerOffset;
+        WriteBarrierBase<Unknown>* dst = reinterpret_cast<WriteBarrierBase<Unknown>*>(
+            reinterpret_cast<char*>(this) + registersOffset(symbolTable()));
         WriteBarrierBase<Unknown>* src = m_registers;
 
         int captureEnd = symbolTable()->captureEnd();
@@ -164,15 +166,19 @@ namespace JSC {
 
     inline bool JSActivation::isTornOff()
     {
-        return m_registers == storage() + registerOffset();
+        return m_registers == reinterpret_cast<WriteBarrierBase<Unknown>*>(
+            reinterpret_cast<char*>(this) + registersOffset(symbolTable()));
+    }
+
+    inline size_t JSActivation::storageOffset()
+    {
+        return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSActivation));
     }
 
     inline WriteBarrier<Unknown>* JSActivation::storage()
     {
         return reinterpret_cast<WriteBarrier<Unknown>*>(
-            reinterpret_cast<char*>(this) +
-                WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSActivation))
-        );
+            reinterpret_cast<char*>(this) + storageOffset());
     }
 
     inline size_t JSActivation::allocationSize(SharedSymbolTable* symbolTable)