Commit e79807b9 authored by oliver@apple.com's avatar oliver@apple.com

Bug 25559: Improve native function call performance

<https://bugs.webkit.org/show_bug.cgi?id=25559>

Reviewed by Gavin Barraclough

In order to cache calls to native functions we now make the standard
prototype functions use a small assembly thunk that converts the JS
calling convention into the native calling convention.  As this is
only beneficial in the JIT we use the NativeFunctionWrapper typedef
to alternate between PrototypeFunction and JSFunction to keep the
code sane.  This change from PrototypeFunction to NativeFunctionWrapper
is the bulk of this patch.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@43220 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent b0999f7d
2009-05-05 Oliver Hunt <oliver@apple.com>
Reviewed by Gavin Barraclough.
Bug 25559: Improve native function call performance
<https://bugs.webkit.org/show_bug.cgi?id=25559>
In order to cache calls to native functions we now make the standard
prototype functions use a small assembly thunk that converts the JS
calling convention into the native calling convention. As this is
only beneficial in the JIT we use the NativeFunctionWrapper typedef
to alternate between PrototypeFunction and JSFunction to keep the
code sane. This change from PrototypeFunction to NativeFunctionWrapper
is the bulk of this patch.
* JavaScriptCore.exp:
* JavaScriptCore.xcodeproj/project.pbxproj:
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::call):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::addPtr):
* assembler/X86Assembler.h:
(JSC::X86Assembler::leaq_mr):
(JSC::X86Assembler::call_m):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::execute):
(JSC::Interpreter::prepareForRepeatCall):
* jit/JIT.cpp:
(JSC::JIT::privateCompileCTIMachineTrampolines):
* jit/JIT.h:
(JSC::JIT::compileCTIMachineTrampolines):
* jit/JITCall.cpp:
(JSC::JIT::linkCall):
(JSC::JIT::compileOpCallInitializeCallFrame):
(JSC::JIT::compileOpCall):
* jit/JITCode.h:
(JSC::JITCode::operator bool):
* jit/JITInlineMethods.h:
(JSC::JIT::emitGetFromCallFrameHeader):
(JSC::JIT::emitGetFromCallFrameHeader32):
* jit/JITStubs.cpp:
(JSC::JITStubs::JITStubs):
(JSC::JITStubs::cti_op_call_JSFunction):
(JSC::JITStubs::cti_vm_dontLazyLinkCall):
(JSC::JITStubs::cti_vm_lazyLinkCall):
(JSC::JITStubs::cti_op_construct_JSConstruct):
* jit/JITStubs.h:
(JSC::JITStubs::ctiNativeCallThunk):
* jsc.cpp:
(GlobalObject::GlobalObject):
* parser/Nodes.cpp:
(JSC::FunctionBodyNode::FunctionBodyNode):
(JSC::FunctionBodyNode::createNativeThunk):
(JSC::FunctionBodyNode::generateJITCode):
* parser/Nodes.h:
(JSC::FunctionBodyNode::):
(JSC::FunctionBodyNode::generatedJITCode):
(JSC::FunctionBodyNode::jitCode):
* profiler/Profiler.cpp:
(JSC::Profiler::createCallIdentifier):
* runtime/ArgList.h:
* runtime/ArrayPrototype.cpp:
(JSC::isNumericCompareFunction):
* runtime/BooleanPrototype.cpp:
(JSC::BooleanPrototype::BooleanPrototype):
* runtime/DateConstructor.cpp:
(JSC::DateConstructor::DateConstructor):
* runtime/ErrorPrototype.cpp:
(JSC::ErrorPrototype::ErrorPrototype):
* runtime/FunctionPrototype.cpp:
(JSC::FunctionPrototype::addFunctionProperties):
(JSC::functionProtoFuncToString):
* runtime/FunctionPrototype.h:
* runtime/JSFunction.cpp:
(JSC::JSFunction::JSFunction):
(JSC::JSFunction::~JSFunction):
(JSC::JSFunction::mark):
(JSC::JSFunction::getCallData):
(JSC::JSFunction::call):
(JSC::JSFunction::argumentsGetter):
(JSC::JSFunction::callerGetter):
(JSC::JSFunction::lengthGetter):
(JSC::JSFunction::getOwnPropertySlot):
(JSC::JSFunction::put):
(JSC::JSFunction::deleteProperty):
(JSC::JSFunction::getConstructData):
(JSC::JSFunction::construct):
* runtime/JSFunction.h:
(JSC::JSFunction::JSFunction):
(JSC::JSFunction::setScope):
(JSC::JSFunction::scope):
(JSC::JSFunction::isHostFunction):
(JSC::JSFunction::scopeChain):
(JSC::JSFunction::clearScopeChain):
(JSC::JSFunction::setScopeChain):
(JSC::JSFunction::nativeFunction):
(JSC::JSFunction::setNativeFunction):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::~JSGlobalData):
(JSC::JSGlobalData::createNativeThunk):
* runtime/JSGlobalData.h:
(JSC::JSGlobalData::nativeFunctionThunk):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::reset):
* runtime/JSGlobalObject.h:
* runtime/Lookup.cpp:
(JSC::setUpStaticFunctionSlot):
* runtime/Lookup.h:
* runtime/NumberPrototype.cpp:
(JSC::NumberPrototype::NumberPrototype):
* runtime/ObjectPrototype.cpp:
(JSC::ObjectPrototype::ObjectPrototype):
* runtime/RegExpPrototype.cpp:
(JSC::RegExpPrototype::RegExpPrototype):
* runtime/StringConstructor.cpp:
(JSC::StringConstructor::StringConstructor):
2009-05-05 Gavin Barraclough <barraclough@apple.com>
Reviewed by Oliver Hunt.
......@@ -96,6 +96,7 @@ __ZN3JSC10Identifier24checkSameIdentifierTableEPNS_9ExecStateEPNS_7UString3RepE
__ZN3JSC10Identifier3addEPNS_9ExecStateEPKc
__ZN3JSC10Identifier5equalEPKNS_7UString3RepEPKc
__ZN3JSC10JSFunction4infoE
__ZN3JSC10JSFunctionC1EPNS_9ExecStateEN3WTF10PassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8JSObjectESA_RKNS_7ArgListEE
__ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeE
__ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeEPKc
__ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeERKNS_7UStringE
......
......@@ -124,7 +124,7 @@
86CC85A10EE79A4700288682 /* JITInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CC85A00EE79A4700288682 /* JITInlineMethods.h */; };
86CC85A30EE79B7400288682 /* JITCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CC85A20EE79B7400288682 /* JITCall.cpp */; };
86CC85C40EE7A89400288682 /* JITPropertyAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CC85C30EE7A89400288682 /* JITPropertyAccess.cpp */; };
86CCEFDE0F413F8900FD7F9E /* JITCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CCEFDD0F413F8900FD7F9E /* JITCode.h */; };
86CCEFDE0F413F8900FD7F9E /* JITCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CCEFDD0F413F8900FD7F9E /* JITCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
86DB64640F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86DB64630F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp */; };
86EAC4950F93E8D1008EC948 /* RegexCompiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86EAC48D0F93E8D1008EC948 /* RegexCompiler.cpp */; };
86EAC4960F93E8D1008EC948 /* RegexCompiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86EAC48E0F93E8D1008EC948 /* RegexCompiler.h */; };
......@@ -177,6 +177,7 @@
A72701B90DADE94900E548D7 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; };
A727FF6B0DA3092200E548D7 /* JSPropertyNameIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */; };
A766B44F0EE8DCD1009518CA /* ExecutableAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
A76EE6590FAE59D5003F069A /* NativeFunctionWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = A76EE6580FAE59D5003F069A /* NativeFunctionWrapper.h */; settings = {ATTRIBUTES = (Private, ); }; };
A782F1A50EEC9FA20036273F /* ExecutableAllocatorPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A782F1A40EEC9FA20036273F /* ExecutableAllocatorPosix.cpp */; };
A791EF280F11E07900AE1F68 /* JSByteArray.h in Headers */ = {isa = PBXBuildFile; fileRef = A791EF260F11E07900AE1F68 /* JSByteArray.h */; settings = {ATTRIBUTES = (Private, ); }; };
A791EF290F11E07900AE1F68 /* JSByteArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A791EF270F11E07900AE1F68 /* JSByteArray.cpp */; };
......@@ -693,6 +694,7 @@
A72701B30DADE94900E548D7 /* ExceptionHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionHelpers.h; sourceTree = "<group>"; };
A727FF650DA3053B00E548D7 /* JSPropertyNameIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPropertyNameIterator.h; sourceTree = "<group>"; };
A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPropertyNameIterator.cpp; sourceTree = "<group>"; };
A76EE6580FAE59D5003F069A /* NativeFunctionWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeFunctionWrapper.h; sourceTree = "<group>"; };
A782F1A40EEC9FA20036273F /* ExecutableAllocatorPosix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExecutableAllocatorPosix.cpp; sourceTree = "<group>"; };
A791EF260F11E07900AE1F68 /* JSByteArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSByteArray.h; sourceTree = "<group>"; };
A791EF270F11E07900AE1F68 /* JSByteArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSByteArray.cpp; sourceTree = "<group>"; };
......@@ -1419,6 +1421,7 @@
6507D2970E871E4A00D7D896 /* TypeInfo.h */,
F692A8850255597D01FF60F7 /* UString.cpp */,
F692A8860255597D01FF60F7 /* UString.h */,
A76EE6580FAE59D5003F069A /* NativeFunctionWrapper.h */,
);
path = runtime;
sourceTree = "<group>";
......@@ -1790,6 +1793,7 @@
86EAC49B0F93E8D1008EC948 /* RegexParser.h in Headers */,
86EAC49C0F93E8D1008EC948 /* RegexPattern.h in Headers */,
96DD73790F9DA3100027FBCC /* VMTags.h in Headers */,
A76EE6590FAE59D5003F069A /* NativeFunctionWrapper.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -553,6 +553,11 @@ public:
return Call(m_assembler.call(target), Call::None);
}
void call(Address address)
{
m_assembler.call_m(address.offset, address.base);
}
void ret()
{
m_assembler.ret();
......
......@@ -122,7 +122,7 @@ public:
void addPtr(Imm32 imm, RegisterID src, RegisterID dest)
{
m_assembler.leal_mr(imm.m_value, src, dest);
m_assembler.leaq_mr(imm.m_value, src, dest);
}
void andPtr(RegisterID src, RegisterID dest)
......
......@@ -1008,6 +1008,12 @@ public:
{
m_formatter.oneByteOp(OP_LEA, dst, base, offset);
}
#if PLATFORM(X86_64)
void leaq_mr(int offset, RegisterID base, RegisterID dst)
{
m_formatter.oneByteOp64(OP_LEA, dst, base, offset);
}
#endif
// Flow control:
......@@ -1022,6 +1028,11 @@ public:
m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_CALLN, dst);
return JmpSrc(m_formatter.size());
}
void call_m(int offset, RegisterID base)
{
m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_CALLN, base, offset);
}
JmpSrc jmp()
{
......
......@@ -690,9 +690,7 @@ JSValue Interpreter::execute(FunctionBodyNode* functionBodyNode, CallFrame* call
m_reentryDepth++;
#if ENABLE(JIT)
if (!codeBlock->jitCode())
JIT::compile(scopeChain->globalData, codeBlock);
result = codeBlock->jitCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
result = functionBodyNode->jitCode(scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
#else
result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
#endif
......@@ -740,8 +738,7 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionBodyNode* functionBod
// a 0 codeBlock indicates a built-in caller
newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
#if ENABLE(JIT)
if (!codeBlock->jitCode())
JIT::compile(scopeChain->globalData, codeBlock);
functionBodyNode->jitCode(scopeChain);
#endif
CallFrameClosure result = { callFrame, newCallFrame, function, codeBlock, scopeChain->globalData, oldEnd, scopeChain, codeBlock->m_numParameters, argc };
......@@ -761,6 +758,7 @@ JSValue Interpreter::execute(CallFrameClosure& closure, JSValue* exception)
m_reentryDepth++;
#if ENABLE(JIT)
ASSERT(closure.codeBlock->jitCode());
result = closure.codeBlock->jitCode().execute(&m_registerFile, closure.newCallFrame, closure.globalData, exception);
#else
result = privateExecute(Normal, &m_registerFile, closure.newCallFrame, exception);
......
This diff is collapsed.
......@@ -362,11 +362,11 @@ namespace JSC {
jit.privateCompilePutByIdTransition(stubInfo, oldStructure, newStructure, cachedOffset, chain, returnAddress);
}
static void compileCTIMachineTrampolines(JSGlobalData* globalData, RefPtr<ExecutablePool>* executablePool, void** ctiArrayLengthTrampoline, void** ctiStringLengthTrampoline, void** ctiVirtualCallPreLink, void** ctiVirtualCallLink, void** ctiVirtualCall)
static void compileCTIMachineTrampolines(JSGlobalData* globalData, RefPtr<ExecutablePool>* executablePool, void** ctiArrayLengthTrampoline, void** ctiStringLengthTrampoline, void** ctiVirtualCallPreLink, void** ctiVirtualCallLink, void** ctiVirtualCall, void** ctiNativeCallThunk)
{
JIT jit(globalData);
jit.privateCompileCTIMachineTrampolines(executablePool, ctiArrayLengthTrampoline, ctiStringLengthTrampoline, ctiVirtualCallPreLink, ctiVirtualCallLink, ctiVirtualCall);
jit.privateCompileCTIMachineTrampolines(executablePool, globalData, ctiArrayLengthTrampoline, ctiStringLengthTrampoline, ctiVirtualCallPreLink, ctiVirtualCallLink, ctiVirtualCall, ctiNativeCallThunk);
}
static void patchGetByIdSelf(StructureStubInfo*, Structure*, size_t cachedOffset, ProcessorReturnAddress returnAddress);
......@@ -399,7 +399,7 @@ namespace JSC {
void privateCompilePutByIdReplace(StructureStubInfo*, Structure*, size_t cachedOffset, ProcessorReturnAddress returnAddress);
void privateCompilePutByIdTransition(StructureStubInfo*, Structure*, Structure*, size_t cachedOffset, StructureChain*, ProcessorReturnAddress returnAddress);
void privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, void** ctiArrayLengthTrampoline, void** ctiStringLengthTrampoline, void** ctiVirtualCallPreLink, void** ctiVirtualCallLink, void** ctiVirtualCall);
void privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* data, void** ctiArrayLengthTrampoline, void** ctiStringLengthTrampoline, void** ctiVirtualCallPreLink, void** ctiVirtualCallLink, void** ctiVirtualCall, void** ctiNativeCallThunk);
void privateCompilePatchGetArrayLength(ProcessorReturnAddress returnAddress);
void addSlowCase(Jump);
......@@ -467,7 +467,8 @@ namespace JSC {
void emitPutToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry entry);
void emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry);
void emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, RegisterID to);
void emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, RegisterID to, RegisterID from = callFrameRegister);
void emitGetFromCallFrameHeader32(RegisterFile::CallFrameHeaderEntry entry, RegisterID to);
JSValue getConstantOperand(unsigned src);
int32_t getConstantOperandImmediateInt(unsigned src);
......
......@@ -56,10 +56,12 @@ void JIT::unlinkCall(CallLinkInfo* callLinkInfo)
void JIT::linkCall(JSFunction* callee, CodeBlock* calleeCodeBlock, JITCode ctiCode, CallLinkInfo* callLinkInfo, int callerArgCount)
{
// Currently we only link calls with the exact number of arguments.
if (callerArgCount == calleeCodeBlock->m_numParameters) {
// If this is a native call calleeCodeBlock is null so the number of parameters is unimportant
if (!calleeCodeBlock || callerArgCount == calleeCodeBlock->m_numParameters) {
ASSERT(!callLinkInfo->isLinked());
calleeCodeBlock->addCaller(callLinkInfo);
if (calleeCodeBlock)
calleeCodeBlock->addCaller(callLinkInfo);
callLinkInfo->hotPathBegin.repatch(callee);
callLinkInfo->hotPathOther.relink(ctiCode.addressForCall());
......@@ -73,7 +75,7 @@ void JIT::compileOpCallInitializeCallFrame()
{
store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
loadPtr(Address(regT2, FIELD_OFFSET(JSFunction, m_scopeChain) + FIELD_OFFSET(ScopeChain, m_node)), regT1); // newScopeChain
loadPtr(Address(regT2, FIELD_OFFSET(JSFunction, m_data) + FIELD_OFFSET(ScopeChain, m_node)), regT1); // newScopeChain
storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register))));
storePtr(regT2, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register))));
......@@ -242,7 +244,7 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca
// Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register))));
storePtr(regT2, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register))));
loadPtr(Address(regT2, FIELD_OFFSET(JSFunction, m_scopeChain) + FIELD_OFFSET(ScopeChain, m_node)), regT1); // newScopeChain
loadPtr(Address(regT2, FIELD_OFFSET(JSFunction, m_data) + FIELD_OFFSET(ScopeChain, m_node)), regT1); // newScopeChain
store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register))));
storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
......
......@@ -56,7 +56,7 @@ namespace JSC {
{
}
operator bool()
operator bool() const
{
return code != 0;
}
......
......@@ -168,9 +168,15 @@ ALWAYS_INLINE void JIT::emitPutImmediateToCallFrameHeader(void* value, RegisterF
storePtr(ImmPtr(value), Address(callFrameRegister, entry * sizeof(Register)));
}
ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, RegisterID to)
ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, RegisterID to, RegisterID from)
{
loadPtr(Address(callFrameRegister, entry * sizeof(Register)), to);
loadPtr(Address(from, entry * sizeof(Register)), to);
killLastResultRegister();
}
ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader32(RegisterFile::CallFrameHeaderEntry entry, RegisterID to)
{
load32(Address(callFrameRegister, entry * sizeof(Register)), to);
killLastResultRegister();
}
......
......@@ -74,8 +74,9 @@ JITStubs::JITStubs(JSGlobalData* globalData)
, m_ctiVirtualCallPreLink(0)
, m_ctiVirtualCallLink(0)
, m_ctiVirtualCall(0)
, m_ctiNativeCallThunk(0)
{
JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_ctiArrayLengthTrampoline, &m_ctiStringLengthTrampoline, &m_ctiVirtualCallPreLink, &m_ctiVirtualCallLink, &m_ctiVirtualCall);
JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_ctiArrayLengthTrampoline, &m_ctiStringLengthTrampoline, &m_ctiVirtualCallPreLink, &m_ctiVirtualCallLink, &m_ctiVirtualCall, &m_ctiNativeCallThunk);
}
#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
......@@ -819,13 +820,12 @@ void* JITStubs::cti_op_call_JSFunction(STUB_ARGS)
ASSERT(ARG_src1.getCallData(callData) == CallTypeJS);
#endif
ScopeChainNode* callDataScopeChain = asFunction(ARG_src1)->scope().node();
CodeBlock* newCodeBlock = &asFunction(ARG_src1)->body()->bytecode(callDataScopeChain);
JSFunction* function = asFunction(ARG_src1);
FunctionBodyNode* body = function->body();
ScopeChainNode* callDataScopeChain = function->scope().node();
body->jitCode(callDataScopeChain);
if (!newCodeBlock->jitCode())
JIT::compile(ARG_globalData, newCodeBlock);
return newCodeBlock;
return &(body->generatedBytecode());
}
VoidPtrPair JITStubs::cti_op_call_arityCheck(STUB_ARGS)
......@@ -879,13 +879,12 @@ void* JITStubs::cti_vm_dontLazyLinkCall(STUB_ARGS)
JSGlobalData* globalData = ARG_globalData;
JSFunction* callee = asFunction(ARG_src1);
CodeBlock* codeBlock = &callee->body()->bytecode(callee->scope().node());
if (!codeBlock->jitCode())
JIT::compile(globalData, codeBlock);
JITCode jitCode = callee->body()->generatedJITCode();
ASSERT(jitCode);
ctiPatchNearCallByReturnAddress(ARG_returnAddress2, globalData->jitStubs.ctiVirtualCallLink());
return codeBlock->jitCode().addressForCall();
return jitCode.addressForCall();
}
void* JITStubs::cti_vm_lazyLinkCall(STUB_ARGS)
......@@ -893,14 +892,17 @@ void* JITStubs::cti_vm_lazyLinkCall(STUB_ARGS)
BEGIN_STUB_FUNCTION();
JSFunction* callee = asFunction(ARG_src1);
CodeBlock* codeBlock = &callee->body()->bytecode(callee->scope().node());
if (!codeBlock->jitCode())
JIT::compile(ARG_globalData, codeBlock);
JITCode jitCode = callee->body()->generatedJITCode();
ASSERT(jitCode);
CodeBlock* codeBlock = 0;
if (!callee->isHostFunction())
codeBlock = &callee->body()->bytecode(callee->scope().node());
CallLinkInfo* callLinkInfo = &ARG_callFrame->callerFrame()->codeBlock()->getCallLinkInfo(ARG_returnAddress2);
JIT::linkCall(callee, codeBlock, codeBlock->jitCode(), callLinkInfo, ARG_int3);
JIT::linkCall(callee, codeBlock, jitCode, callLinkInfo, ARG_int3);
return codeBlock->jitCode().addressForCall();
return jitCode.addressForCall();
}
JSObject* JITStubs::cti_op_push_activation(STUB_ARGS)
......@@ -1059,16 +1061,25 @@ JSObject* JITStubs::cti_op_construct_JSConstruct(STUB_ARGS)
{
BEGIN_STUB_FUNCTION();
JSFunction* constructor = asFunction(ARG_src1);
if (constructor->isHostFunction()) {
CallFrame* callFrame = ARG_callFrame;
CodeBlock* codeBlock = callFrame->codeBlock();
unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
ARG_globalData->exception = createNotAConstructorError(callFrame, constructor, vPCIndex, codeBlock);
VM_THROW_EXCEPTION();
}
#ifndef NDEBUG
ConstructData constructData;
ASSERT(asFunction(ARG_src1)->getConstructData(constructData) == ConstructTypeJS);
ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
#endif
Structure* structure;
if (ARG_src4.isObject())
structure = asObject(ARG_src4)->inheritorID();
else
structure = asFunction(ARG_src1)->scope().node()->globalObject()->emptyObjectStructure();
structure = constructor->scope().node()->globalObject()->emptyObjectStructure();
return new (ARG_globalData) JSObject(structure);
}
......
......@@ -210,6 +210,7 @@ namespace JSC {
void* ctiVirtualCallPreLink() { return m_ctiVirtualCallPreLink; }
void* ctiVirtualCallLink() { return m_ctiVirtualCallLink; }
void* ctiVirtualCall() { return m_ctiVirtualCall; }
void* ctiNativeCallThunk() { return m_ctiNativeCallThunk; }
private:
RefPtr<ExecutablePool> m_executablePool;
......@@ -219,6 +220,7 @@ namespace JSC {
void* m_ctiVirtualCallPreLink;
void* m_ctiVirtualCallLink;
void* m_ctiVirtualCall;
void* m_ctiNativeCallThunk;
};
} // namespace JSC
......
......@@ -26,6 +26,7 @@
#include "Completion.h"
#include "InitializeThreading.h"
#include "JSArray.h"
#include "JSFunction.h"
#include "JSLock.h"
#include "PrototypeFunction.h"
#include "SamplingTool.h"
......@@ -176,18 +177,18 @@ ASSERT_CLASS_FITS_IN_CELL(GlobalObject);
GlobalObject::GlobalObject(const Vector<UString>& arguments)
: JSGlobalObject()
{
putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "debug"), functionDebug));
putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "print"), functionPrint));
putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "quit"), functionQuit));
putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "gc"), functionGC));
putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "version"), functionVersion));
putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "run"), functionRun));
putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "load"), functionLoad));
putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "readline"), functionReadline));
putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "debug"), functionDebug));
putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "print"), functionPrint));
putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "quit"), functionQuit));
putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "gc"), functionGC));
putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "version"), functionVersion));
putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "run"), functionRun));
putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "load"), functionLoad));
putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "readline"), functionReadline));
#if ENABLE(SAMPLING_FLAGS)
putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "setSamplingFlags"), functionSetSamplingFlags));
putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "clearSamplingFlags"), functionClearSamplingFlags));
putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "setSamplingFlags"), functionSetSamplingFlags));
putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "clearSamplingFlags"), functionClearSamplingFlags));
#endif
JSObject* array = constructEmptyArray(globalExec());
......
......@@ -2685,6 +2685,9 @@ void EvalNode::mark()
FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData)
: ScopeNode(globalData)
#if ENABLE(JIT)
, m_jitCode(0)
#endif
, m_parameters(0)
, m_parameterCount(0)
, m_refCount(0)
......@@ -2693,6 +2696,9 @@ FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData)
FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
: ScopeNode(globalData, sourceCode, children, varStack, funcStack, features, numConstants)
#if ENABLE(JIT)
, m_jitCode(0)
#endif
, m_parameters(0)
, m_parameterCount(0)
, m_refCount(0)
......@@ -2731,6 +2737,15 @@ void FunctionBodyNode::mark()
m_code->mark();
}
#if ENABLE(JIT)
PassRefPtr<FunctionBodyNode> FunctionBodyNode::createNativeThunk(JSGlobalData* globalData)
{
PassRefPtr<FunctionBodyNode> body = new FunctionBodyNode(globalData);
body->m_jitCode = globalData->jitStubs.ctiNativeCallThunk();
return body;
}
#endif
FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData)
{
return new FunctionBodyNode(globalData);
......@@ -2760,6 +2775,18 @@ void FunctionBodyNode::generateBytecode(ScopeChainNode* scopeChainNode)
destroyData();
}
#if ENABLE(JIT)
void FunctionBodyNode::generateJITCode(ScopeChainNode* scopeChainNode)
{
bytecode(scopeChainNode);
ASSERT(m_code);
ASSERT(!m_code->jitCode());
JIT::compile(scopeChainNode->globalData, m_code.get());
ASSERT(m_code->jitCode());
m_jitCode = m_code->jitCode();
}
#endif
CodeBlock& FunctionBodyNode::bytecodeForExceptionInfoReparse(ScopeChainNode* scopeChainNode, CodeBlock* codeBlockBeingRegeneratedFrom)
{
ASSERT(!m_code);
......
......@@ -27,6 +27,7 @@
#define NODES_H_
#include "Error.h"
#include "JITCode.h"
#include "Opcode.h"
#include "ResultType.h"
#include "SourceCode.h"
......@@ -2189,6 +2190,9 @@ namespace JSC {
class FunctionBodyNode : public ScopeNode {
friend class JIT;
public:
#if ENABLE(JIT)
static PassRefPtr<FunctionBodyNode> createNativeThunk(JSGlobalData*) JSC_FAST_CALL;
#endif
static FunctionBodyNode* create(JSGlobalData*) JSC_FAST_CALL;
static FunctionBodyNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL;
virtual ~FunctionBodyNode();
......@@ -2199,25 +2203,23 @@ namespace JSC {
Identifier* copyParameters();
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
CodeBlock& bytecode(ScopeChainNode* scopeChain) JSC_FAST_CALL
bool isGenerated() JSC_FAST_CALL
{
ASSERT(scopeChain);
if (!m_code)
generateBytecode(scopeChain);
return *m_code;
return m_code;
}
CodeBlock& generatedBytecode() JSC_FAST_CALL
#if ENABLE(JIT)
bool isHostFunction() const JSC_FAST_CALL
{
ASSERT(m_code);
return *m_code;
return m_jitCode && !m_code;
}
bool isGenerated() JSC_FAST_CALL
#else
bool isHostFunction() const JSC_FAST_CALL
{
return m_code;
return true;
}
#endif
virtual void mark();
......@@ -2241,13 +2243,44 @@ namespace JSC {
}
CodeBlock& bytecodeForExceptionInfoReparse(ScopeChainNode*, CodeBlock*) JSC_FAST_CALL;
#if ENABLE(JIT)
JITCode generatedJITCode()
{
ASSERT(m_jitCode);
return m_jitCode;
}
JITCode jitCode(ScopeChainNode* scopeChain)
{
if (!m_jitCode)
generateJITCode(scopeChain);
return m_jitCode;
}
#endif
CodeBlock& bytecode(ScopeChainNode* scopeChain) JSC_FAST_CALL
{
ASSERT(scopeChain);
if (!m_code)
generateBytecode(scopeChain);
return *m_code;
}
CodeBlock& generatedBytecode() JSC_FAST_CALL
{
ASSERT(m_code);
return *m_code;
}
private:
FunctionBodyNode(JSGlobalData*) JSC_FAST_CALL;
FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL;
void generateBytecode(ScopeChainNode*) JSC_FAST_CALL;
#if ENABLE(JIT)
void generateJITCode(ScopeChainNode*) JSC_FAST_CALL;