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());