Commit 6f0b31aa authored by msaboff@apple.com's avatar msaboff@apple.com

Move the setting up of callee's callFrame from pushFrame to callToJavaScript thunk

https://bugs.webkit.org/show_bug.cgi?id=123999

Reviewed by Filip Pizlo.

Changed LLInt and/or JIT enabled ports to allocate the stack frame in the
callToJavaScript stub.  Added an additional stub, callToNativeFunction that
allocates a stack frame in a similar way for calling native entry points
that take a single ExecState* argument.  These stubs are implemented
using common macros in LowLevelInterpreter{32_64,64}.asm.  There are also
Windows X86 and X86-64 versions in the corresponding JitStubsXX.h.
The stubs allocate and create a sentinel frame, then create the callee's
frame, populating  the header and arguments from the passed in ProtoCallFrame*.
It is assumed that the caller of either stub does a check for enough stack space
via JSStack::entryCheck().

For ports using the C-Loop interpreter, the prior method for allocating stack
frame and invoking functions is used, namely with JSStack::pushFrame() and
::popFrame().

Made spelling changes "sentinal" -> "sentinel".

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* interpreter/CachedCall.h:
(JSC::CachedCall::CachedCall):
(JSC::CachedCall::setThis):
(JSC::CachedCall::setArgument):
* interpreter/CallFrameClosure.h:
(JSC::CallFrameClosure::resetCallFrame):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::prepareForRepeatCall):
* interpreter/Interpreter.h:
* interpreter/JSStack.h:
* interpreter/JSStackInlines.h:
(JSC::JSStack::entryCheck):
(JSC::JSStack::pushFrame):
(JSC::JSStack::popFrame):
* interpreter/ProtoCallFrame.cpp: Added.
(JSC::ProtoCallFrame::init):
* interpreter/ProtoCallFrame.h: Added.
(JSC::ProtoCallFrame::codeBlock):
(JSC::ProtoCallFrame::setCodeBlock):
(JSC::ProtoCallFrame::setScope):
(JSC::ProtoCallFrame::setCallee):
(JSC::ProtoCallFrame::argumentCountIncludingThis):
(JSC::ProtoCallFrame::argumentCount):
(JSC::ProtoCallFrame::setArgumentCountIncludingThis):
(JSC::ProtoCallFrame::setPaddedArgsCount):
(JSC::ProtoCallFrame::clearCurrentVPC):
(JSC::ProtoCallFrame::setThisValue):
(JSC::ProtoCallFrame::setArgument):
* jit/JITCode.cpp:
(JSC::JITCode::execute):
* jit/JITCode.h:
* jit/JITOperations.cpp:
* jit/JITStubs.h:
* jit/JITStubsMSVC64.asm:
* jit/JITStubsX86.h:
* llint/LLIntOffsetsExtractor.cpp:
* llint/LLIntThunks.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/ArgList.h:
(JSC::ArgList::data):
* runtime/JSArray.cpp:
(JSC::AVLTreeAbstractorForArrayCompare::compare_key_key):
* runtime/StringPrototype.cpp:
(JSC::replaceUsingRegExpSearch):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@160094 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 3edd28b6
......@@ -217,6 +217,7 @@ set(JavaScriptCore_SOURCES
interpreter/CallFrame.cpp
interpreter/Interpreter.cpp
interpreter/JSStack.cpp
interpreter/ProtoCallFrame.cpp
interpreter/StackVisitor.cpp
interpreter/VMInspector.cpp
......
2013-12-04 Michael Saboff <msaboff@apple.com>
Move the setting up of callee's callFrame from pushFrame to callToJavaScript thunk
https://bugs.webkit.org/show_bug.cgi?id=123999
Reviewed by Filip Pizlo.
Changed LLInt and/or JIT enabled ports to allocate the stack frame in the
callToJavaScript stub. Added an additional stub, callToNativeFunction that
allocates a stack frame in a similar way for calling native entry points
that take a single ExecState* argument. These stubs are implemented
using common macros in LowLevelInterpreter{32_64,64}.asm. There are also
Windows X86 and X86-64 versions in the corresponding JitStubsXX.h.
The stubs allocate and create a sentinel frame, then create the callee's
frame, populating the header and arguments from the passed in ProtoCallFrame*.
It is assumed that the caller of either stub does a check for enough stack space
via JSStack::entryCheck().
For ports using the C-Loop interpreter, the prior method for allocating stack
frame and invoking functions is used, namely with JSStack::pushFrame() and
::popFrame().
Made spelling changes "sentinal" -> "sentinel".
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* interpreter/CachedCall.h:
(JSC::CachedCall::CachedCall):
(JSC::CachedCall::setThis):
(JSC::CachedCall::setArgument):
* interpreter/CallFrameClosure.h:
(JSC::CallFrameClosure::resetCallFrame):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::prepareForRepeatCall):
* interpreter/Interpreter.h:
* interpreter/JSStack.h:
* interpreter/JSStackInlines.h:
(JSC::JSStack::entryCheck):
(JSC::JSStack::pushFrame):
(JSC::JSStack::popFrame):
* interpreter/ProtoCallFrame.cpp: Added.
(JSC::ProtoCallFrame::init):
* interpreter/ProtoCallFrame.h: Added.
(JSC::ProtoCallFrame::codeBlock):
(JSC::ProtoCallFrame::setCodeBlock):
(JSC::ProtoCallFrame::setScope):
(JSC::ProtoCallFrame::setCallee):
(JSC::ProtoCallFrame::argumentCountIncludingThis):
(JSC::ProtoCallFrame::argumentCount):
(JSC::ProtoCallFrame::setArgumentCountIncludingThis):
(JSC::ProtoCallFrame::setPaddedArgsCount):
(JSC::ProtoCallFrame::clearCurrentVPC):
(JSC::ProtoCallFrame::setThisValue):
(JSC::ProtoCallFrame::setArgument):
* jit/JITCode.cpp:
(JSC::JITCode::execute):
* jit/JITCode.h:
* jit/JITOperations.cpp:
* jit/JITStubs.h:
* jit/JITStubsMSVC64.asm:
* jit/JITStubsX86.h:
* llint/LLIntOffsetsExtractor.cpp:
* llint/LLIntThunks.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/ArgList.h:
(JSC::ArgList::data):
* runtime/JSArray.cpp:
(JSC::AVLTreeAbstractorForArrayCompare::compare_key_key):
* runtime/StringPrototype.cpp:
(JSC::replaceUsingRegExpSearch):
2013-12-04 László Langó <lango@inf.u-szeged.hu>
Remove stdio.h from JSC files.
......
......@@ -622,6 +622,8 @@ javascriptcore_sources += \
Source/JavaScriptCore/interpreter/JSStack.cpp \
Source/JavaScriptCore/interpreter/JSStack.h \
Source/JavaScriptCore/interpreter/JSStackInlines.h \
Source/JavaScriptCore/interpreter/ProtoCallFrame.cpp \
Source/JavaScriptCore/interpreter/ProtoCallFrame.h \
Source/JavaScriptCore/interpreter/Register.h \
Source/JavaScriptCore/interpreter/StackVisitor.cpp \
Source/JavaScriptCore/interpreter/StackVisitor.h \
......
......@@ -459,6 +459,7 @@
<ClCompile Include="..\interpreter\CallFrame.cpp" />
<ClCompile Include="..\interpreter\Interpreter.cpp" />
<ClCompile Include="..\interpreter\JSStack.cpp" />
<ClCompile Include="..\interpreter\ProtoCallFrame.cpp" />
<ClCompile Include="..\interpreter\StackVisitor.cpp" />
<ClCompile Include="..\interpreter\VMInspector.cpp" />
<ClCompile Include="..\jit\AssemblyHelpers.cpp" />
......@@ -1003,6 +1004,7 @@
<ClInclude Include="..\interpreter\Interpreter.h" />
<ClInclude Include="..\interpreter\JSStack.h" />
<ClInclude Include="..\interpreter\JSStackInlines.h" />
<ClInclude Include="..\interpreter\ProtoCallFrame.h" />
<ClInclude Include="..\interpreter\Register.h" />
<ClInclude Include="..\interpreter\StackVisitor.h" />
<ClInclude Include="..\interpreter\VMInspector.h" />
......
......@@ -288,6 +288,9 @@
<ClCompile Include="..\interpreter\JSStack.cpp">
<Filter>interpreter</Filter>
</ClCompile>
<ClCompile Include="..\interpreter\ProtoCallFrame.cpp">
<Filter>interpreter</Filter>
</ClCompile>
<ClCompile Include="..\interpreter\StackVisitor.cpp">
<Filter>interpreter</Filter>
</ClCompile>
......@@ -1727,6 +1730,9 @@
<ClInclude Include="..\interpreter\JSStackInlines.h">
<Filter>interpreter</Filter>
</ClInclude>
<ClInclude Include="..\interpreter\ProtoCallFrame.h">
<Filter>interpreter</Filter>
</ClInclude>
<ClInclude Include="..\interpreter\Register.h">
<Filter>interpreter</Filter>
</ClInclude>
......
......@@ -735,6 +735,7 @@
65C02850171795E200351E35 /* ARMv7Disassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65C0284F171795E200351E35 /* ARMv7Disassembler.cpp */; };
65C0285C1717966800351E35 /* ARMv7DOpcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65C0285A1717966800351E35 /* ARMv7DOpcode.cpp */; };
65C0285D1717966800351E35 /* ARMv7DOpcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 65C0285B1717966800351E35 /* ARMv7DOpcode.h */; };
65FB5117184EEE7000C12B70 /* ProtoCallFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65FB5116184EE9BC00C12B70 /* ProtoCallFrame.cpp */; };
7C15F65D17C199CE00794D40 /* JSPromiseCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C15F65B17C199CE00794D40 /* JSPromiseCallback.cpp */; };
7C15F65E17C199CE00794D40 /* JSPromiseCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C15F65C17C199CE00794D40 /* JSPromiseCallback.h */; };
7C184E1A17BEDBD3007CB63A /* JSPromise.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C184E1817BEDBD3007CB63A /* JSPromise.cpp */; };
......@@ -2015,6 +2016,8 @@
65EA4C9A092AF9E20093D800 /* JSLock.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = JSLock.h; sourceTree = "<group>"; tabWidth = 8; };
65EA73620BAE35D1001BB560 /* CommonIdentifiers.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CommonIdentifiers.cpp; sourceTree = "<group>"; };
65EA73630BAE35D1001BB560 /* CommonIdentifiers.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CommonIdentifiers.h; sourceTree = "<group>"; };
65FB5115184EE8F800C12B70 /* ProtoCallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProtoCallFrame.h; sourceTree = "<group>"; };
65FB5116184EE9BC00C12B70 /* ProtoCallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProtoCallFrame.cpp; sourceTree = "<group>"; };
704FD35305697E6D003DBED9 /* BooleanObject.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = BooleanObject.h; sourceTree = "<group>"; tabWidth = 8; };
7C15F65B17C199CE00794D40 /* JSPromiseCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPromiseCallback.cpp; sourceTree = "<group>"; };
7C15F65C17C199CE00794D40 /* JSPromiseCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPromiseCallback.h; sourceTree = "<group>"; };
......@@ -2918,6 +2921,8 @@
1429D77A0ED20D7300B89619 /* interpreter */ = {
isa = PBXGroup;
children = (
65FB5116184EE9BC00C12B70 /* ProtoCallFrame.cpp */,
65FB5115184EE8F800C12B70 /* ProtoCallFrame.h */,
0F55F0F114D1063600AC7649 /* AbstractPC.cpp */,
0F55F0F214D1063600AC7649 /* AbstractPC.h */,
A7F8690E0F9584A100558697 /* CachedCall.h */,
......@@ -5277,6 +5282,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
65FB5117184EEE7000C12B70 /* ProtoCallFrame.cpp in Sources */,
0FFA549716B8835000B3A982 /* A64DOpcode.cpp in Sources */,
0F55F0F414D1063900AC7649 /* AbstractPC.cpp in Sources */,
147F39BD107EC37600427A48 /* ArgList.cpp in Sources */,
......
......@@ -31,6 +31,7 @@
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "Interpreter.h"
#include "ProtoCallFrame.h"
#include "VMEntryScope.h"
namespace JSC {
......@@ -43,9 +44,14 @@ namespace JSC {
, m_entryScope(callFrame->vm(), function->scope()->globalObject())
{
ASSERT(!function->isHostFunction());
if (callFrame->vm().isSafeToRecurse())
if (callFrame->vm().isSafeToRecurse()) {
#if !ENABLE(LLINT_C_LOOP)
m_arguments.resize(argumentCount);
m_closure = m_interpreter->prepareForRepeatCall(function->jsExecutable(), callFrame, &m_protoCallFrame, function, argumentCount + 1, function->scope(), m_arguments.data());
#else
m_closure = m_interpreter->prepareForRepeatCall(function->jsExecutable(), callFrame, function, argumentCount + 1, function->scope());
else
#endif
} else
throwStackOverflowError(callFrame);
m_valid = !callFrame->hadException();
}
......@@ -55,6 +61,10 @@ namespace JSC {
ASSERT(m_valid);
return m_interpreter->execute(m_closure);
}
#if !ENABLE(LLINT_C_LOOP)
void setThis(JSValue v) { m_protoCallFrame.setThisValue(v); }
void setArgument(int n, JSValue v) { m_protoCallFrame.setArgument(n, v); }
#else
void setThis(JSValue v) { m_closure.setThis(v); }
void setArgument(int n, JSValue v) { m_closure.setArgument(n, v); }
......@@ -70,11 +80,16 @@ namespace JSC {
if (m_valid)
m_interpreter->endRepeatCall(m_closure);
}
#endif
private:
bool m_valid;
Interpreter* m_interpreter;
VMEntryScope m_entryScope;
#if !ENABLE(LLINT_C_LOOP)
ProtoCallFrame m_protoCallFrame;
Vector<JSValue> m_arguments;
#endif
CallFrameClosure m_closure;
};
}
......
......@@ -26,11 +26,17 @@
#ifndef CallFrameClosure_h
#define CallFrameClosure_h
#include "ProtoCallFrame.h"
namespace JSC {
struct CallFrameClosure {
CallFrame* oldCallFrame;
#if ENABLE(LLINT_C_LOOP)
CallFrame* newCallFrame;
#else
ProtoCallFrame* newCallFrame;
#endif
JSFunction* function;
FunctionExecutable* functionExecutable;
VM* vm;
......@@ -51,12 +57,14 @@ struct CallFrameClosure {
void resetCallFrame()
{
newCallFrame->setScope(scope);
#if ENABLE(LLINT_C_LOOP)
// setArgument() takes an arg index that starts from 0 for the first
// argument after the 'this' value. Since both argumentCountIncludingThis
// and parameterCountIncludingThis includes the 'this' value, we need to
// subtract 1 from them to make i a valid argument index for setArgument().
// subtract 1 from them to make it a valid argument index for setArgument().
for (int i = argumentCountIncludingThis-1; i < parameterCountIncludingThis-1; ++i)
newCallFrame->setArgument(i, jsUndefined());
#endif
}
};
......
......@@ -53,12 +53,14 @@
#include "JSString.h"
#include "JSWithScope.h"
#include "LLIntCLoop.h"
#include "LLIntThunks.h"
#include "LegacyProfiler.h"
#include "LiteralParser.h"
#include "NameInstance.h"
#include "ObjectPrototype.h"
#include "Operations.h"
#include "Parser.h"
#include "ProtoCallFrame.h"
#include "RegExpObject.h"
#include "RegExpPrototype.h"
#include "Register.h"
......@@ -860,12 +862,20 @@ failedJSONP:
// Push the call frame for this invocation:
ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
#if ENABLE(LLINT_C_LOOP)
CallFrame* newCallFrame = m_stack.pushFrame(callFrame, codeBlock, scope, 1, 0);
if (UNLIKELY(!newCallFrame))
return checkedReturn(throwStackOverflowError(callFrame));
// Set the arguments for the callee:
newCallFrame->setThisValue(thisObj);
#else
if (UNLIKELY(!m_stack.entryCheck(codeBlock, 1)))
return checkedReturn(throwStackOverflowError(callFrame));
ProtoCallFrame protoCallFrame;
protoCallFrame.init(codeBlock, scope, 0, thisObj, 1);
#endif
if (LegacyProfiler* profiler = vm.enabledProfiler())
profiler->willExecute(callFrame, program->sourceURL(), program->lineNo());
......@@ -879,14 +889,16 @@ failedJSONP:
#if ENABLE(LLINT_C_LOOP)
result = LLInt::CLoop::execute(newCallFrame, llint_program_prologue);
#elif ENABLE(JIT)
result = program->generatedJITCode()->execute(&m_stack, newCallFrame, &vm);
result = program->generatedJITCode()->execute(&vm, &protoCallFrame, m_stack.getTopOfStack());
#endif // ENABLE(JIT)
}
if (LegacyProfiler* profiler = vm.enabledProfiler())
profiler->didExecute(callFrame, program->sourceURL(), program->lineNo());
#if ENABLE(LLINT_C_LOOP)
m_stack.popFrame(newCallFrame);
#endif
return checkedReturn(result);
}
......@@ -930,6 +942,7 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT
if (UNLIKELY(vm.watchdog.didFire(callFrame)))
return throwTerminatedExecutionException(callFrame);
#if ENABLE(LLINT_C_LOOP)
CallFrame* newCallFrame = m_stack.pushFrame(callFrame, newCodeBlock, scope, argsCount, function);
if (UNLIKELY(!newCallFrame))
return checkedReturn(throwStackOverflowError(callFrame));
......@@ -938,6 +951,13 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT
newCallFrame->setThisValue(thisValue);
for (size_t i = 0; i < args.size(); ++i)
newCallFrame->setArgument(i, args.at(i));
#else
if (UNLIKELY(!m_stack.entryCheck(newCodeBlock, argsCount)))
return checkedReturn(throwStackOverflowError(callFrame));
ProtoCallFrame protoCallFrame;
protoCallFrame.init(newCodeBlock, scope, function, thisValue, argsCount, args.data());
#endif
if (LegacyProfiler* profiler = vm.enabledProfiler())
profiler->willExecute(callFrame, function);
......@@ -952,16 +972,23 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT
#if ENABLE(LLINT_C_LOOP)
result = LLInt::CLoop::execute(newCallFrame, llint_function_for_call_prologue);
#elif ENABLE(JIT)
result = callData.js.functionExecutable->generatedJITCodeForCall()->execute(&m_stack, newCallFrame, &vm);
result = callData.js.functionExecutable->generatedJITCodeForCall()->execute(&vm, &protoCallFrame, m_stack.getTopOfStack());
#endif // ENABLE(JIT)
} else
} else {
#if ENABLE(LLINT_C_LOOP)
result = JSValue::decode(callData.native.function(newCallFrame));
#else
result = JSValue::decode(callToNativeFunction(reinterpret_cast<void*>(callData.native.function), &vm.topCallFrame, &protoCallFrame, m_stack.getTopOfStack()));
#endif
}
}
if (LegacyProfiler* profiler = vm.enabledProfiler())
profiler->didExecute(callFrame, function);
#if ENABLE(LLINT_C_LOOP)
m_stack.popFrame(newCallFrame);
#endif
return checkedReturn(result);
}
......@@ -1005,7 +1032,7 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
if (UNLIKELY(vm.watchdog.didFire(callFrame)))
return throwTerminatedExecutionException(callFrame);
#if ENABLE(LLINT_C_LOOP)
CallFrame* newCallFrame = m_stack.pushFrame(callFrame, newCodeBlock, scope, argsCount, constructor);
if (UNLIKELY(!newCallFrame))
return checkedReturn(throwStackOverflowError(callFrame));
......@@ -1014,6 +1041,13 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
newCallFrame->setThisValue(jsUndefined());
for (size_t i = 0; i < args.size(); ++i)
newCallFrame->setArgument(i, args.at(i));
#else
if (UNLIKELY(!m_stack.entryCheck(newCodeBlock, argsCount)))
return checkedReturn(throwStackOverflowError(callFrame));
ProtoCallFrame protoCallFrame;
protoCallFrame.init(newCodeBlock, scope, constructor, jsUndefined(), argsCount, args.data());
#endif
if (LegacyProfiler* profiler = vm.enabledProfiler())
profiler->willExecute(callFrame, constructor);
......@@ -1028,22 +1062,25 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
#if ENABLE(LLINT_C_LOOP)
result = LLInt::CLoop::execute(newCallFrame, llint_function_for_construct_prologue);
#elif ENABLE(JIT)
result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&m_stack, newCallFrame, &vm);
result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&vm, &protoCallFrame, m_stack.getTopOfStack());
#endif // ENABLE(JIT)
} else {
#if ENABLE(LLINT_C_LOOP)
result = JSValue::decode(constructData.native.function(newCallFrame));
if (!callFrame->hadException()) {
ASSERT_WITH_MESSAGE(result.isObject(), "Host constructor returned non object.");
if (!result.isObject())
throwTypeError(newCallFrame);
}
#else
result = JSValue::decode(callToNativeFunction(reinterpret_cast<void*>(constructData.native.function), &vm.topCallFrame, &protoCallFrame, m_stack.getTopOfStack()));
#endif
if (!callFrame->hadException())
RELEASE_ASSERT(result.isObject());
}
}
if (LegacyProfiler* profiler = vm.enabledProfiler())
profiler->didExecute(callFrame, constructor);
#if ENABLE(LLINT_C_LOOP)
m_stack.popFrame(newCallFrame);
#endif
if (callFrame->hadException())
return 0;
......@@ -1051,7 +1088,11 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
return checkedReturn(asObject(result));
}
#if ENABLE(LLINT_C_LOOP)
CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, int argumentCountIncludingThis, JSScope* scope)
#else
CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, ProtoCallFrame* protoCallFrame, JSFunction* function, int argumentCountIncludingThis, JSScope* scope, JSValue* args)
#endif
{
VM& vm = *scope->vm();
ASSERT(!vm.exception());
......@@ -1070,19 +1111,26 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionE
size_t argsCount = argumentCountIncludingThis;
CallFrame* newCallFrame = m_stack.pushFrame(callFrame, newCodeBlock, scope, argsCount, function);
#if ENABLE(LLINT_C_LOOP)
CallFrame* newCallFrame = m_stack.pushFrame(callFrame, newCodeBlock, scope, argsCount, function);
if (UNLIKELY(!newCallFrame)) {
throwStackOverflowError(callFrame);
return CallFrameClosure();
}
if (UNLIKELY(!newCallFrame)) {
// Return the successful closure:
CallFrameClosure result = { callFrame, newCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis };
#else
if (UNLIKELY(!m_stack.entryCheck(newCodeBlock, argsCount))) {
throwStackOverflowError(callFrame);
return CallFrameClosure();
}
protoCallFrame->init(newCodeBlock, scope, function, jsUndefined(), argsCount, args);
// Return the successful closure:
CallFrameClosure result = { callFrame, newCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis };
CallFrameClosure result = { callFrame, protoCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis };
#endif
return result;
}
......@@ -1096,9 +1144,13 @@ JSValue Interpreter::execute(CallFrameClosure& closure)
return jsNull();
StackStats::CheckPoint stackCheckPoint;
#if ENABLE(LLINT_C_LOOP)
m_stack.validateFence(closure.newCallFrame, "BEFORE");
#endif
closure.resetCallFrame();
#if ENABLE(LLINT_C_LOOP)
m_stack.validateFence(closure.newCallFrame, "STEP 1");
#endif
if (LegacyProfiler* profiler = vm.enabledProfiler())
profiler->willExecute(closure.oldCallFrame, closure.function);
......@@ -1114,7 +1166,9 @@ JSValue Interpreter::execute(CallFrameClosure& closure)
// Hence, we need to preserve the topCallFrame here ourselves before
// repeating this call on a second callback function.
#if ENABLE(LLINT_C_LOOP)
TopCallFrameSetter topCallFrame(vm, closure.newCallFrame);
#endif
// Execute the code:
JSValue result;
......@@ -1125,21 +1179,25 @@ JSValue Interpreter::execute(CallFrameClosure& closure)
#if ENABLE(LLINT_C_LOOP)
result = LLInt::CLoop::execute(closure.newCallFrame, llint_function_for_call_prologue);
#elif ENABLE(JIT)
result = closure.functionExecutable->generatedJITCodeForCall()->execute(&m_stack, closure.newCallFrame, &vm);
result = closure.functionExecutable->generatedJITCodeForCall()->execute(&vm, closure.newCallFrame, m_stack.getTopOfStack());
#endif // ENABLE(JIT)
}
if (LegacyProfiler* profiler = vm.enabledProfiler())
profiler->didExecute(closure.oldCallFrame, closure.function);
#if ENABLE(LLINT_C_LOOP)
m_stack.validateFence(closure.newCallFrame, "AFTER");
#endif
return checkedReturn(result);
}
#if ENABLE(LLINT_C_LOOP)
void Interpreter::endRepeatCall(CallFrameClosure& closure)
{
m_stack.popFrame(closure.newCallFrame);
}
#endif
JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, JSScope* scope)
{
......@@ -1203,12 +1261,20 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue
// Push the frame:
ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
#if ENABLE(LLINT_C_LOOP)
CallFrame* newCallFrame = m_stack.pushFrame(callFrame, codeBlock, scope, 1, 0);
if (UNLIKELY(!newCallFrame))
return checkedReturn(throwStackOverflowError(callFrame));
// Set the arguments for the callee:
newCallFrame->setThisValue(thisValue);
#else
if (UNLIKELY(!m_stack.entryCheck(codeBlock, 1)))
return checkedReturn(throwStackOverflowError(callFrame));
ProtoCallFrame protoCallFrame;
protoCallFrame.init(codeBlock, scope, 0, thisValue, 1);
#endif
if (LegacyProfiler* profiler = vm.enabledProfiler())
profiler->willExecute(callFrame, eval->sourceURL(), eval->lineNo());
......@@ -1222,14 +1288,16 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue
#if ENABLE(LLINT_C_LOOP)
result = LLInt::CLoop::execute(newCallFrame, llint_eval_prologue);
#elif ENABLE(JIT)
result = eval->generatedJITCode()->execute(&m_stack, newCallFrame, &vm);
result = eval->generatedJITCode()->execute(&vm, &protoCallFrame, m_stack.getTopOfStack());
#endif // ENABLE(JIT)
}
if (LegacyProfiler* profiler = vm.enabledProfiler())
profiler->didExecute(callFrame, eval->sourceURL(), eval->lineNo());
#if ENABLE(LLINT_C_LOOP)
m_stack.popFrame(newCallFrame);
#endif
return checkedReturn(result);
}
......
......@@ -59,7 +59,8 @@ namespace JSC {
struct CallFrameClosure;
struct HandlerInfo;
struct Instruction;
struct ProtoCallFrame;
enum DebugHookID {
WillExecuteProgram,
DidExecuteProgram,
......@@ -256,8 +257,12 @@ namespace JSC {
private:
enum ExecutionFlag { Normal, InitializeAndReturn };
#if !ENABLE(LLINT_C_LOOP)
CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, ProtoCallFrame*, JSFunction*, int argumentCountIncludingThis, JSScope*, JSValue*);
#else
CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, JSFunction*, int argumentCountIncludingThis, JSScope*);
void endRepeatCall(CallFrameClosure&);
#endif
JSValue execute(CallFrameClosure&);
void getStackTrace(Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
......
......@@ -35,6 +35,7 @@
#include <wtf/PageReservation.h>
#include <wtf/VMTags.h>
#define ENABLE_DEBUG_JSSTACK 0
#if !defined(NDEBUG) && !defined(ENABLE_DEBUG_JSSTACK)
#define ENABLE_DEBUG_JSSTACK 1
#endif
......@@ -99,6 +100,8 @@ namespace JSC {
Register* getStartOfFrame(CallFrame*);
Register* getTopOfStack();
bool entryCheck(class CodeBlock*, int);
CallFrame* pushFrame(CallFrame* callerFrame, class CodeBlock*,
JSScope*, int argsCount, JSObject* callee);
......
......@@ -51,6 +51,35 @@ inline Register* JSStack::getStartOfFrame(CallFrame* frame)
return getTopOfFrame(callerFrame);
}
inline bool JSStack::entryCheck(class CodeBlock* codeBlock, int argsCount)
{
Register* oldEnd = getTopOfStack();
// Ensure that we have enough space for the parameters:
size_t paddedArgsCount = argsCount;
if (codeBlock) {
size_t numParameters = codeBlock->numParameters();
if (paddedArgsCount < numParameters)
paddedArgsCount = numParameters;
}
Register* newCallFrameSlot = oldEnd - paddedArgsCount - (2 * JSStack::CallFrameHeaderSize) + 1;
#if ENABLE(DEBUG_JSSTACK)
newCallFrameSlot -= JSStack::FenceSize;
#endif
Register* newEnd = newCallFrameSlot;
if (!!codeBlock)
newEnd += virtualRegisterForLocal(codeBlock->frameRegisterCount()).offset();
// Ensure that we have the needed stack capacity to push the new frame:
if (!grow(newEnd))
return false;
return true;
}
inline CallFrame* JSStack::pushFrame(CallFrame* callerFrame,