Title: [90529] trunk/Source/_javascript_Core
Revision
90529
Author
[email protected]
Date
2011-07-06 20:42:02 -0700 (Wed, 06 Jul 2011)

Log Message

2011-07-06  Filip Pizlo  <[email protected]>

        DFG JIT does not support method_check
        https://bugs.webkit.org/show_bug.cgi?id=63972

        Reviewed by Gavin Barraclough.

        * assembler/CodeLocation.h:
        (JSC::CodeLocationPossiblyNearCall::CodeLocationPossiblyNearCall):
        * bytecode/CodeBlock.cpp:
        (JSC::CodeBlock::visitAggregate):
        * bytecode/CodeBlock.h:
        (JSC::MethodCallLinkInfo::MethodCallLinkInfo):
        (JSC::MethodCallLinkInfo::seenOnce):
        (JSC::MethodCallLinkInfo::setSeen):
        * dfg/DFGAliasTracker.h:
        (JSC::DFG::AliasTracker::recordGetMethod):
        * dfg/DFGByteCodeParser.cpp:
        (JSC::DFG::ByteCodeParser::parseBlock):
        * dfg/DFGJITCodeGenerator.cpp:
        (JSC::DFG::JITCodeGenerator::cachedGetById):
        (JSC::DFG::JITCodeGenerator::cachedGetMethod):
        * dfg/DFGJITCodeGenerator.h:
        * dfg/DFGJITCompiler.cpp:
        (JSC::DFG::JITCompiler::compileFunction):
        * dfg/DFGJITCompiler.h:
        (JSC::DFG::JITCompiler::addMethodGet):
        (JSC::DFG::JITCompiler::MethodGetRecord::MethodGetRecord):
        * dfg/DFGNode.h:
        (JSC::DFG::Node::hasIdentifier):
        * dfg/DFGNonSpeculativeJIT.cpp:
        (JSC::DFG::NonSpeculativeJIT::compile):
        * dfg/DFGOperations.cpp:
        * dfg/DFGOperations.h:
        * dfg/DFGRepatch.cpp:
        (JSC::DFG::dfgRepatchGetMethodFast):
        (JSC::DFG::tryCacheGetMethod):
        (JSC::DFG::dfgRepatchGetMethod):
        * dfg/DFGRepatch.h:
        * dfg/DFGSpeculativeJIT.cpp:
        (JSC::DFG::SpeculativeJIT::compile):
        * jit/JITWriteBarrier.h:
        (JSC::JITWriteBarrier::set):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (90528 => 90529)


--- trunk/Source/_javascript_Core/ChangeLog	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/ChangeLog	2011-07-07 03:42:02 UTC (rev 90529)
@@ -1,5 +1,49 @@
 2011-07-06  Filip Pizlo  <[email protected]>
 
