https://bugs.webkit.org/show_bug.cgi?id=69646
Reviewed by Gavin Barraclough.
Add support for optimising non-method_check calls
to intrinsic functions (eg. when Math.abs, etc are
cached in local variables).
* bytecode/CodeBlock.h:
(JSC::getCallLinkInfoBytecodeIndex):
Support searching CallLinkInfos by bytecode index
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
Add support for linked calls in addition to method_check
when searching for intrinsics
* dfg/DFGNode.h:
(JSC::DFG::Node::hasFunctionCheckData):
(JSC::DFG::Node::function):
Add ability to store a JSFunction* in a node - this is safe
as the function will be marked by the codeblock we're compiling
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::propagateNodePredictions):
(JSC::DFG::Propagator::checkFunctionElimination):
(JSC::DFG::Propagator::performNodeCSE):
Add support for new CheckFunction node, and implement CSE pass.
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
Rather trivial implementation of CheckFunction
* jit/JIT.cpp:
(JSC::JIT::privateCompile):
* jit/JIT.h:
* jit/JITCall.cpp:
(JSC::JIT::compileOpCall):
* jit/JITCall32_64.cpp:
(JSC::JIT::compileOpCall):
Need to propagate bytecode index for calls now.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@96962
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2011-10-07 Oliver Hunt <oliver@apple.com>
+
+ Support direct calls to intrinsic functions
+ https://bugs.webkit.org/show_bug.cgi?id=69646
+
+ Reviewed by Gavin Barraclough.
+
+ Add support for optimising non-method_check calls
+ to intrinsic functions (eg. when Math.abs, etc are
+ cached in local variables).
+
+ * bytecode/CodeBlock.h:
+ (JSC::getCallLinkInfoBytecodeIndex):
+ Support searching CallLinkInfos by bytecode index
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ Add support for linked calls in addition to method_check
+ when searching for intrinsics
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::hasFunctionCheckData):
+ (JSC::DFG::Node::function):
+ Add ability to store a JSFunction* in a node - this is safe
+ as the function will be marked by the codeblock we're compiling
+ * dfg/DFGPropagator.cpp:
+ (JSC::DFG::Propagator::propagateNodePredictions):
+ (JSC::DFG::Propagator::checkFunctionElimination):
+ (JSC::DFG::Propagator::performNodeCSE):
+ Add support for new CheckFunction node, and implement CSE pass.
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ Rather trivial implementation of CheckFunction
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompile):
+ * jit/JIT.h:
+ * jit/JITCall.cpp:
+ (JSC::JIT::compileOpCall):
+ * jit/JITCall32_64.cpp:
+ (JSC::JIT::compileOpCall):
+ Need to propagate bytecode index for calls now.
+
2011-10-07 Dominic Cooney <dominicc@chromium.org>
[JSC] Disable ThreadRestrictionVerifier for JIT ExecutableMemoryHandles
bool hasSeenShouldRepatch : 1;
bool isCall : 1;
bool isDFG : 1;
+ unsigned bytecodeIndex;
bool isLinked() { return callee; }
void unlink(JSGlobalData&, RepatchBuffer&);
return callLinkInfo->callReturnLocation.executableAddress();
}
+ inline unsigned getCallLinkInfoBytecodeIndex(CallLinkInfo* callLinkInfo)
+ {
+ return callLinkInfo->bytecodeIndex;
+ }
+
inline void* getMethodCallLinkInfoReturnLocation(MethodCallLinkInfo* methodCallLinkInfo)
{
return methodCallLinkInfo->callReturnLocation.executableAddress();
{
return *(binarySearch<CallLinkInfo, void*, getCallLinkInfoReturnLocation>(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress.value()));
}
+
+ CallLinkInfo& getCallLinkInfo(unsigned bytecodeIndex)
+ {
+ return *(binarySearch<CallLinkInfo, unsigned, getCallLinkInfoBytecodeIndex>(m_callLinkInfos.begin(), m_callLinkInfos.size(), bytecodeIndex));
+ }
MethodCallLinkInfo& getMethodCallLinkInfo(ReturnAddressPtr returnAddress)
{
case op_call: {
NodeIndex callTarget = get(currentInstruction[1].u.operand);
- if (m_graph.isFunctionConstant(m_codeBlock, callTarget)) {
+ enum { ConstantFunction, LinkedFunction, UnknownFunction } callType;
+
+ if (m_graph.isFunctionConstant(m_codeBlock, callTarget))
+ callType = ConstantFunction;
+ else if (m_profiledBlock->getCallLinkInfo(m_currentIndex).isLinked())
+ callType = LinkedFunction;
+ else
+ callType = UnknownFunction;
+ if (callType != UnknownFunction) {
int argCount = currentInstruction[2].u.operand;
int registerOffset = currentInstruction[3].u.operand;
int firstArg = registerOffset - argCount - RegisterFile::CallFrameHeaderSize;
usesResult = true;
prediction = getPrediction(m_graph.size(), m_currentIndex + OPCODE_LENGTH(op_call));
}
-
- DFG::Intrinsic intrinsic = m_graph.valueOfFunctionConstant(m_codeBlock, callTarget)->executable()->intrinsic();
+ DFG::Intrinsic intrinsic;
+ if (callType == ConstantFunction)
+ intrinsic = m_graph.valueOfFunctionConstant(m_codeBlock, callTarget)->executable()->intrinsic();
+ else {
+ ASSERT(callType == LinkedFunction);
+ JSFunction* function = m_profiledBlock->getCallLinkInfo(m_currentIndex).callee.get();
+ intrinsic = function->executable()->intrinsic();
+ if (intrinsic != NoIntrinsic)
+ addToGraph(CheckFunction, OpInfo(function), callTarget);
+ }
if (handleIntrinsic(usesResult, resultOperand, intrinsic, firstArg, lastArg, prediction)) {
// NEXT_OPCODE() has to be inside braces.
macro(PutScopedVar, NodeMustGenerate | NodeClobbersWorld) \
macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \
macro(PutGlobalVar, NodeMustGenerate | NodeClobbersWorld) \
+ macro(CheckFunction, NodeMustGenerate) \
\
/* Optimizations for array mutation. */\
macro(ArrayPush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
ASSERT(hasMethodCheckData());
return m_opInfo2;
}
-
+
+ bool hasFunctionCheckData()
+ {
+ return op == CheckFunction;
+ }
+
+ JSFunction* function()
+ {
+ ASSERT(hasFunctionCheckData());
+ return reinterpret_cast<JSFunction*>(m_opInfo);
+ }
+
bool hasStructureTransitionData()
{
return op == PutStructure;
case PutById:
case PutByIdDirect:
case CheckStructure:
+ case CheckFunction:
case PutStructure:
case PutByOffset:
break;
}
return NoNode;
}
-
+
NodeIndex getMethodLoadElimination(const MethodCheckData& methodCheckData, unsigned identifierNumber, NodeIndex child1)
{
NodeIndex start = startIndexForChildren(child1);
}
return NoNode;
}
-
+
+ bool checkFunctionElimination(JSFunction* function, NodeIndex child1)
+ {
+ NodeIndex start = startIndexForChildren(child1);
+ for (NodeIndex index = m_compileIndex; index-- > start;) {
+ Node& node = m_graph[index];
+ switch (node.op) {
+ case CheckFunction:
+ if (node.child1() == child1 && node.function() == function)
+ return true;
+ break;
+
+ default:
+ if (clobbersWorld(index))
+ return false;
+ break;
+ }
+ }
+ return false;
+ }
+
bool checkStructureLoadElimination(const StructureSet& structureSet, NodeIndex child1)
{
NodeIndex start = startIndexForChildren(child1);
if (checkStructureLoadElimination(node.structureSet(), node.child1()))
eliminate();
break;
-
+
+ case CheckFunction:
+ if (checkFunctionElimination(node.function(), node.child1()))
+ eliminate();
+ break;
+
case GetPropertyStorage:
setReplacement(getPropertyStorageLoadElimination(node.child1()));
break;
break;
}
+ case CheckFunction: {
+ SpeculateCellOperand function(this, node.child1());
+ speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, function.gpr(), JITCompiler::TrustedImmPtr(node.function())));
+ noResult(m_compileIndex);
+ break;
+ }
+
case CheckStructure: {
SpeculateCellOperand base(this, node.child1());
integerResult(resultGPR, m_compileIndex);
break;
}
-
+ case CheckFunction: {
+ SpeculateCellOperand function(this, node.child1());
+ speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, function.gpr(), JITCompiler::TrustedImmPtr(node.function())));
+ noResult(m_compileIndex);
+ break;
+ }
case CheckStructure: {
SpeculateCellOperand base(this, node.child1());
for (unsigned i = 0; i < m_codeBlock->numberOfCallLinkInfos(); ++i) {
CallLinkInfo& info = m_codeBlock->callLinkInfo(i);
info.isCall = m_callStructureStubCompilationInfo[i].isCall;
+ info.bytecodeIndex = m_callStructureStubCompilationInfo[i].bytecodeIndex;
info.callReturnLocation = CodeLocationLabel(patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].callReturnLocation));
info.hotPathBegin = patchBuffer.locationOf(m_callStructureStubCompilationInfo[i].hotPathBegin);
info.hotPathOther = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].hotPathOther);
MacroAssembler::Call hotPathOther;
MacroAssembler::Call callReturnLocation;
bool isCall;
+ unsigned bytecodeIndex;
};
struct MethodCallCompilationInfo {
m_callStructureStubCompilationInfo.append(StructureStubCompilationInfo());
m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
m_callStructureStubCompilationInfo[callLinkInfoIndex].isCall = opcodeID != op_construct;
+ m_callStructureStubCompilationInfo[callLinkInfoIndex].bytecodeIndex = m_bytecodeOffset;
// The following is the fast case, only used whan a callee can be linked.
m_callStructureStubCompilationInfo.append(StructureStubCompilationInfo());
m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
m_callStructureStubCompilationInfo[callLinkInfoIndex].isCall = opcodeID != op_construct;
+ m_callStructureStubCompilationInfo[callLinkInfoIndex].bytecodeIndex = m_bytecodeIndex;
addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));