Title: [160960] branches/jsCStack/Source/_javascript_Core
Revision
160960
Author
mark....@apple.com
Date
2013-12-20 23:11:59 -0800 (Fri, 20 Dec 2013)

Log Message

CStack: Introduce JSStack::ensureCapacityFor().
https://bugs.webkit.org/show_bug.cgi?id=126109.

Not yet reviewed.

Client code should use JSStack::ensureCapacityFor() when checking for
available stack space for pushing JS frames or making arity adjustments.
JSStack::ensureCapacityFor() works for both cases of the JS stack on the
C stack or as a sperate stack.

JSStack::grow() is now private, and is only used by the C Loop LLINT.

Also made some other JSStack methods private as they are not needed
outside of the JSSTack class.

* dfg/DFGOSREntry.cpp:
(JSC::DFG::prepareOSREntry):
* ftl/FTLOSREntry.cpp:
(JSC::FTL::prepareOSREntry):
* interpreter/Interpreter.cpp:
(JSC::sizeFrameForVarargs):
* interpreter/JSStack.h:
* interpreter/JSStackInlines.h:
(JSC::JSStack::ensureCapacityFor):
(JSC::JSStack::topOfStackForCapacityCheck):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
(JSC::CommonSlowPaths::arityCheckFor):

Modified Paths

Diff

Modified: branches/jsCStack/Source/_javascript_Core/ChangeLog (160959 => 160960)


--- branches/jsCStack/Source/_javascript_Core/ChangeLog	2013-12-21 05:23:10 UTC (rev 160959)
+++ branches/jsCStack/Source/_javascript_Core/ChangeLog	2013-12-21 07:11:59 UTC (rev 160960)
@@ -1,3 +1,35 @@
+2013-12-20  Mark Lam  <mark....@apple.com>
+
+        CStack: Introduce JSStack::ensureCapacityFor().
+        https://bugs.webkit.org/show_bug.cgi?id=126109.
+
+        Not yet reviewed.
+
+        Client code should use JSStack::ensureCapacityFor() when checking for
+        available stack space for pushing JS frames or making arity adjustments.
+        JSStack::ensureCapacityFor() works for both cases of the JS stack on the
+        C stack or as a sperate stack.
+
+        JSStack::grow() is now private, and is only used by the C Loop LLINT.
+
+        Also made some other JSStack methods private as they are not needed
+        outside of the JSSTack class.
+
+        * dfg/DFGOSREntry.cpp:
+        (JSC::DFG::prepareOSREntry):
+        * ftl/FTLOSREntry.cpp:
+        (JSC::FTL::prepareOSREntry):
+        * interpreter/Interpreter.cpp:
+        (JSC::sizeFrameForVarargs):
+        * interpreter/JSStack.h:
+        * interpreter/JSStackInlines.h:
+        (JSC::JSStack::ensureCapacityFor):
+        (JSC::JSStack::topOfStackForCapacityCheck):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * runtime/CommonSlowPaths.h:
+        (JSC::CommonSlowPaths::arityCheckFor):
+
 2013-12-20  Filip Pizlo  <fpi...@apple.com>
 
         FTL OSR exit should be able to handle the arity check fail case

Modified: branches/jsCStack/Source/_javascript_Core/dfg/DFGOSREntry.cpp (160959 => 160960)


--- branches/jsCStack/Source/_javascript_Core/dfg/DFGOSREntry.cpp	2013-12-21 05:23:10 UTC (rev 160959)
+++ branches/jsCStack/Source/_javascript_Core/dfg/DFGOSREntry.cpp	2013-12-21 07:11:59 UTC (rev 160960)
@@ -188,7 +188,7 @@
     //    would have otherwise just kept running albeit less quickly.
     
     unsigned frameSize = jitCode->common.requiredRegisterCountForExecutionAndExit();