+        DFG JIT does not support method_check
+        https://bugs.webkit.org/show_bug.cgi?id=63972
+
+        Reviewed by Gavin Barraclough.
+
+        * assembler/CodeLocation.h:
+        (JSC::CodeLocationPossiblyNearCall::CodeLocationPossiblyNearCall):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::visitAggregate):
+        * bytecode/CodeBlock.h:
+        (JSC::MethodCallLinkInfo::MethodCallLinkInfo):
+        (JSC::MethodCallLinkInfo::seenOnce):
+        (JSC::MethodCallLinkInfo::setSeen):
+        * dfg/DFGAliasTracker.h:
+        (JSC::DFG::AliasTracker::recordGetMethod):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGJITCodeGenerator.cpp:
+        (JSC::DFG::JITCodeGenerator::cachedGetById):
+        (JSC::DFG::JITCodeGenerator::cachedGetMethod):
+        * dfg/DFGJITCodeGenerator.h:
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::compileFunction):
+        * dfg/DFGJITCompiler.h:
+        (JSC::DFG::JITCompiler::addMethodGet):
+        (JSC::DFG::JITCompiler::MethodGetRecord::MethodGetRecord):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasIdentifier):
+        * dfg/DFGNonSpeculativeJIT.cpp:
+        (JSC::DFG::NonSpeculativeJIT::compile):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGRepatch.cpp:
+        (JSC::DFG::dfgRepatchGetMethodFast):
+        (JSC::DFG::tryCacheGetMethod):
+        (JSC::DFG::dfgRepatchGetMethod):
+        * dfg/DFGRepatch.h:
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * jit/JITWriteBarrier.h:
+        (JSC::JITWriteBarrier::set):
+
+2011-07-06  Filip Pizlo  <[email protected]>
+
         DFG JIT op_call implementation will flush registers even when those registers are dead
         https://bugs.webkit.org/show_bug.cgi?id=64023
 

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (90528 => 90529)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2011-07-07 03:42:02 UTC (rev 90529)
@@ -1565,7 +1565,9 @@
 
     for (size_t size = m_methodCallLinkInfos.size(), i = 0; i < size; ++i) {
         if (m_methodCallLinkInfos[i].cachedStructure) {
-            // Both members must be filled at the same time
+            // These members must be filled at the same time, and only after
+            // the MethodCallLinkInfo is set as seen.
+            ASSERT(m_methodCallLinkInfos[i].seenOnce());
             visitor.append(&m_methodCallLinkInfos[i].cachedStructure);
             ASSERT(!!m_methodCallLinkInfos[i].cachedPrototypeStructure);
             visitor.append(&m_methodCallLinkInfos[i].cachedPrototypeStructure);

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.h (90528 => 90529)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2011-07-07 03:42:02 UTC (rev 90529)
@@ -129,25 +129,18 @@
 
     struct MethodCallLinkInfo {
         MethodCallLinkInfo()
+            : seen(false)
         {
         }
 
         bool seenOnce()
         {
-            ASSERT(!cachedStructure);
-            return cachedPrototypeStructure.isFlagged();
+            return seen;
         }
 
         void setSeen()
         {
-            ASSERT(!cachedStructure && !cachedPrototypeStructure);
-            // We use the values of cachedStructure & cachedPrototypeStructure to indicate the
-            // current state.
-            //     - In the initial state, both are null.
-            //     - Once this transition has been taken once, cachedStructure is
-            //       null and cachedPrototypeStructure is set to a nun-null value.
-            //     - Once the call is linked both structures are set to non-null values.
-            cachedPrototypeStructure.setFlagOnBarrier();
+            seen = true;
         }
 
         CodeLocationCall callReturnLocation;
@@ -155,6 +148,7 @@
         JITWriteBarrier<Structure> cachedPrototypeStructure;
         JITWriteBarrier<JSFunction> cachedFunction;
         JITWriteBarrier<JSObject> cachedPrototype;
+        bool seen;
     };
 
     struct GlobalResolveInfo {

Modified: trunk/Source/_javascript_Core/dfg/DFGAliasTracker.h (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGAliasTracker.h	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGAliasTracker.h	2011-07-07 03:42:02 UTC (rev 90529)
@@ -82,6 +82,12 @@
         ASSERT_UNUSED(getById, m_graph[getById].op == GetById);
         m_candidateAliasGetByVal = NoNode;
     }
+    
+    void recordGetMethod(NodeIndex getMethod)
+    {
+        ASSERT_UNUSED(getMethod, m_graph[getMethod].op == GetMethod);
+        m_candidateAliasGetByVal = NoNode;
+    }
 
     void recordPutById(NodeIndex putById)
     {

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2011-07-07 03:42:02 UTC (rev 90529)
@@ -852,12 +852,28 @@
 
             NEXT_OPCODE(op_put_by_val);
         }
+            
+        case op_method_check: {
+            Instruction* getInstruction = currentInstruction + OPCODE_LENGTH(op_method_check);
+            
+            ASSERT(interpreter->getOpcodeID(getInstruction->u.opcode) == op_get_by_id);
+            
+            NodeIndex base = get(getInstruction[2].u.operand);
+            unsigned identifier = getInstruction[3].u.operand;
+            
+            NodeIndex getMethod = addToGraph(GetMethod, OpInfo(identifier), base);
+            set(getInstruction[1].u.operand, getMethod);
+            aliases.recordGetMethod(getMethod);
+            
+            m_currentIndex += OPCODE_LENGTH(op_method_check) + OPCODE_LENGTH(op_get_by_id);
+            continue;
+        }
 
         case op_get_by_id: {
             PROPERTY_ACCESS_OP();
             NodeIndex base = get(currentInstruction[2].u.operand);
             unsigned identifier = currentInstruction[3].u.operand;
-
+            
             NodeIndex getById = addToGraph(GetById, OpInfo(identifier), base);
             set(currentInstruction[1].u.operand, getById);
             aliases.recordGetById(getById);

Modified: trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.cpp (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.cpp	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.cpp	2011-07-07 03:42:02 UTC (rev 90529)
@@ -325,7 +325,7 @@
     }
 }
 
-void JITCodeGenerator::cachedGetById(GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget)
+JITCompiler::Call JITCodeGenerator::cachedGetById(GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget, NodeType nodeType)
 {
     GPRReg scratchGPR;
     
@@ -353,7 +353,20 @@
     m_jit.move(baseGPR, GPRInfo::argumentGPR1);
     m_jit.move(JITCompiler::ImmPtr(identifier(identifierNumber)), GPRInfo::argumentGPR2);
     m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
-    JITCompiler::Call functionCall = appendCallWithExceptionCheck(operationGetByIdOptimize);
+    JITCompiler::Call functionCall;
+    switch (nodeType) {
+    case GetById:
+        functionCall = appendCallWithExceptionCheck(operationGetByIdOptimize);
+        break;
+        
+    case GetMethod:
+        functionCall = appendCallWithExceptionCheck(operationGetMethodOptimize);
+        break;
+        
+    default:
+        ASSERT_NOT_REACHED();
+        return JITCompiler::Call();
+    }
     m_jit.move(GPRInfo::returnValueGPR, resultGPR);
     silentFillAllRegisters(resultGPR);
     
@@ -371,6 +384,8 @@
     
     if (scratchGPR != resultGPR && scratchGPR != InvalidGPRReg)
         unlock(scratchGPR);
+    
+    return functionCall;
 }
 
 void JITCodeGenerator::writeBarrier(MacroAssembler&, GPRReg owner, GPRReg scratch)
@@ -430,6 +445,29 @@
     m_jit.addPropertyAccess(functionCall, checkImmToCall, callToCheck, callToStore, callToSlowCase, callToDone, static_cast<int8_t>(baseGPR), static_cast<int8_t>(valueGPR), static_cast<int8_t>(scratchGPR));
 }
 
+void JITCodeGenerator::cachedGetMethod(GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget)
+{
+    JITCompiler::Call slowCall;
+    JITCompiler::DataLabelPtr structToCompare, protoObj, protoStructToCompare, putFunction;
+    
+    JITCompiler::Jump wrongStructure = m_jit.branchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), structToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
+    protoObj = m_jit.moveWithPatch(JITCompiler::TrustedImmPtr(0), resultGPR);
+    JITCompiler::Jump wrongProtoStructure = m_jit.branchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(resultGPR, JSCell::structureOffset()), protoStructToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
+    
+    putFunction = m_jit.moveWithPatch(JITCompiler::TrustedImmPtr(0), resultGPR);
+    
+    JITCompiler::Jump done = m_jit.jump();
+    
+    wrongStructure.link(&m_jit);
+    wrongProtoStructure.link(&m_jit);
+    
+    slowCall = cachedGetById(baseGPR, resultGPR, identifierNumber, slowPathTarget, GetMethod);
+    
+    done.link(&m_jit);
+    
+    m_jit.addMethodGet(slowCall, structToCompare, protoObj, protoStructToCompare, putFunction);
+}
+
 void JITCodeGenerator::emitCall(Node& node)
 {
     NodeIndex calleeNodeIndex = m_jit.graph().m_varArgChildren[node.firstChild()];

Modified: trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h	2011-07-07 03:42:02 UTC (rev 90529)
@@ -522,8 +522,9 @@
         }
     }
     
-    void cachedGetById(GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
+    JITCompiler::Call cachedGetById(GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), NodeType = GetById);
     void cachedPutById(GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
+    void cachedGetMethod(GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
     
     MacroAssembler::Address addressOfCallData(int idx)
     {

Modified: trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp	2011-07-07 03:42:02 UTC (rev 90529)
@@ -295,6 +295,7 @@
         m_calls.clear();
         m_propertyAccesses.clear();
         m_jsCalls.clear();
+        m_methodGets.clear();
         rewindToLabel(speculativePathBegin);
 
         SpeculationCheckVector noChecks;
@@ -409,6 +410,16 @@
         info.hotPathOther = linkBuffer.locationOfNearCall(m_jsCalls[i].m_fastCall);
     }
     
+    m_codeBlock->addMethodCallLinkInfos(m_methodGets.size());
+    for (unsigned i = 0; i < m_methodGets.size(); ++i) {
+        MethodCallLinkInfo& info = m_codeBlock->methodCallLinkInfo(i);
+        info.cachedStructure.setLocation(linkBuffer.locationOf(m_methodGets[i].m_structToCompare));
+        info.cachedPrototypeStructure.setLocation(linkBuffer.locationOf(m_methodGets[i].m_protoStructToCompare));
+        info.cachedFunction.setLocation(linkBuffer.locationOf(m_methodGets[i].m_putFunction));
+        info.cachedPrototype.setLocation(linkBuffer.locationOf(m_methodGets[i].m_protoObj));
+        info.callReturnLocation = linkBuffer.locationOf(m_methodGets[i].m_slowCall);
+    }
+    
     // FIXME: switch the register file check & arity check over to DFGOpertaion style calls, not JIT stubs.
     linkBuffer.link(callRegisterFileCheck, cti_register_file_check);
     linkBuffer.link(callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck);

Modified: trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h	2011-07-07 03:42:02 UTC (rev 90529)
@@ -268,6 +268,11 @@
         m_propertyAccesses.append(PropertyAccessRecord(functionCall, deltaCheckImmToCall, deltaCallToStructCheck, deltaCallToLoadOrStore, deltaCallToSlowCase, deltaCallToDone,  baseGPR, valueGPR, scratchGPR));
     }
     
+    void addMethodGet(Call slowCall, DataLabelPtr structToCompare, DataLabelPtr protoObj, DataLabelPtr protoStructToCompare, DataLabelPtr putFunction)
+    {
+        m_methodGets.append(MethodGetRecord(slowCall, structToCompare, protoObj, protoStructToCompare, putFunction));
+    }
+    
     void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, bool isCall, unsigned exceptionInfo)
     {
         m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, isCall, exceptionInfo));
@@ -318,6 +323,23 @@
         int8_t m_scratchGPR;
     };
     
+    struct MethodGetRecord {
+        MethodGetRecord(Call slowCall, DataLabelPtr structToCompare, DataLabelPtr protoObj, DataLabelPtr protoStructToCompare, DataLabelPtr putFunction)
+            : m_slowCall(slowCall)
+            , m_structToCompare(structToCompare)
+            , m_protoObj(protoObj)
+            , m_protoStructToCompare(protoStructToCompare)
+            , m_putFunction(putFunction)
+        {
+        }
+        
+        Call m_slowCall;
+        DataLabelPtr m_structToCompare;
+        DataLabelPtr m_protoObj;
+        DataLabelPtr m_protoStructToCompare;
+        DataLabelPtr m_putFunction;
+    };
+    
     struct JSCallRecord {
         JSCallRecord(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, bool isCall, unsigned exceptionInfo)
             : m_fastCall(fastCall)
@@ -336,6 +358,7 @@
     };
 
     Vector<PropertyAccessRecord, 4> m_propertyAccesses;
+    Vector<MethodGetRecord, 4> m_methodGets;
     Vector<JSCallRecord, 4> m_jsCalls;
 };
 

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2011-07-07 03:42:02 UTC (rev 90529)
@@ -128,6 +128,7 @@
     macro(GetById, NodeResultJS | NodeMustGenerate) \
     macro(PutById, NodeMustGenerate) \
     macro(PutByIdDirect, NodeMustGenerate) \
+    macro(GetMethod, NodeResultJS | NodeMustGenerate) \
     macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \
     macro(PutGlobalVar, NodeMustGenerate) \
     \
@@ -266,7 +267,7 @@
 
     bool hasIdentifier()
     {
-        return op == GetById || op == PutById || op == PutByIdDirect;
+        return op == GetById || op == PutById || op == PutByIdDirect || op == GetMethod;
     }
 
     unsigned identifierNumber()

Modified: trunk/Source/_javascript_Core/dfg/DFGNonSpeculativeJIT.cpp (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGNonSpeculativeJIT.cpp	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGNonSpeculativeJIT.cpp	2011-07-07 03:42:02 UTC (rev 90529)
@@ -838,6 +838,20 @@
         break;
     }
 
