Diff
Modified: branches/jsCStack/Source/_javascript_Core/ChangeLog (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/ChangeLog 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/ChangeLog 2013-12-21 19:25:09 UTC (rev 160967)
@@ -1,3 +1,75 @@
+2013-12-21 Mark Lam <[email protected]>
+
+ CStack: Update the VMEntryScope's stack limit when the VM enters/exits ErrorMode.
+ https://bugs.webkit.org/show_bug.cgi?id=126009.
+
+ Not yet reviewed.
+
+ 1. Renamed JSStack::updateStackLimit() to setStackLimit() because that
+ is what it actually does. We're going to repurpose the updateStackLimit
+ name for another function.
+
+ 2. Fixed a bug in setStackLimit() where setJSStackLimit() was called with
+ the value of newEnd which points past the end of the stack. The fix is
+ to add 1 to point at the last slot at top of the stack. This is what is
+ the users of the jsStackLimit value expects.
+
+ 3. Introduce the new JSStack::updateStackLimit() which is responsible for
+ re-setting the current stack limit. updateStackLimit() will handle both
+ cases of the JS stack being on the C stack or a separate stack.
+
+ For the C stack case, JStack::updateStackLimit() will check if a
+ VMEntryScope has been installed in the VM. If so, it will tell the
+ VMEntryScope to do the real work of updating the stack limit. The
+ VMEntryScope will take into account whether the VM's Interpreter is
+ in an error handling mode or not when determining the amount of host
+ zone space to reserve on the stack for computing the stack limit value.
+
+ 4. Interpreter::ErrorHandlingMode now calls JSStack::updateStackLimit
+ whenever it enters / exit error handling mode. This allows the stack
+ limit to change with the error mode change.
+
+ 5. A lot of places in the code were throwing StackOverflowErrors by
+ creating and throwing the error themselves instead of using the
+ throwStackOverflowError() helper function. As a result, the VM never
+ got the chance to enter error mode. This is a bug and is now fixed by
+ making all these sites use throwStackOverflowError() instead.
+
+ For sites that can't use throwStackOverflowError(), I updated them to
+ instantiate Interpreter::ErrorHandlingMode to set the error mode
+ appropriately.
+
+ 6. Made JSStack::enableErrorStackReserve() and disableErrorStackReserve()
+ private. They are no longer called from outside of JSStack.
+
+ * interpreter/Interpreter.cpp:
+ (JSC::Interpreter::ErrorHandlingMode::ErrorHandlingMode):
+ (JSC::Interpreter::ErrorHandlingMode::~ErrorHandlingMode):
+ (JSC::sizeFrameForVarargs):
+ * interpreter/JSStack.cpp:
+ (JSC::JSStack::JSStack):
+ (JSC::JSStack::growSlowCase):
+ (JSC::JSStack::updateStackLimit):
+ * interpreter/JSStack.h:
+ * interpreter/JSStackInlines.h:
+ (JSC::JSStack::shrink):
+ (JSC::JSStack::setStackLimit):
+ * jit/JITOperations.cpp:
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ * parser/ParserError.h:
+ (JSC::ParserError::toErrorObject):
+ * runtime/CommonSlowPaths.cpp:
+ (JSC::SLOW_PATH_DECL):
+ * runtime/JSONObject.cpp:
+ (JSC::Walker::walk):
+ * runtime/StringRecursionChecker.cpp:
+ (JSC::StringRecursionChecker::throwStackOverflowError):
+ * runtime/VMEntryScope.cpp:
+ (JSC::VMEntryScope::VMEntryScope):
+ (JSC::VMEntryScope::updateStackLimit):
+ * runtime/VMEntryScope.h:
+
2013-12-21 Filip Pizlo <[email protected]>
Register restoration thunk should restore the ArgumentCount after it restores registers
Modified: branches/jsCStack/Source/_javascript_Core/interpreter/Interpreter.cpp (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/interpreter/Interpreter.cpp 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/interpreter/Interpreter.cpp 2013-12-21 19:25:09 UTC (rev 160967)
@@ -94,9 +94,8 @@
Interpreter::ErrorHandlingMode::ErrorHandlingMode(ExecState *exec)
: m_interpreter(*exec->interpreter())
{
- if (!m_interpreter.m_errorHandlingModeReentry)
- m_interpreter.stack().enableErrorStackReserve();
m_interpreter.m_errorHandlingModeReentry++;
+ m_interpreter.stack().updateStackLimit();
}
Interpreter::ErrorHandlingMode::~ErrorHandlingMode()
@@ -104,7 +103,7 @@
m_interpreter.m_errorHandlingModeReentry--;
ASSERT(m_interpreter.m_errorHandlingModeReentry >= 0);
if (!m_interpreter.m_errorHandlingModeReentry)
- m_interpreter.stack().disableErrorStackReserve();
+ m_interpreter.stack().updateStackLimit();
}
JSValue eval(CallFrame* callFrame)
@@ -161,7 +160,7 @@
unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize + 1);
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
if (argumentCountIncludingThis > Arguments::MaxArguments + 1 || !stack->ensureCapacityFor(newCallFrame->registers())) {
- callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
+ throwStackOverflowError(callFrame);
return 0;
}
return newCallFrame;
@@ -172,7 +171,7 @@
unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize + 1);
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
if (!stack->ensureCapacityFor(newCallFrame->registers())) {
- callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
+ throwStackOverflowError(callFrame);
return 0;
}
return newCallFrame;
@@ -189,7 +188,7 @@
unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1));
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) {
- callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
+ throwStackOverflowError(callFrame);
return 0;
}
return newCallFrame;
@@ -201,7 +200,7 @@
unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1));
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) {
- callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
+ throwStackOverflowError(callFrame);
return 0;
}
return newCallFrame;
@@ -212,7 +211,7 @@
unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1));
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) {
- callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
+ throwStackOverflowError(callFrame);
return 0;
}
return newCallFrame;
Modified: branches/jsCStack/Source/_javascript_Core/interpreter/JSStack.cpp (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/interpreter/JSStack.cpp 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/interpreter/JSStack.cpp 2013-12-21 19:25:09 UTC (rev 160967)
@@ -31,6 +31,7 @@
#include "ConservativeRoots.h"
#include "Interpreter.h"
+#include "VMEntryScope.h"
namespace JSC {
@@ -50,7 +51,7 @@
ASSERT(capacity && isPageAligned(capacity));
m_reservation = PageReservation::reserve(roundUpAllocationSize(capacity * sizeof(Register), commitSize), OSAllocator::JSVMStackPages);
- updateStackLimit(highAddress());
+ setStackLimit(highAddress());
m_commitEnd = highAddress();
m_lastStackTop = baseOfStack();
@@ -73,7 +74,7 @@
// If we have already committed enough memory to satisfy this request,
// just update the end pointer and return.
if (newEnd >= m_commitEnd) {
- updateStackLimit(newEnd);
+ setStackLimit(newEnd);
return true;
}
@@ -89,7 +90,7 @@
m_reservation.commit(reinterpret_cast<char*>(m_commitEnd) - delta, delta);
addToCommittedByteCount(delta);
m_commitEnd = reinterpret_cast_ptr<Register*>(reinterpret_cast<char*>(m_commitEnd) - delta);
- updateStackLimit(newEnd);
+ setStackLimit(newEnd);
return true;
}
@@ -175,4 +176,16 @@
}
}
+void JSStack::updateStackLimit()
+{
+#if ENABLE(LLINT_C_LOOP)
+ if (m_vm.interpreter->isInErrorHandlingMode())
+ enableErrorStackReserve();
+ else
+ disableErrorStackReserve();
+#endif
+ if (m_vm.entryScope)
+ m_vm.entryScope->updateStackLimit();
+}
+
} // namespace JSC
Modified: branches/jsCStack/Source/_javascript_Core/interpreter/JSStack.h (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/interpreter/JSStack.h 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/interpreter/JSStack.h 2013-12-21 19:25:09 UTC (rev 160967)
@@ -83,6 +83,8 @@
bool ensureCapacityFor(Register* newTopOfStack);
+ void updateStackLimit();
+
void gatherConservativeRoots(ConservativeRoots&);
void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&);
void sanitizeStack();
@@ -105,9 +107,6 @@
bool containsAddress(Register* address) { return (lowAddress() <= address && address <= highAddress()); }
- void enableErrorStackReserve();
- void disableErrorStackReserve();
-
#if ENABLE(DEBUG_JSSTACK)
void installFence(CallFrame*, const char *function = "", int lineNo = 0);
void validateFence(CallFrame*, const char *function = "", int lineNo = 0);
@@ -152,8 +151,11 @@
void releaseExcessCapacity();
void addToCommittedByteCount(long);
- void updateStackLimit(Register* newEnd);
+ void setStackLimit(Register* newEnd);
+ void enableErrorStackReserve();
+ void disableErrorStackReserve();
+
VM& m_vm;
Register* m_end;
Register* m_commitEnd;
Modified: branches/jsCStack/Source/_javascript_Core/interpreter/JSStackInlines.h (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/interpreter/JSStackInlines.h 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/interpreter/JSStackInlines.h 2013-12-21 19:25:09 UTC (rev 160967)
@@ -169,7 +169,7 @@
{
if (newEnd >= m_end)
return;
- updateStackLimit(newEnd);
+ setStackLimit(newEnd);
if (m_end == baseOfStack() && (m_commitEnd - baseOfStack()) >= maxExcessCapacity)
releaseExcessCapacity();
}
@@ -182,11 +182,11 @@
return growSlowCase(newEnd);
}
-inline void JSStack::updateStackLimit(Register* newEnd)
+inline void JSStack::setStackLimit(Register* newEnd)
{
m_end = newEnd;
#if ENABLE(LLINT_C_LOOP)
- m_vm.setJSStackLimit(newEnd);
+ m_vm.setJSStackLimit(newEnd + 1);
#endif
}
Modified: branches/jsCStack/Source/_javascript_Core/jit/JITOperations.cpp (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/jit/JITOperations.cpp 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/jit/JITOperations.cpp 2013-12-21 19:25:09 UTC (rev 160967)
@@ -79,6 +79,7 @@
callerFrame = exec;
NativeCallFrameTracer tracer(vm, callerFrame);
+ Interpreter::ErrorHandlingMode mode(callerFrame);
vm->throwException(callerFrame, createStackOverflowError(callerFrame));
}
@@ -92,7 +93,7 @@
int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForCall);
if (missingArgCount < 0)
- vm->throwException(callerFrame, createStackOverflowError(callerFrame));
+ throwStackOverflowError(callerFrame);
return missingArgCount;
}
@@ -107,7 +108,7 @@
int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForConstruct);
if (missingArgCount < 0)
- vm->throwException(callerFrame, createStackOverflowError(callerFrame));
+ throwStackOverflowError(callerFrame);
return missingArgCount;
}
@@ -703,7 +704,7 @@
FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
JSObject* error = functionExecutable->prepareForExecution(execCallee, callee->scope(), kind);
if (error) {
- vm->throwException(exec, createStackOverflowError(exec));
+ throwStackOverflowError(exec);
return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
}
codeBlock = functionExecutable->codeBlockFor(kind);
Modified: branches/jsCStack/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2013-12-21 19:25:09 UTC (rev 160967)
@@ -451,6 +451,7 @@
#endif
{
exec = exec->callerFrame();
+ Interpreter::ErrorHandlingMode mode(exec);
CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec));
pc = returnToThrowForThrownException(exec);
}
Modified: branches/jsCStack/Source/_javascript_Core/parser/ParserError.h (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/parser/ParserError.h 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/parser/ParserError.h 2013-12-21 19:25:09 UTC (rev 160967)
@@ -94,8 +94,10 @@
return addErrorInfo(globalObject->globalExec(), createSyntaxError(globalObject, m_message), m_line, source);
case EvalError:
return createSyntaxError(globalObject, m_message);
- case StackOverflow:
+ case StackOverflow: {
+ Interpreter::ErrorHandlingMode mode(globalObject->globalExec());
return createStackOverflowError(globalObject);
+ }
case OutOfMemory:
return createOutOfMemoryError(globalObject);
}
Modified: branches/jsCStack/Source/_javascript_Core/runtime/CommonSlowPaths.cpp (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/runtime/CommonSlowPaths.cpp 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/runtime/CommonSlowPaths.cpp 2013-12-21 19:25:09 UTC (rev 160967)
@@ -190,6 +190,7 @@
int slotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForCall);
if (slotsToAdd < 0) {
exec = exec->callerFrame();
+ Interpreter::ErrorHandlingMode mode(exec);
CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec));
RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec);
}
@@ -202,6 +203,7 @@
int slotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForConstruct);
if (slotsToAdd < 0) {
exec = exec->callerFrame();
+ Interpreter::ErrorHandlingMode mode(exec);
CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec));
RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec);
}
Modified: branches/jsCStack/Source/_javascript_Core/runtime/JSONObject.cpp (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/runtime/JSONObject.cpp 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/runtime/JSONObject.cpp 2013-12-21 19:25:09 UTC (rev 160967)
@@ -654,7 +654,7 @@
ASSERT(inValue.isObject());
ASSERT(isJSArray(asObject(inValue)) || asObject(inValue)->inherits(JSArray::info()));
if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
- return m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec));
+ return throwStackOverflowError(m_exec);
JSArray* array = asArray(inValue);
arrayStack.push(array);
@@ -705,7 +705,7 @@
ASSERT(inValue.isObject());
ASSERT(!isJSArray(asObject(inValue)) && !asObject(inValue)->inherits(JSArray::info()));
if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
- return m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec));
+ return throwStackOverflowError(m_exec);
JSObject* object = asObject(inValue);
objectStack.push(object);
Modified: branches/jsCStack/Source/_javascript_Core/runtime/StringRecursionChecker.cpp (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/runtime/StringRecursionChecker.cpp 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/runtime/StringRecursionChecker.cpp 2013-12-21 19:25:09 UTC (rev 160967)
@@ -28,7 +28,7 @@
JSValue StringRecursionChecker::throwStackOverflowError()
{
- return m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec));
+ return JSC::throwStackOverflowError(m_exec);
}
JSValue StringRecursionChecker::emptyString()
Modified: branches/jsCStack/Source/_javascript_Core/runtime/VMEntryScope.cpp (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/runtime/VMEntryScope.cpp 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/runtime/VMEntryScope.cpp 2013-12-21 19:25:09 UTC (rev 160967)
@@ -53,8 +53,7 @@
// Clear the exception stack between entries
vm.clearExceptionStack();
- void* limit = m_stack.recursionLimit(requiredCapacity());
- vm.setStackLimit(limit);
+ updateStackLimit();
vm.setLastStackTop(m_stack.origin());
}
@@ -65,6 +64,12 @@
m_vm.setLastStackTop(m_prevLastStackTop);
}
+void VMEntryScope::updateStackLimit()
+{
+ void* limit = m_stack.recursionLimit(requiredCapacity());
+ m_vm.setStackLimit(limit);
+}
+
size_t VMEntryScope::requiredCapacity() const
{
Interpreter* interpreter = m_vm.interpreter;
Modified: branches/jsCStack/Source/_javascript_Core/runtime/VMEntryScope.h (160966 => 160967)
--- branches/jsCStack/Source/_javascript_Core/runtime/VMEntryScope.h 2013-12-21 18:51:04 UTC (rev 160966)
+++ branches/jsCStack/Source/_javascript_Core/runtime/VMEntryScope.h 2013-12-21 19:25:09 UTC (rev 160967)
@@ -40,6 +40,7 @@
JS_EXPORT_PRIVATE VMEntryScope(VM&, JSGlobalObject*);
JS_EXPORT_PRIVATE ~VMEntryScope();
+ void updateStackLimit();
JSGlobalObject* globalObject() const { return m_globalObject; }
private: