Diff
Modified: branches/jsCStack/Source/_javascript_Core/ChangeLog (160946 => 160947)
--- branches/jsCStack/Source/_javascript_Core/ChangeLog 2013-12-21 00:44:36 UTC (rev 160946)
+++ branches/jsCStack/Source/_javascript_Core/ChangeLog 2013-12-21 00:56:24 UTC (rev 160947)
@@ -1,3 +1,50 @@
+2013-12-20 Mark Lam <mark....@apple.com>
+
+ CStack: callToJavaScript should do stack check for incoming args.
+ https://bugs.webkit.org/show_bug.cgi?id=126088.
+
+ Not yet reviewed.
+
+ 1. Change callToJavaScript()'s prototype to:
+ EncodedJSValue callToJavaScript(void*, VM*, ProtoCallFrame*);
+
+ We now pass VM* instead of &vm.topCallFrame for the second argument.
+ This gives us greater utility out of that arg.
+ We also now save the VM* in the VMEntrySentinelFrame instead of
+ &vm.topCallFrame.
+
+ 2. Change callToJavaScript() to do a stack check to ensure that we have
+ adequate stack space to copy all the args from the protoCallFrame.
+ If not, it'll throw a StackOverflowError.
+
+ 3. Removed JSStack::entryCheck() and calls to it.
+
+ callToJavaScript now takes care of the stack check that ensures
+ adequate stack space for incoming args.
+ callToJavaScript does assume that we have adequate stack space for
+ the VMEntrySentinelFrame, but that is ensured by our stack host zone.
+
+ Changes to callToJavaScript are done in the doCallToJavaScript macro.
+ Hence, all the changes apply to callToNativeFunction as well.
+
+ * interpreter/Interpreter.cpp:
+ (JSC::Interpreter::execute):
+ (JSC::Interpreter::executeCall):
+ (JSC::Interpreter::executeConstruct):
+ (JSC::Interpreter::prepareForRepeatCall):
+ * interpreter/JSStack.h:
+ * interpreter/JSStackInlines.h:
+ * jit/JITCode.cpp:
+ (JSC::JITCode::execute):
+ * jit/JITStubs.h:
+ * jit/JITStubsMSVC64.asm: Added a FIXME.
+ * jit/JITStubsX86.h: Added a FIXME.
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::llint_throw_stack_overflow_error):
+ * llint/LLIntSlowPaths.h:
+ * llint/LLIntThunks.h:
+ * llint/LowLevelInterpreter64.asm:
+
2013-12-20 Filip Pizlo <fpi...@apple.com>
Arity check slow path should ensure that when we return, we restore SP back to what the caller expects
Modified: branches/jsCStack/Source/_javascript_Core/interpreter/Interpreter.cpp (160946 => 160947)
--- branches/jsCStack/Source/_javascript_Core/interpreter/Interpreter.cpp 2013-12-21 00:44:36 UTC (rev 160946)
+++ branches/jsCStack/Source/_javascript_Core/interpreter/Interpreter.cpp 2013-12-21 00:56:24 UTC (rev 160947)
@@ -892,9 +892,6 @@
ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
- if (UNLIKELY(!m_stack.entryCheck(codeBlock, 1)))
- return checkedReturn(throwStackOverflowError(callFrame));
-
ProtoCallFrame protoCallFrame;
protoCallFrame.init(codeBlock, scope, 0, thisObj, 1);
@@ -955,9 +952,6 @@
if (UNLIKELY(vm.watchdog.didFire(callFrame)))
return throwTerminatedExecutionException(callFrame);
- if (UNLIKELY(!m_stack.entryCheck(newCodeBlock, argsCount)))
- return checkedReturn(throwStackOverflowError(callFrame));
-
ProtoCallFrame protoCallFrame;
protoCallFrame.init(newCodeBlock, scope, function, thisValue, argsCount, args.data());
@@ -973,7 +967,7 @@
if (isJSCall)
result = callData.js.functionExecutable->generatedJITCodeForCall()->execute(&vm, &protoCallFrame);
else
- result = JSValue::decode(callToNativeFunction(reinterpret_cast<void*>(callData.native.function), &vm.topCallFrame, &protoCallFrame));
+ result = JSValue::decode(callToNativeFunction(reinterpret_cast<void*>(callData.native.function), &vm, &protoCallFrame));
}
if (LegacyProfiler* profiler = vm.enabledProfiler())
@@ -1023,9 +1017,6 @@
if (UNLIKELY(vm.watchdog.didFire(callFrame)))
return throwTerminatedExecutionException(callFrame);
- if (UNLIKELY(!m_stack.entryCheck(newCodeBlock, argsCount)))
- return checkedReturn(throwStackOverflowError(callFrame));
-
ProtoCallFrame protoCallFrame;
protoCallFrame.init(newCodeBlock, scope, constructor, jsUndefined(), argsCount, args.data());
@@ -1041,7 +1032,7 @@
if (isJSConstruct)
result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&vm, &protoCallFrame);
else {
- result = JSValue::decode(callToNativeFunction(reinterpret_cast<void*>(constructData.native.function), &vm.topCallFrame, &protoCallFrame));
+ result = JSValue::decode(callToNativeFunction(reinterpret_cast<void*>(constructData.native.function), &vm, &protoCallFrame));
if (!callFrame->hadException())
RELEASE_ASSERT(result.isObject());
@@ -1076,11 +1067,6 @@
size_t argsCount = argumentCountIncludingThis;
- 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, protoCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis };
@@ -1182,9 +1168,6 @@
ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
- if (UNLIKELY(!m_stack.entryCheck(codeBlock, 1)))
- return checkedReturn(throwStackOverflowError(callFrame));
-
ProtoCallFrame protoCallFrame;
protoCallFrame.init(codeBlock, scope, 0, thisValue, 1);
Modified: branches/jsCStack/Source/_javascript_Core/interpreter/JSStack.h (160946 => 160947)
--- branches/jsCStack/Source/_javascript_Core/interpreter/JSStack.h 2013-12-21 00:44:36 UTC (rev 160946)
+++ branches/jsCStack/Source/_javascript_Core/interpreter/JSStack.h 2013-12-21 00:56:24 UTC (rev 160947)
@@ -101,8 +101,6 @@
Register* startOfFrameFor(CallFrame*);
Register* topOfStack();
- bool entryCheck(class CodeBlock*, int);
-
CallFrame* pushFrame(class CodeBlock*, JSScope*, int argsCount, JSObject* callee);
void popFrame(CallFrame*);
Modified: branches/jsCStack/Source/_javascript_Core/interpreter/JSStackInlines.h (160946 => 160947)
--- branches/jsCStack/Source/_javascript_Core/interpreter/JSStackInlines.h 2013-12-21 00:44:36 UTC (rev 160946)
+++ branches/jsCStack/Source/_javascript_Core/interpreter/JSStackInlines.h 2013-12-21 00:56:24 UTC (rev 160947)
@@ -51,35 +51,6 @@
return topOfFrameFor(callerFrame);
}
-inline bool JSStack::entryCheck(class CodeBlock* codeBlock, int argsCount)
-{
- Register* oldEnd = topOfStack();
-
- // 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* topOfStack = newCallFrameSlot;
- if (!!codeBlock)
- topOfStack += codeBlock->stackPointerOffset();
-
- // Ensure that we have the needed stack capacity to push the new frame:
- if (!grow(topOfStack))
- return false;
-
- return true;
-}
-
inline CallFrame* JSStack::pushFrame(class CodeBlock* codeBlock, JSScope* scope, int argsCount, JSObject* callee)
{
ASSERT(!!scope);
Modified: branches/jsCStack/Source/_javascript_Core/jit/JITCode.cpp (160946 => 160947)
--- branches/jsCStack/Source/_javascript_Core/jit/JITCode.cpp 2013-12-21 00:44:36 UTC (rev 160946)
+++ branches/jsCStack/Source/_javascript_Core/jit/JITCode.cpp 2013-12-21 00:56:24 UTC (rev 160947)
@@ -44,7 +44,7 @@
JSValue JITCode::execute(VM* vm, ProtoCallFrame* protoCallFrame)
{
- JSValue result = JSValue::decode(callToJavaScript(executableAddress(), &vm->topCallFrame, protoCallFrame));
+ JSValue result = JSValue::decode(callToJavaScript(executableAddress(), vm, protoCallFrame));
return vm->exception() ? jsNull() : result;
}
Modified: branches/jsCStack/Source/_javascript_Core/jit/JITStubs.h (160946 => 160947)
--- branches/jsCStack/Source/_javascript_Core/jit/JITStubs.h 2013-12-21 00:44:36 UTC (rev 160946)
+++ branches/jsCStack/Source/_javascript_Core/jit/JITStubs.h 2013-12-21 00:56:24 UTC (rev 160947)
@@ -37,14 +37,13 @@
#if ENABLE(JIT)
#if OS(WINDOWS)
-class ExecState;
-class Register;
struct ProtoCallFrame;
+class VM;
extern "C" {
- EncodedJSValue callToJavaScript(void*, ExecState**, ProtoCallFrame*);
+ EncodedJSValue callToJavaScript(void*, VM*, ProtoCallFrame*);
+ EncodedJSValue callToNativeFunction(void*, VM*, ProtoCallFrame*);
void handleUncaughtException();
- EncodedJSValue callToNativeFunction(void*, ExecState**, ProtoCallFrame*);
}
#endif
Modified: branches/jsCStack/Source/_javascript_Core/jit/JITStubsMSVC64.asm (160946 => 160947)
--- branches/jsCStack/Source/_javascript_Core/jit/JITStubsMSVC64.asm 2013-12-21 00:44:36 UTC (rev 160946)
+++ branches/jsCStack/Source/_javascript_Core/jit/JITStubsMSVC64.asm 2013-12-21 00:56:24 UTC (rev 160947)
@@ -35,6 +35,16 @@
;; FIXME: This function has not been tested as the Win 64 port doesn't currently use the JIT.
;; It is believed to be an accurate adaptation of the assembly created by the llint stub of the
;; same name with changes for agrument register differences.
+
+ ;; FIXME: This code is stale and need to be updated for the following:
+ ;; 1. The prototype is now:
+ ;; EncodedJSValue callToJavaScript(void* code, VM*, ProtoCallFrame*)
+ ;; The code below was implemented for a prototype of:
+ ;; EncodedJSValue callToJavaScript(void* code, ExecState**, ProtoCallFrame*, Register*)
+ ;;
+ ;; 2. Need to add code for a stack check to ensure that we have enough stack space
+ ;; for incoming args.
+
int 3
mov r10, qword ptr[rsp]
push rbp
Modified: branches/jsCStack/Source/_javascript_Core/jit/JITStubsX86.h (160946 => 160947)
--- branches/jsCStack/Source/_javascript_Core/jit/JITStubsX86.h 2013-12-21 00:44:36 UTC (rev 160946)
+++ branches/jsCStack/Source/_javascript_Core/jit/JITStubsX86.h 2013-12-21 00:56:24 UTC (rev 160947)
@@ -206,6 +206,16 @@
// FIXME: Since Windows doesn't use the LLInt, we have inline stubs here.
// Until the LLInt is changed to support Windows, these stub needs to be updated.
+
+ // FIXME: This code is stale and need to be updated for the following:
+ // 1. The prototype is now:
+ // EncodedJSValue callToJavaScript(void* code, VM*, ProtoCallFrame*)
+ // I've left the old prototype in place to give context for what the implementation
+ // below is doing.
+ //
+ // 2. Need to add code for a stack check to ensure that we have enough stack space
+ // for incoming args.
+
__declspec(naked) EncodedJSValue callToJavaScript(void* code, ExecState**, ProtoCallFrame*, Register*)
{
__asm {
Modified: branches/jsCStack/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (160946 => 160947)
--- branches/jsCStack/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2013-12-21 00:44:36 UTC (rev 160946)
+++ branches/jsCStack/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2013-12-21 00:56:24 UTC (rev 160947)
@@ -51,6 +51,7 @@
#include "LowLevelInterpreter.h"
#include "ObjectConstructor.h"
#include "Operations.h"
+#include "ProtoCallFrame.h"
#include "StructureRareDataInlines.h"
#include <wtf/StringPrintStream.h>
@@ -1392,6 +1393,14 @@
LLINT_END();
}
+void llint_throw_stack_overflow_error(VM* vm, ProtoCallFrame* protoFrame)
+{
+ ExecState* exec = vm->topCallFrame;
+ if (!exec)
+ exec = protoFrame->scope()->globalObject()->globalExec();
+ throwStackOverflowError(exec);
+}
+
} } // namespace JSC::LLInt
#endif // ENABLE(LLINT)
Modified: branches/jsCStack/Source/_javascript_Core/llint/LLIntSlowPaths.h (160946 => 160947)
--- branches/jsCStack/Source/_javascript_Core/llint/LLIntSlowPaths.h 2013-12-21 00:44:36 UTC (rev 160946)
+++ branches/jsCStack/Source/_javascript_Core/llint/LLIntSlowPaths.h 2013-12-21 00:56:24 UTC (rev 160947)
@@ -36,6 +36,7 @@
class ExecState;
struct Instruction;
+struct ProtoCallFrame;
namespace LLInt {
@@ -122,6 +123,7 @@
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_from_scope);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_to_scope);
+extern "C" void llint_throw_stack_overflow_error(VM*, ProtoCallFrame*);
} } // namespace JSC::LLInt
Modified: branches/jsCStack/Source/_javascript_Core/llint/LLIntThunks.h (160946 => 160947)
--- branches/jsCStack/Source/_javascript_Core/llint/LLIntThunks.h 2013-12-21 00:44:36 UTC (rev 160946)
+++ branches/jsCStack/Source/_javascript_Core/llint/LLIntThunks.h 2013-12-21 00:56:24 UTC (rev 160947)
@@ -34,14 +34,12 @@
namespace JSC {
-class ExecState;
-class Register;
class VM;
struct ProtoCallFrame;
extern "C" {
- EncodedJSValue callToJavaScript(void*, ExecState**, ProtoCallFrame*);
- EncodedJSValue callToNativeFunction(void*, ExecState**, ProtoCallFrame*);
+ EncodedJSValue callToJavaScript(void*, VM*, ProtoCallFrame*);
+ EncodedJSValue callToNativeFunction(void*, VM*, ProtoCallFrame*);
#if ENABLE(JIT)
void handleUncaughtException();
#endif
Modified: branches/jsCStack/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (160946 => 160947)
--- branches/jsCStack/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2013-12-21 00:44:36 UTC (rev 160946)
+++ branches/jsCStack/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2013-12-21 00:56:24 UTC (rev 160947)
@@ -151,9 +151,8 @@
macro doCallToJavaScript(makeCall)
if X86_64
const entry = t4
- const vmTopCallFrame = t5
+ const vm = t5
const protoCallFrame = t1
- const topOfStack = t2
const previousCFR = t0
const previousPC = t6
@@ -162,9 +161,8 @@
const temp3 = t6
elsif ARM64
const entry = a0
- const vmTopCallFrame = a1
+ const vm = a1
const protoCallFrame = a2
- const topOfStack = a3
const previousCFR = t5
const previousPC = lr
@@ -181,12 +179,14 @@
checkStackPointerAlignment(temp2, 0xbad0dc01)
- # Allocate and initialize the sentinel frame.
+ # The stack host zone ensures that we have adequate space for the
+ # VMEntrySentinelFrame. Proceed with allocating and initializing the
+ # sentinel frame.
move sp, cfr
subp CallFrameHeaderSlots*8, cfr
storep 0, ArgumentCount[cfr]
- storep vmTopCallFrame, Callee[cfr]
- loadp [vmTopCallFrame], temp2
+ storep vm, Callee[cfr]
+ loadp VM::topCallFrame[vm], temp2
storep temp2, ScopeChain[cfr]
storep 1, CodeBlock[cfr]
storep previousPC, ReturnPC[cfr]
@@ -195,8 +195,27 @@
loadi ProtoCallFrame::paddedArgCount[protoCallFrame], temp2
addp CallFrameHeaderSlots, temp2, temp2
lshiftp 3, temp2
- subp cfr, temp2, sp
+ subp cfr, temp2, temp1
+ # Ensure that we have enough additional stack capacity for the incoming args,
+ # and the frame for the JS code we're executing. We need to do this check
+ # before we start copying the args from the protoCallFrame below.
+ bpaeq temp1, VM::m_jsStackLimit[vm], .stackHeightOK
+
+ move cfr, sp
+
+ if C_LOOP
+ # FIXME: Need to call stack check here to see if we can grow the stack.
+ # Will need to preserve registers so that we can recover if we do not end
+ # up throwing a StackOverflowError.
+ end
+
+ cCall2(_llint_throw_stack_overflow_error, vm, protoCallFrame)
+ callToJavaScriptEpilogue()
+ ret
+
+.stackHeightOK:
+ move temp1, sp
move 5, temp1
.copyHeaderLoop:
@@ -228,7 +247,7 @@
jmp .copyArgsLoop
.copyArgsDone:
- storep sp, [vmTopCallFrame]
+ storep sp, VM::topCallFrame[vm]
move 0xffff000000000000, csr1
addp 2, csr1, csr2
@@ -243,9 +262,9 @@
loadp CallerFrame[cfr], cfr
.calleeFramePopped:
- loadp Callee[cfr], temp2 # VM.topCallFrame
- loadp ScopeChain[cfr], temp3
- storep temp3, [temp2]
+ loadp Callee[cfr], temp2 # VM
+ loadp ScopeChain[cfr], temp3 # previous topCallFrame
+ storep temp3, VM::topCallFrame[temp2]
checkStackPointerAlignment(temp3, 0xbad0dc04)
@@ -285,9 +304,9 @@
# returning to the caller C frame.
loadp CallerFrame[cfr], cfr
- loadp Callee[cfr], t3 # VM.topCallFrame
- loadp ScopeChain[cfr], t6
- storep t6, [t3]
+ loadp Callee[cfr], t3 # VM
+ loadp ScopeChain[cfr], t6 # previous topCallFrame
+ storep t6, VM::topCallFrame[t3]
callToJavaScriptEpilogue()
ret