-    if (!vm->interpreter->stack().grow(&exec->registers()[virtualRegisterForLocal(frameSize).offset()])) {
+    if (!vm->interpreter->stack().ensureCapacityFor(&exec->registers()[virtualRegisterForLocal(frameSize - 1).offset()])) {
         if (Options::verboseOSR())
             dataLogF("    OSR failed because stack growth failed.\n");
         return 0;

Modified: branches/jsCStack/Source/_javascript_Core/ftl/FTLOSREntry.cpp (160959 => 160960)


--- branches/jsCStack/Source/_javascript_Core/ftl/FTLOSREntry.cpp	2013-12-21 05:23:10 UTC (rev 160959)
+++ branches/jsCStack/Source/_javascript_Core/ftl/FTLOSREntry.cpp	2013-12-21 07:11:59 UTC (rev 160960)
@@ -80,7 +80,7 @@
         scratch[local] = JSValue::encode(values.local(local));
     
     int stackFrameSize = entryCode->common.requiredRegisterCountForExecutionAndExit();
-    if (!vm.interpreter->stack().grow(&exec->registers()[virtualRegisterForLocal(stackFrameSize).offset()])) {
+    if (!vm.interpreter->stack().ensureCapacityFor(&exec->registers()[virtualRegisterForLocal(stackFrameSize - 1).offset()])) {
         if (Options::verboseOSR())
             dataLog("    OSR failed because stack growth failed.\n");
         return 0;

Modified: branches/jsCStack/Source/_javascript_Core/interpreter/Interpreter.cpp (160959 => 160960)


--- branches/jsCStack/Source/_javascript_Core/interpreter/Interpreter.cpp	2013-12-21 05:23:10 UTC (rev 160959)
+++ branches/jsCStack/Source/_javascript_Core/interpreter/Interpreter.cpp	2013-12-21 07:11:59 UTC (rev 160960)
@@ -160,7 +160,7 @@
         unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
         unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize + 1);
         CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
-        if (argumentCountIncludingThis > Arguments::MaxArguments + 1 || !stack->grow(newCallFrame->registers())) {
+        if (argumentCountIncludingThis > Arguments::MaxArguments + 1 || !stack->ensureCapacityFor(newCallFrame->registers())) {
             callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
             return 0;
         }
@@ -171,7 +171,7 @@
         unsigned argumentCountIncludingThis = 1;
         unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(),  -firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize + 1);
         CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
-        if (!stack->grow(newCallFrame->registers())) {
+        if (!stack->ensureCapacityFor(newCallFrame->registers())) {
             callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
             return 0;
         }
@@ -188,7 +188,7 @@
         unsigned argCount = argsObject->length(callFrame);
         unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1));
         CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
-        if (argCount > Arguments::MaxArguments || !stack->grow(newCallFrame->registers())) {
+        if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) {
             callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
             return 0;
         }
@@ -200,7 +200,7 @@
         unsigned argCount = array->length();
         unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1));
         CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
-        if (argCount > Arguments::MaxArguments || !stack->grow(newCallFrame->registers())) {
+        if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) {
             callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
             return 0;
         }
@@ -211,7 +211,7 @@
     unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
     unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1));
     CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
-    if (argCount > Arguments::MaxArguments || !stack->grow(newCallFrame->registers())) {
+    if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) {
         callFrame->vm().throwException(callFrame,  createStackOverflowError(callFrame));
         return 0;
     }

Modified: branches/jsCStack/Source/_javascript_Core/interpreter/JSStack.h (160959 => 160960)


--- branches/jsCStack/Source/_javascript_Core/interpreter/JSStack.h	2013-12-21 05:23:10 UTC (rev 160959)
+++ branches/jsCStack/Source/_javascript_Core/interpreter/JSStack.h	2013-12-21 07:11:59 UTC (rev 160960)
@@ -81,6 +81,8 @@
         JSStack(VM&, size_t capacity = defaultCapacity);
         ~JSStack();
         
+        bool ensureCapacityFor(Register* newTopOfStack);
+
         void gatherConservativeRoots(ConservativeRoots&);
         void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&);
         void sanitizeStack();
@@ -92,14 +94,10 @@
 
         size_t size() const { return highAddress() - lowAddress(); }
 
-        bool grow(Register* topOfStack);
-        
         static size_t committedByteCount();
         static void initializeThreading();
 
-        Register* topOfFrameFor(CallFrame*);
         Register* startOfFrameFor(CallFrame*);
-        Register* topOfStack();
 
         CallFrame* pushFrame(class CodeBlock*, JSScope*, int argsCount, JSObject* callee);
 
@@ -120,6 +118,11 @@
 #endif // !ENABLE(DEBUG_JSSTACK)
 
     private:
