2008-10-17 Gavin Barraclough <barraclough@apple.com>
Optimize op_call by allowing call sites to be directly linked to callees.
For the hot path of op_call, CTI now generates a check (initially for an impossible
value), and the first time the call is executed we attempt to link the call directly
to the callee. WWe can currently only do so if the arity of the caller and callee
match. The (optimized) setup for the call on the hot path is linked directly to
the ctiCode for the callee, without indirection.
Two forms of the slow case of the call are generated, the first will be executed the
first time the call is reached. As well as this path attempting to link the call to
a callee, it also relinks the slow case to a second slow case, which will not continue
to attempt relinking the call. (This policy could be changed in future, but for not
this is intended to prevent thrashing).
If a callee that the caller has been linked to is garbage collected, then the link
in the caller's JIt code will be reset back to a value that cannot match - to prevent
any false positive matches.
~20% progression on deltablue & richards, >12% overall reduction in v8-tests
runtime, one or two percent progression on sunspider.
Reviewed by Oliver Hunt.
* VM/CTI.cpp:
(JSC::):
(JSC::CTI::emitNakedCall):
(JSC::unreachable):
(JSC::CTI::compileOpCallInitializeCallFrame):
(JSC::CTI::compileOpCallSetupArgs):
(JSC::CTI::compileOpCall):
(JSC::CTI::privateCompileMainPass):
(JSC::CTI::privateCompileSlowCases):
(JSC::CTI::privateCompile):
(JSC::CTI::unlinkCall):
(JSC::CTI::linkCall):
* VM/CTI.h:
* VM/CodeBlock.cpp:
(JSC::CodeBlock::~CodeBlock):
(JSC::CodeBlock::unlinkCallers):
(JSC::CodeBlock::derefStructureIDs):
* VM/CodeBlock.h:
(JSC::StructureStubInfo::StructureStubInfo):
(JSC::CallLinkInfo::CallLinkInfo):
(JSC::CodeBlock::addCaller):
(JSC::CodeBlock::removeCaller):
(JSC::CodeBlock::getStubInfo):
* VM/CodeGenerator.cpp:
(JSC::CodeGenerator::emitCall):
(JSC::CodeGenerator::emitConstruct):
* VM/Machine.cpp:
(JSC::Machine::cti_op_call_profiler):
(JSC::Machine::cti_op_call_JSFunction):
(JSC::Machine::cti_vm_lazyLinkCall):
(JSC::Machine::cti_op_construct_JSConstructFast):
(JSC::Machine::cti_op_construct_JSConstruct):
(JSC::Machine::cti_op_construct_NotJSConstruct):
* VM/Machine.h:
* kjs/JSFunction.cpp:
(JSC::JSFunction::~JSFunction):
* kjs/JSFunction.h:
* kjs/nodes.h:
(JSC::FunctionBodyNode::):
* masm/X86Assembler.h:
(JSC::X86Assembler::getDifferenceBetweenLabels):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@37670 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JavaScriptCore/VM/CTI.h b/JavaScriptCore/VM/CTI.h
index 26338dc..0efd9de 100644
--- a/JavaScriptCore/VM/CTI.h
+++ b/JavaScriptCore/VM/CTI.h
@@ -66,6 +66,7 @@
#define ARG_int3 ((int)((ARGS)[3]))
#define ARG_int4 ((int)((ARGS)[4]))
#define ARG_int5 ((int)((ARGS)[5]))
+#define ARG_int6 ((int)((ARGS)[6]))
#define ARG_func1 ((FuncDeclNode*)((ARGS)[1]))
#define ARG_funcexp1 ((FuncExprNode*)((ARGS)[1]))
#define ARG_registers1 ((Register*)((ARGS)[1]))
@@ -94,6 +95,7 @@
class StructureIDChain;
struct Instruction;
struct OperandTypes;
+ struct StructureStubInfo;
typedef JSValue* (SFX_CALL *CTIHelper_j)(CTI_ARGS);
typedef JSPropertyNameIterator* (SFX_CALL *CTIHelper_p)(CTI_ARGS);
@@ -222,6 +224,8 @@
struct StructureStubCompilationInfo {
X86Assembler::JmpSrc callReturnLocation;
X86Assembler::JmpDst hotPathBegin;
+ X86Assembler::JmpSrc hotPathOther;
+ X86Assembler::JmpDst coldPathOther;
};
extern "C" {
@@ -257,6 +261,7 @@
#else
static const int repatchOffsetGetByIdSlowCaseCall = 17 + 4 + ctiArgumentInitSize;
#endif
+ static const int repatchOffsetOpCallCall = 6;
public:
static void compile(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock)
@@ -320,6 +325,9 @@
return cti.privateCompilePatchGetArrayLength(returnAddress);
}
+ static void linkCall(CodeBlock* callerCodeBlock, JSFunction* callee, CodeBlock* calleeCodeBlock, void* ctiCode, void* returnAddress, int callerArgCount);
+ static void unlinkCall(StructureStubInfo*);
+
inline static JSValue* execute(void* code, RegisterFile* registerFile, CallFrame* callFrame, JSGlobalData* globalData, JSValue** exception)
{
return ctiTrampoline(code, registerFile, callFrame, exception, Profiler::enabledProfilerReference(), globalData);
@@ -346,8 +354,9 @@
void privateCompilePatchGetArrayLength(void* returnAddress);
enum CompileOpCallType { OpCallNormal, OpCallEval, OpConstruct };
- void compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType type = OpCallNormal);
+ void compileOpCall(Instruction* instruction, unsigned i, unsigned structureIDInstructionIndex, CompileOpCallType type = OpCallNormal);
void compileOpCallInitializeCallFrame(unsigned callee, unsigned argCount);
+ void compileOpCallSetupArgs(Instruction* instruction, bool isConstruct, bool isEval);
enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq };
void compileOpStrictEq(Instruction* instruction, unsigned i, CompileOpStrictEqType type);
void putDoubleResultToJSNumberCellOrJSImmediate(X86::XMMRegisterID xmmSource, X86::RegisterID jsNumberCell, unsigned dst, X86Assembler::JmpSrc* wroteJSNumberCell, X86::XMMRegisterID tempXmm, X86::RegisterID tempReg1, X86::RegisterID tempReg2);
@@ -388,7 +397,8 @@
void emitTagAsBoolImmediate(X86Assembler::RegisterID reg);
- X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, X86::RegisterID);
+ X86Assembler::JmpSrc emitNakedCall(unsigned opcodeIndex, X86::RegisterID);
+ X86Assembler::JmpSrc emitNakedCall(unsigned opcodeIndex, void(*function)());
X86Assembler::JmpSrc emitCTICall(unsigned opcodeIndex, CTIHelper_j);
X86Assembler::JmpSrc emitCTICall(unsigned opcodeIndex, CTIHelper_p);
X86Assembler::JmpSrc emitCTICall(unsigned opcodeIndex, CTIHelper_v);