+    case GetMethod: {
+        JSValueOperand base(this, node.child1());
+        GPRReg baseGPR = base.gpr();
+        GPRTemporary result(this, base);
+        GPRReg resultGPR = result.gpr();
+
+        JITCompiler::Jump notCell = m_jit.branchTestPtr(MacroAssembler::NonZero, baseGPR, GPRInfo::tagMaskRegister);
+
+        cachedGetMethod(baseGPR, resultGPR, node.identifierNumber(), notCell);
+
+        jsValueResult(resultGPR, m_compileIndex);
+        break;
+    }
+
     case PutById: {
         JSValueOperand base(this, node.child1());
         JSValueOperand value(this, node.child2());

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2011-07-07 03:42:02 UTC (rev 90529)
@@ -228,19 +228,19 @@
     return JSValue::encode(baseValue.get(exec, *propertyName, slot));
 }
 
-EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr);
-FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdOptimize);
-EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
+EncodedJSValue operationGetMethodOptimizeWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr);
+FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetMethodOptimize);
+EncodedJSValue operationGetMethodOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
 {
     JSValue baseValue = JSValue::decode(encodedBase);
     PropertySlot slot(baseValue);
     JSValue result = baseValue.get(exec, *propertyName, slot);
 
-    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
-    if (stubInfo.seen)
-        dfgRepatchGetByID(exec, baseValue, *propertyName, slot, stubInfo);
+    MethodCallLinkInfo& methodInfo = exec->codeBlock()->getMethodCallLinkInfo(returnAddress);
+    if (methodInfo.seenOnce())
+        dfgRepatchGetMethod(exec, baseValue, *propertyName, slot, methodInfo);
     else
-        stubInfo.seen = true;
+        methodInfo.setSeen();
 
     return JSValue::encode(result);
 }
@@ -259,6 +259,23 @@
     return JSValue::encode(result);
 }
 
+EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr);
+FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdOptimize);
+EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
+{
+    JSValue baseValue = JSValue::decode(encodedBase);
+    PropertySlot slot(baseValue);
+    JSValue result = baseValue.get(exec, *propertyName, slot);
+
+    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
+    if (stubInfo.seen)
+        dfgRepatchGetByID(exec, baseValue, *propertyName, slot, stubInfo);
+    else
+        stubInfo.seen = true;
+
+    return JSValue::encode(result);
+}
+
 void operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
 {
     operationPutByValInternal<true>(exec, encodedBase, encodedProperty, encodedValue);

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2011-07-07 03:42:02 UTC (rev 90529)
@@ -61,6 +61,7 @@
 EncodedJSValue operationGetById(ExecState*, EncodedJSValue encodedBase, Identifier*);
 EncodedJSValue operationGetByIdBuildList(ExecState*, EncodedJSValue encodedBase, Identifier*);
 EncodedJSValue operationGetByIdOptimize(ExecState*, EncodedJSValue encodedBase, Identifier*);
+EncodedJSValue operationGetMethodOptimize(ExecState*, EncodedJSValue encodedBase, Identifier*);
 EncodedJSValue operationInstanceOf(ExecState*, EncodedJSValue value, EncodedJSValue base, EncodedJSValue prototype);
 void operationThrowHasInstanceError(ExecState*, EncodedJSValue base);
 void operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);

Modified: trunk/Source/_javascript_Core/dfg/DFGRepatch.cpp (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGRepatch.cpp	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGRepatch.cpp	2011-07-07 03:42:02 UTC (rev 90529)
@@ -161,6 +161,63 @@
         dfgRepatchCall(exec->codeBlock(), stubInfo.callReturnLocation, operationGetById);
 }
 