+
+        inline Register* topOfFrameFor(CallFrame*);
+        inline Register* topOfStack();
+        inline Register* topOfStackForCapacityCheck();
+
         Register* lowAddress() const
         {
             return m_end;
@@ -143,6 +146,7 @@
         void installTrapsAfterFrame(CallFrame*) { }
 #endif
 
+        bool grow(Register* topOfStack);
         bool growSlowCase(Register*);
         void shrink(Register*);
         void releaseExcessCapacity();

Modified: branches/jsCStack/Source/_javascript_Core/interpreter/JSStackInlines.h (160959 => 160960)


--- branches/jsCStack/Source/_javascript_Core/interpreter/JSStackInlines.h	2013-12-21 05:23:10 UTC (rev 160959)
+++ branches/jsCStack/Source/_javascript_Core/interpreter/JSStackInlines.h	2013-12-21 07:11:59 UTC (rev 160960)
@@ -33,6 +33,36 @@
 
 namespace JSC {
 
+inline bool JSStack::ensureCapacityFor(Register* newTopOfStack)
+{
+#if ENABLE(LLINT_C_LOOP)
+    return grow(newTopOfStack);
+#else
+    ASSERT(wtfThreadData().stack().isGrowingDownward());
+    Register* topOfStack = topOfStackForCapacityCheck();
+    if (newTopOfStack > topOfStack)
+        return true;
+    size_t neededCapacity = (topOfStack - newTopOfStack) * sizeof(Register);
+    return m_vm.isSafeToRecurse(neededCapacity);
+#endif
+}
+
+inline Register* JSStack::topOfStackForCapacityCheck()
+{
+#if !ENABLE(LLINT_C_LOOP)
+    // We're trying to get an estimate of the top of the stack for the purpose
+    // of a capacity check. If m_topCallFrame is 0, then we can't calculate an
+    // accurate top of stack value. Just use the current stack position as an
+    // estimate for the top of the stack from where JS code will start executing.
+    // This is conservative, but it will be safe.
+    if (!m_topCallFrame) {
+        Register* p = reinterpret_cast<Register*>(&p);
+        return p;
+    }
+#endif
+    return topOfStack() + 1;
+}
+
 inline Register* JSStack::topOfFrameFor(CallFrame* frame)
 {
     if (UNLIKELY(!frame))

Modified: branches/jsCStack/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (160959 => 160960)


--- branches/jsCStack/Source/_javascript_Core/llint/LLIntSlowPaths.cpp	2013-12-21 05:23:10 UTC (rev 160959)
+++ branches/jsCStack/Source/_javascript_Core/llint/LLIntSlowPaths.cpp	2013-12-21 07:11:59 UTC (rev 160960)
@@ -441,8 +441,15 @@
     dataLogF("Num vars = %u.\n", exec->codeBlock()->m_numVars);
     dataLogF("Current end is at %p.\n", exec->vm().interpreter->stack().end());
 #endif
-    ASSERT(!exec->vm().interpreter->stack().containsAddress(&exec->registers()[virtualRegisterForLocal(exec->codeBlock()->m_numCalleeRegisters).offset()]));
-    if (UNLIKELY(!vm.interpreter->stack().grow(&exec->registers()[virtualRegisterForLocal(exec->codeBlock()->m_numCalleeRegisters).offset()]))) {
+
+    // For JIT enabled builds which uses the C stack, the stack is not growable.
+    // Hence, if we get here, then we know a stack overflow is imminent. So, just
+    // throw the StackOverflowError unconditionally.
+#if ENABLE(LLINT_C_LOOP)
+    ASSERT(!exec->vm().interpreter->stack().containsAddress(exec->topOfFrame()));
+    if (UNLIKELY(!vm.interpreter->stack().ensureCapacityFor(exec->topOfFrame())))
+#endif
+    {
         exec = exec->callerFrame();
         CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec));
         pc = returnToThrowForThrownException(exec);

Modified: branches/jsCStack/Source/_javascript_Core/runtime/CommonSlowPaths.h (160959 => 160960)


--- branches/jsCStack/Source/_javascript_Core/runtime/CommonSlowPaths.h	2013-12-21 05:23:10 UTC (rev 160959)
+++ branches/jsCStack/Source/_javascript_Core/runtime/CommonSlowPaths.h	2013-12-21 07:11:59 UTC (rev 160960)
@@ -67,15 +67,8 @@
     int neededStackSpace = missingArgumentCount + 1; // Allow space to save the original return PC.
     int paddedStackSpace = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), neededStackSpace);
 
-#if ENABLE(LLINT_CLOOP)
-    if (!stack->grow(exec->registers() - passedStackSpace))
+    if (!stack->ensureCapacityFor(exec->registers() - paddedStackSpace))
         return -1;
-#else
-    UNUSED_PARAM(stack);
-    if (!exec->vm().isSafeToRecurse(paddedStackSpace * sizeof(Register)))
-        return -1;
-#endif // ENABLE(LLINT_CLOOP)
-
     return paddedStackSpace / stackAlignmentRegisters();
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to