+static void dfgRepatchGetMethodFast(JSGlobalData* globalData, CodeBlock* codeBlock, MethodCallLinkInfo& methodInfo, JSFunction* callee, Structure* structure, JSObject* slotBaseObject)
+{
+    ScriptExecutable* owner = codeBlock->ownerExecutable();
+    
+    RepatchBuffer repatchBuffer(codeBlock);
+
+    // Only optimize once!
+    repatchBuffer.relink(methodInfo.callReturnLocation, operationGetById);
+
+    methodInfo.cachedStructure.set(*globalData, owner, structure);
+    methodInfo.cachedPrototypeStructure.set(*globalData, owner, slotBaseObject->structure());
+    methodInfo.cachedPrototype.set(*globalData, owner, slotBaseObject);
+    methodInfo.cachedFunction.set(*globalData, owner, callee);
+}
+
+static bool tryCacheGetMethod(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, MethodCallLinkInfo& methodInfo)
+{
+    CodeBlock* codeBlock = exec->codeBlock();
+    JSGlobalData* globalData = &exec->globalData();
+    
+    Structure* structure;
+    JSCell* specific;
+    JSObject* slotBaseObject;
+    if (baseValue.isCell()
+        && slot.isCacheableValue()
+        && !(structure = baseValue.asCell()->structure())->isUncacheableDictionary()
+        && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(exec, propertyName, specific)
+        && specific) {
+        
+        JSFunction* callee = (JSFunction*)specific;
+        
+        // Since we're accessing a prototype in a loop, it's a good bet that it
+        // should not be treated as a dictionary.
+        if (slotBaseObject->structure()->isDictionary())
+            slotBaseObject->flattenDictionaryObject(exec->globalData());
+        
+        if (slot.slotBase() == structure->prototypeForLookup(exec)) {
+            dfgRepatchGetMethodFast(globalData, codeBlock, methodInfo, callee, structure, slotBaseObject);
+            return true;
+        }
+        
+        if (slot.slotBase() == baseValue) {
+            dfgRepatchGetMethodFast(globalData, codeBlock, methodInfo, callee, structure, exec->scopeChain()->globalObject->methodCallDummy());
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+void dfgRepatchGetMethod(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, MethodCallLinkInfo& methodInfo)
+{
+    bool cached = tryCacheGetMethod(exec, baseValue, propertyName, slot, methodInfo);
+    if (!cached)
+        dfgRepatchCall(exec->codeBlock(), methodInfo.callReturnLocation, operationGetByIdOptimize);
+}
+
 static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identifier&, const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
     if (!baseValue.isCell()

Modified: trunk/Source/_javascript_Core/dfg/DFGRepatch.h (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGRepatch.h	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGRepatch.h	2011-07-07 03:42:02 UTC (rev 90529)
@@ -34,6 +34,7 @@
 namespace JSC { namespace DFG {
 
 void dfgRepatchGetByID(ExecState*, JSValue, const Identifier&, const PropertySlot&, StructureStubInfo&);
+void dfgRepatchGetMethod(ExecState*, JSValue, const Identifier&, const PropertySlot&, MethodCallLinkInfo&);
 void dfgBuildGetByIDList(ExecState*, JSValue, const Identifier&, const PropertySlot&, StructureStubInfo&);
 void dfgRepatchPutByID(ExecState*, JSValue, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind);
 void dfgLinkCall(ExecState*, CallLinkInfo&, CodeBlock*, JSFunction* callee, MacroAssemblerCodePtr);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (90528 => 90529)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2011-07-07 03:42:02 UTC (rev 90529)
@@ -1019,7 +1019,19 @@
         jsValueResult(resultGPR, m_compileIndex);
         break;
     }
+        
+    case GetMethod: {
+        SpeculateCellOperand base(this, node.child1());
+        GPRTemporary result(this, base);
 
+        GPRReg resultGPR = result.gpr();
+
+        cachedGetMethod(base.gpr(), resultGPR, node.identifierNumber());
+
+        jsValueResult(resultGPR, m_compileIndex);
+        break;
+    }
+
     case PutById: {
         SpeculateCellOperand base(this, node.child1());
         JSValueOperand value(this, node.child2());

Modified: trunk/Source/_javascript_Core/jit/JITWriteBarrier.h (90528 => 90529)


--- trunk/Source/_javascript_Core/jit/JITWriteBarrier.h	2011-07-07 03:18:51 UTC (rev 90528)
+++ trunk/Source/_javascript_Core/jit/JITWriteBarrier.h	2011-07-07 03:42:02 UTC (rev 90529)
@@ -121,6 +121,10 @@
         validateCell(value);
         JITWriteBarrierBase::set(globalData, location, owner, value);
     }
+    void set(JSGlobalData& globalData, JSCell* owner, T* value)
+    {
+        set(globalData, location(), owner, value);
+    }
     T* get() const
     {
         T* result = static_cast<T*>(JITWriteBarrierBase::get());
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to