<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[189454] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/189454">189454</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2015-09-06 22:19:28 -0700 (Sun, 06 Sep 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>StackOverflow stack unwinding should stop at native frames.
https://bugs.webkit.org/show_bug.cgi?id=148749

Reviewed by Michael Saboff.

In the present code, after ping-pong'ing back and forth between native and JS
code a few times, if we have a stack overflow on re-entry into the VM to run
JS code's whose stack frame would overflow the JS stack, the code will end up
unwinding past the native function that is making the call to re-enter the VM.
As a result, any clean up code (e.g. destructors for stack variables) in the
skipped native function frame (and its chain of native function callers) will
not be called.

This patch is based on the Michael Saboff's fix of this issue landed on the
jsc-tailcall branch: http://trac.webkit.org/changeset/188555

We now check for the case where there are no JS frames to unwind since the
last native frame, and treat the exception as an unhandled exception.  The
native function is responsible for further propagating the exception if needed.

Other supporting work:
1. Remove vm-&gt;vmEntryFrameForThrow.  It should always be the same as
   vm-&gt;topVMEntryFrame.
2. Change operationThrowStackOverflowError() to use the throwStackOverflowError()
   helper function instead of rolling its own.
3. Added a test that exercises this edge case.  The test should not hang or crash.

* API/tests/PingPongStackOverflowTest.cpp: Added.
(PingPongStackOverflowObject_hasInstance):
(testPingPongStackOverflow):
* API/tests/PingPongStackOverflowTest.h: Added.
* API/tests/testapi.c:
(main):
* JavaScriptCore.xcodeproj/project.pbxproj:
* interpreter/CallFrame.h:
(JSC::ExecState::operator=):
(JSC::ExecState::callerFrame):
(JSC::ExecState::callerFrameOrVMEntryFrame):
(JSC::ExecState::argIndexForRegister):
(JSC::ExecState::callerFrameAndPC):
* interpreter/Interpreter.cpp:
(JSC::UnwindFunctor::UnwindFunctor):
(JSC::UnwindFunctor::operator()):
(JSC::Interpreter::unwind):
* interpreter/Interpreter.h:
(JSC::NativeCallFrameTracer::NativeCallFrameTracer):
(JSC::Interpreter::sampler):
* jit/CCallHelpers.h:
(JSC::CCallHelpers::jumpToExceptionHandler):
* jit/JITExceptions.cpp:
(JSC::genericUnwind):
* jit/JITExceptions.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_catch):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_catch):
* jit/JITOperations.cpp:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/VM.h:
(JSC::VM::exceptionOffset):
(JSC::VM::callFrameForThrowOffset):
(JSC::VM::vmEntryFrameForThrowOffset): Deleted.
(JSC::VM::topVMEntryFrameOffset): Deleted.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreAPIteststestapic">trunk/Source/JavaScriptCore/API/tests/testapi.c</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreinterpreterCallFrameh">trunk/Source/JavaScriptCore/interpreter/CallFrame.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreinterpreterInterpretercpp">trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreinterpreterInterpreterh">trunk/Source/JavaScriptCore/interpreter/Interpreter.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCCallHelpersh">trunk/Source/JavaScriptCore/jit/CCallHelpers.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITExceptionscpp">trunk/Source/JavaScriptCore/jit/JITExceptions.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITExceptionsh">trunk/Source/JavaScriptCore/jit/JITExceptions.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodescpp">trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodes32_64cpp">trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOperationscpp">trunk/Source/JavaScriptCore/jit/JITOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMh">trunk/Source/JavaScriptCore/runtime/VM.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreAPItestsPingPongStackOverflowTestcpp">trunk/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreAPItestsPingPongStackOverflowTesth">trunk/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreAPItestsPingPongStackOverflowTestcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.cpp (0 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.cpp        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -0,0 +1,182 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+#include &quot;PingPongStackOverflowTest.h&quot;
+
+#include &quot;InitializeThreading.h&quot;
+#include &quot;JSContextRefPrivate.h&quot;
+#include &quot;JavaScriptCore.h&quot;
+#include &quot;Options.h&quot;
+#include &lt;wtf/text/StringBuilder.h&gt;
+
+using JSC::Options;
+
+static JSGlobalContextRef context = nullptr;
+static int nativeRecursionCount = 0;
+
+static bool PingPongStackOverflowObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(constructor);
+
+    JSStringRef hasInstanceName = JSStringCreateWithUTF8CString(&quot;hasInstance&quot;);
+    JSValueRef hasInstance = JSObjectGetProperty(context, constructor, hasInstanceName, exception);
+    JSStringRelease(hasInstanceName);
+    if (!hasInstance)
+        return false;
+
+    int countAtEntry = nativeRecursionCount++;
+
+    JSValueRef result = 0;
+    if (nativeRecursionCount &lt; 100) {
+        JSObjectRef function = JSValueToObject(context, hasInstance, exception);
+        result = JSObjectCallAsFunction(context, function, constructor, 1, &amp;possibleValue, exception);
+    } else {
+        StringBuilder builder;
+        builder.append(&quot;dummy.valueOf([0]&quot;);
+        for (int i = 1; i &lt; 35000; i++) {
+            builder.append(&quot;, [&quot;);
+            builder.appendNumber(i);
+            builder.append(&quot;]&quot;);
+        }
+        builder.append(&quot;);&quot;);
+
+        JSStringRef script = JSStringCreateWithUTF8CString(builder.toString().utf8().data());
+        result = JSEvaluateScript(context, script, NULL, NULL, 1, exception);
+        JSStringRelease(script);
+    }
+
+    --nativeRecursionCount;
+    if (nativeRecursionCount != countAtEntry)
+        printf(&quot;    ERROR: PingPongStackOverflow test saw a recursion count mismatch\n&quot;);
+
+    return result &amp;&amp; JSValueToBoolean(context, result);
+}
+
+JSClassDefinition PingPongStackOverflowObject_definition = {
+    0,
+    kJSClassAttributeNone,
+    
+    &quot;PingPongStackOverflowObject&quot;,
+    NULL,
+    
+    NULL,
+    NULL,
+    
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    PingPongStackOverflowObject_hasInstance,
+    NULL,
+};
+
+static JSClassRef PingPongStackOverflowObject_class(JSContextRef context)
+{
+    UNUSED_PARAM(context);
+    
+    static JSClassRef jsClass;
+    if (!jsClass)
+        jsClass = JSClassCreate(&amp;PingPongStackOverflowObject_definition);
+    
+    return jsClass;
+}
+
+// This tests tests a stack overflow on VM reentry into a JS function from a native function
+// after ping-pong'ing back and forth between JS and native functions multiple times.
+// This test should not hang or crash.
+int testPingPongStackOverflow()
+{
+    bool failed = false;
+
+    JSC::initializeThreading();
+    Options::initialize(); // Ensure options is initialized first.
+
+    auto origReservedZoneSize = Options::reservedZoneSize();
+    auto origErrorModeReservedZoneSize = Options::errorModeReservedZoneSize();
+    auto origUseLLInt = Options::useLLInt();
+    auto origMaxPerThreadStackUsage = Options::maxPerThreadStackUsage();
+
+    Options::reservedZoneSize() = 128 * KB;
+    Options::errorModeReservedZoneSize() = 64 * KB;
+#if ENABLE(JIT)
+    // Normally, we want to disable the LLINT to force the use of JITted code which is necessary for
+    // reproducing the regression in https://bugs.webkit.org/show_bug.cgi?id=148749. However, we only
+    // want to do this if the LLINT isn't the only available execution engine.
+    Options::useLLInt() = false;
+#endif
+
+    const char* scriptString =
+        &quot;var count = 0;&quot; \
+        &quot;PingPongStackOverflowObject.hasInstance = function f() {&quot; \
+        &quot;    return (undefined instanceof PingPongStackOverflowObject);&quot; \
+        &quot;};&quot; \
+        &quot;PingPongStackOverflowObject.__proto__ = undefined;&quot; \
+        &quot;undefined instanceof PingPongStackOverflowObject;&quot;;
+
+    JSValueRef scriptResult = nullptr;
+    JSValueRef exception = nullptr;
+    JSStringRef script = JSStringCreateWithUTF8CString(scriptString);
+
+    nativeRecursionCount = 0;
+    context = JSGlobalContextCreateInGroup(nullptr, nullptr);
+
+    JSObjectRef globalObject = JSContextGetGlobalObject(context);
+    ASSERT(JSValueIsObject(context, globalObject));
+
+    JSObjectRef PingPongStackOverflowObject = JSObjectMake(context, PingPongStackOverflowObject_class(context), NULL);
+    JSStringRef PingPongStackOverflowObjectString = JSStringCreateWithUTF8CString(&quot;PingPongStackOverflowObject&quot;);
+    JSObjectSetProperty(context, globalObject, PingPongStackOverflowObjectString, PingPongStackOverflowObject, kJSPropertyAttributeNone, NULL);
+    JSStringRelease(PingPongStackOverflowObjectString);
+
+    unsigned stackSize = 32 * KB;
+    Options::maxPerThreadStackUsage() = stackSize + Options::reservedZoneSize();
+
+    exception = nullptr;
+    scriptResult = JSEvaluateScript(context, script, nullptr, nullptr, 1, &amp;exception);
+
+    if (!exception) {
+        printf(&quot;FAIL: PingPongStackOverflowError not thrown in PingPongStackOverflow test\n&quot;);
+        failed = true;
+    } else if (nativeRecursionCount) {
+        printf(&quot;FAIL: Unbalanced native recursion count: %d in PingPongStackOverflow test\n&quot;, nativeRecursionCount);
+        failed = true;
+    } else {
+        printf(&quot;PASS: PingPongStackOverflow test.\n&quot;);
+    }
+
+    Options::reservedZoneSize() = origReservedZoneSize;
+    Options::errorModeReservedZoneSize() = origErrorModeReservedZoneSize;
+    Options::useLLInt() = origUseLLInt;
+    Options::maxPerThreadStackUsage() = origMaxPerThreadStackUsage;
+
+    return failed;
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreAPItestsPingPongStackOverflowTesth"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.h (0 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.h        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -0,0 +1,39 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PingPongStackOverflowTest_h
+#define PingPongStackOverflowTest_h
+
+#ifdef __cplusplus
+extern &quot;C&quot; {
+#endif
+
+int testPingPongStackOverflow();
+
+#ifdef __cplusplus
+} /* extern &quot;C&quot; */
+#endif
+
+#endif /* PingPongStackOverflowTest_h */
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreAPIteststestapic"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/API/tests/testapi.c (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/tests/testapi.c        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/API/tests/testapi.c        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -41,10 +41,10 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;CompareAndSwapTest.h&quot;
</span><span class="cx"> #include &quot;CustomGlobalObjectClassTest.h&quot;
</span><ins>+#include &quot;ExecutionTimeLimitTest.h&quot;
</ins><span class="cx"> #include &quot;GlobalContextWithFinalizerTest.h&quot;
</span><ins>+#include &quot;PingPongStackOverflowTest.h&quot;
</ins><span class="cx"> 
</span><del>-#include &quot;ExecutionTimeLimitTest.h&quot;
-
</del><span class="cx"> #if JSC_OBJC_API_ENABLED
</span><span class="cx"> void testObjectiveCAPI(void);
</span><span class="cx"> #endif
</span><span class="lines">@@ -1893,6 +1893,7 @@
</span><span class="cx"> 
</span><span class="cx">     failed = testExecutionTimeLimit() || failed;
</span><span class="cx">     failed = testGlobalContextWithFinalizer() || failed;
</span><ins>+    failed = testPingPongStackOverflow() || failed;
</ins><span class="cx"> 
</span><span class="cx">     // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
</span><span class="cx">     function = NULL;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -1,3 +1,70 @@
</span><ins>+2015-09-06  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        StackOverflow stack unwinding should stop at native frames.
+        https://bugs.webkit.org/show_bug.cgi?id=148749
+
+        Reviewed by Michael Saboff.
+
+        In the present code, after ping-pong'ing back and forth between native and JS
+        code a few times, if we have a stack overflow on re-entry into the VM to run
+        JS code's whose stack frame would overflow the JS stack, the code will end up
+        unwinding past the native function that is making the call to re-enter the VM.
+        As a result, any clean up code (e.g. destructors for stack variables) in the
+        skipped native function frame (and its chain of native function callers) will
+        not be called.
+
+        This patch is based on the Michael Saboff's fix of this issue landed on the
+        jsc-tailcall branch: http://trac.webkit.org/changeset/188555
+
+        We now check for the case where there are no JS frames to unwind since the
+        last native frame, and treat the exception as an unhandled exception.  The
+        native function is responsible for further propagating the exception if needed.
+
+        Other supporting work:
+        1. Remove vm-&gt;vmEntryFrameForThrow.  It should always be the same as
+           vm-&gt;topVMEntryFrame.
+        2. Change operationThrowStackOverflowError() to use the throwStackOverflowError()
+           helper function instead of rolling its own.
+        3. Added a test that exercises this edge case.  The test should not hang or crash.
+
+        * API/tests/PingPongStackOverflowTest.cpp: Added.
+        (PingPongStackOverflowObject_hasInstance):
+        (testPingPongStackOverflow):
+        * API/tests/PingPongStackOverflowTest.h: Added.
+        * API/tests/testapi.c:
+        (main):
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * interpreter/CallFrame.h:
+        (JSC::ExecState::operator=):
+        (JSC::ExecState::callerFrame):
+        (JSC::ExecState::callerFrameOrVMEntryFrame):
+        (JSC::ExecState::argIndexForRegister):
+        (JSC::ExecState::callerFrameAndPC):
+        * interpreter/Interpreter.cpp:
+        (JSC::UnwindFunctor::UnwindFunctor):
+        (JSC::UnwindFunctor::operator()):
+        (JSC::Interpreter::unwind):
+        * interpreter/Interpreter.h:
+        (JSC::NativeCallFrameTracer::NativeCallFrameTracer):
+        (JSC::Interpreter::sampler):
+        * jit/CCallHelpers.h:
+        (JSC::CCallHelpers::jumpToExceptionHandler):
+        * jit/JITExceptions.cpp:
+        (JSC::genericUnwind):
+        * jit/JITExceptions.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_catch):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_catch):
+        * jit/JITOperations.cpp:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/VM.h:
+        (JSC::VM::exceptionOffset):
+        (JSC::VM::callFrameForThrowOffset):
+        (JSC::VM::vmEntryFrameForThrowOffset): Deleted.
+        (JSC::VM::topVMEntryFrameOffset): Deleted.
+
</ins><span class="cx"> 2015-09-06  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, disable module tests in Windows until name resolution is fixed
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -1764,6 +1764,7 @@
</span><span class="cx">                 FE68C6381B90DE0B0042BCB3 /* MacroAssemblerPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE68C6351B90DDD90042BCB3 /* MacroAssemblerPrinter.cpp */; };
</span><span class="cx">                 FE7BA60F1A1A7CEC00F1F7B4 /* HeapVerifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE7BA60D1A1A7CEC00F1F7B4 /* HeapVerifier.cpp */; };
</span><span class="cx">                 FE7BA6101A1A7CEC00F1F7B4 /* HeapVerifier.h in Headers */ = {isa = PBXBuildFile; fileRef = FE7BA60E1A1A7CEC00F1F7B4 /* HeapVerifier.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                FE7C41961B97FC4B00F4D598 /* PingPongStackOverflowTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEDA50D41B97F442009A3B4F /* PingPongStackOverflowTest.cpp */; };
</ins><span class="cx">                 FEA08620182B7A0400F6D851 /* Breakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861E182B7A0400F6D851 /* Breakpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 FEA08621182B7A0400F6D851 /* DebuggerPrimitives.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 FEB51F6C1A97B688001F921C /* Regress141809.mm in Sources */ = {isa = PBXBuildFile; fileRef = FEB51F6B1A97B688001F921C /* Regress141809.mm */; };
</span><span class="lines">@@ -3677,6 +3678,8 @@
</span><span class="cx">                 FED287B115EC9A5700DA8161 /* LLIntOpcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntOpcode.h; path = llint/LLIntOpcode.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Watchdog.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FED94F2C171E3E2300BE77A4 /* Watchdog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Watchdog.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                FEDA50D41B97F442009A3B4F /* PingPongStackOverflowTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PingPongStackOverflowTest.cpp; path = API/tests/PingPongStackOverflowTest.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                FEDA50D51B97F4D9009A3B4F /* PingPongStackOverflowTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PingPongStackOverflowTest.h; path = API/tests/PingPongStackOverflowTest.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 FEF040501AAE662D00BD28B0 /* CompareAndSwapTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompareAndSwapTest.cpp; path = API/tests/CompareAndSwapTest.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FEF040521AAEC4ED00BD28B0 /* CompareAndSwapTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CompareAndSwapTest.h; path = API/tests/CompareAndSwapTest.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FEF6835A174343CC00A32E25 /* JITStubsARM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubsARM.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4048,6 +4051,8 @@
</span><span class="cx">                                 FE0D4A081ABA2437002F54BF /* GlobalContextWithFinalizerTest.h */,
</span><span class="cx">                                 C2181FC018A948FB0025A235 /* JSExportTests.h */,
</span><span class="cx">                                 C2181FC118A948FB0025A235 /* JSExportTests.mm */,
</span><ins>+                                FEDA50D41B97F442009A3B4F /* PingPongStackOverflowTest.cpp */,
+                                FEDA50D51B97F4D9009A3B4F /* PingPongStackOverflowTest.h */,
</ins><span class="cx">                                 65570F581AA4C00A009B3C23 /* Regress141275.h */,
</span><span class="cx">                                 65570F591AA4C00A009B3C23 /* Regress141275.mm */,
</span><span class="cx">                                 FEB51F6A1A97B688001F921C /* Regress141809.h */,
</span><span class="lines">@@ -7344,6 +7349,7 @@
</span><span class="cx">                         isa = PBXSourcesBuildPhase;
</span><span class="cx">                         buildActionMask = 2147483647;
</span><span class="cx">                         files = (
</span><ins>+                                FE7C41961B97FC4B00F4D598 /* PingPongStackOverflowTest.cpp in Sources */,
</ins><span class="cx">                                 FE0D4A091ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp in Sources */,
</span><span class="cx">                                 65570F5A1AA4C3EA009B3C23 /* Regress141275.mm in Sources */,
</span><span class="cx">                                 C29ECB031804D0ED00D2CBB4 /* CurrentThisInsideBlockGetterTest.mm in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinterpreterCallFrameh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/interpreter/CallFrame.h (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/interpreter/CallFrame.h        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/interpreter/CallFrame.h        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -111,6 +111,7 @@
</span><span class="cx">         CallFrame&amp; operator=(const Register&amp; r) { *static_cast&lt;Register*&gt;(this) = r; return *this; }
</span><span class="cx"> 
</span><span class="cx">         CallFrame* callerFrame() const { return static_cast&lt;CallFrame*&gt;(callerFrameOrVMEntryFrame()); }
</span><ins>+        void* callerFrameOrVMEntryFrame() const { return callerFrameAndPC().callerFrame; }
</ins><span class="cx"> 
</span><span class="cx">         JS_EXPORT_PRIVATE CallFrame* callerFrame(VMEntryFrame*&amp;);
</span><span class="cx"> 
</span><span class="lines">@@ -275,8 +276,6 @@
</span><span class="cx">             return argIndex;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        void* callerFrameOrVMEntryFrame() const { return callerFrameAndPC().callerFrame; }
-
</del><span class="cx">         CallerFrameAndPC&amp; callerFrameAndPC() { return *reinterpret_cast&lt;CallerFrameAndPC*&gt;(this); }
</span><span class="cx">         const CallerFrameAndPC&amp; callerFrameAndPC() const { return *reinterpret_cast&lt;const CallerFrameAndPC*&gt;(this); }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinterpreterInterpretercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -631,9 +631,8 @@
</span><span class="cx"> 
</span><span class="cx"> class UnwindFunctor {
</span><span class="cx"> public:
</span><del>-    UnwindFunctor(VMEntryFrame*&amp; vmEntryFrame, CallFrame*&amp; callFrame, bool isTermination, CodeBlock*&amp; codeBlock, HandlerInfo*&amp; handler)
-        : m_vmEntryFrame(vmEntryFrame)
-        , m_callFrame(callFrame)
</del><ins>+    UnwindFunctor(CallFrame*&amp; callFrame, bool isTermination, CodeBlock*&amp; codeBlock, HandlerInfo*&amp; handler)
+        : m_callFrame(callFrame)
</ins><span class="cx">         , m_isTermination(isTermination)
</span><span class="cx">         , m_codeBlock(codeBlock)
</span><span class="cx">         , m_handler(handler)
</span><span class="lines">@@ -643,7 +642,6 @@
</span><span class="cx">     StackVisitor::Status operator()(StackVisitor&amp; visitor)
</span><span class="cx">     {
</span><span class="cx">         VM&amp; vm = m_callFrame-&gt;vm();
</span><del>-        m_vmEntryFrame = visitor-&gt;vmEntryFrame();
</del><span class="cx">         m_callFrame = visitor-&gt;callFrame();
</span><span class="cx">         m_codeBlock = visitor-&gt;codeBlock();
</span><span class="cx">         unsigned bytecodeOffset = visitor-&gt;bytecodeOffset();
</span><span class="lines">@@ -661,15 +659,22 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    VMEntryFrame*&amp; m_vmEntryFrame;
</del><span class="cx">     CallFrame*&amp; m_callFrame;
</span><span class="cx">     bool m_isTermination;
</span><span class="cx">     CodeBlock*&amp; m_codeBlock;
</span><span class="cx">     HandlerInfo*&amp; m_handler;
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-NEVER_INLINE HandlerInfo* Interpreter::unwind(VMEntryFrame*&amp; vmEntryFrame, CallFrame*&amp; callFrame, Exception* exception)
</del><ins>+NEVER_INLINE HandlerInfo* Interpreter::unwind(VM&amp; vm, CallFrame*&amp; callFrame, Exception* exception, UnwindStart unwindStart)
</ins><span class="cx"> {
</span><ins>+    if (unwindStart == UnwindFromCallerFrame) {
+        if (callFrame-&gt;callerFrameOrVMEntryFrame() == vm.topVMEntryFrame)
+            return nullptr;
+
+        callFrame = callFrame-&gt;callerFrame();
+        vm.topCallFrame = callFrame;
+    }
+
</ins><span class="cx">     CodeBlock* codeBlock = callFrame-&gt;codeBlock();
</span><span class="cx">     bool isTermination = false;
</span><span class="cx"> 
</span><span class="lines">@@ -684,13 +689,13 @@
</span><span class="cx">     if (exceptionValue.isObject())
</span><span class="cx">         isTermination = isTerminatedExecutionException(exception);
</span><span class="cx"> 
</span><del>-    ASSERT(callFrame-&gt;vm().exception() &amp;&amp; callFrame-&gt;vm().exception()-&gt;stack().size());
</del><ins>+    ASSERT(vm.exception() &amp;&amp; vm.exception()-&gt;stack().size());
</ins><span class="cx"> 
</span><span class="cx">     Debugger* debugger = callFrame-&gt;vmEntryGlobalObject()-&gt;debugger();
</span><span class="cx">     if (debugger &amp;&amp; debugger-&gt;needsExceptionCallbacks() &amp;&amp; !exception-&gt;didNotifyInspectorOfThrow()) {
</span><span class="cx">         // We need to clear the exception here in order to see if a new exception happens.
</span><span class="cx">         // Afterwards, the values are put back to continue processing this error.
</span><del>-        SuspendExceptionScope scope(&amp;callFrame-&gt;vm());
</del><ins>+        SuspendExceptionScope scope(&amp;vm);
</ins><span class="cx">         // This code assumes that if the debugger is enabled then there is no inlining.
</span><span class="cx">         // If that assumption turns out to be false then we'll ignore the inlined call
</span><span class="cx">         // frames.
</span><span class="lines">@@ -713,13 +718,11 @@
</span><span class="cx">     exception-&gt;setDidNotifyInspectorOfThrow();
</span><span class="cx"> 
</span><span class="cx">     // Calculate an exception handler vPC, unwinding call frames as necessary.
</span><del>-    HandlerInfo* handler = 0;
-    VM&amp; vm = callFrame-&gt;vm();
-    ASSERT(callFrame == vm.topCallFrame);
-    UnwindFunctor functor(vmEntryFrame, callFrame, isTermination, codeBlock, handler);
</del><ins>+    HandlerInfo* handler = nullptr;
+    UnwindFunctor functor(callFrame, isTermination, codeBlock, handler);
</ins><span class="cx">     callFrame-&gt;iterate(functor);
</span><span class="cx">     if (!handler)
</span><del>-        return 0;
</del><ins>+        return nullptr;
</ins><span class="cx"> 
</span><span class="cx">     if (LegacyProfiler* profiler = vm.enabledProfiler())
</span><span class="cx">         profiler-&gt;exceptionUnwind(callFrame);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinterpreterInterpreterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/interpreter/Interpreter.h (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/interpreter/Interpreter.h        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/interpreter/Interpreter.h        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -67,6 +67,8 @@
</span><span class="cx">     struct Instruction;
</span><span class="cx">     struct ProtoCallFrame;
</span><span class="cx"> 
</span><ins>+    enum UnwindStart { UnwindFromCurrentFrame, UnwindFromCallerFrame };
+
</ins><span class="cx">     enum DebugHookID {
</span><span class="cx">         WillExecuteProgram,
</span><span class="cx">         DidExecuteProgram,
</span><span class="lines">@@ -145,6 +147,7 @@
</span><span class="cx">         {
</span><span class="cx">             ASSERT(vm);
</span><span class="cx">             ASSERT(callFrame);
</span><ins>+            ASSERT(callFrame &lt; vm-&gt;topVMEntryFrame);
</ins><span class="cx">             vm-&gt;topCallFrame = callFrame;
</span><span class="cx">         }
</span><span class="cx">     };
</span><span class="lines">@@ -222,7 +225,7 @@
</span><span class="cx">         
</span><span class="cx">         SamplingTool* sampler() { return m_sampler.get(); }
</span><span class="cx"> 
</span><del>-        NEVER_INLINE HandlerInfo* unwind(VMEntryFrame*&amp;, CallFrame*&amp;, Exception*);
</del><ins>+        NEVER_INLINE HandlerInfo* unwind(VM&amp;, CallFrame*&amp;, Exception*, UnwindStart);
</ins><span class="cx">         NEVER_INLINE void debug(CallFrame*, DebugHookID);
</span><span class="cx">         JSString* stackTraceAsString(ExecState*, Vector&lt;StackFrame&gt;);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCCallHelpersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CCallHelpers.h (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CCallHelpers.h        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/jit/CCallHelpers.h        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -2078,7 +2078,6 @@
</span><span class="cx">     void jumpToExceptionHandler()
</span><span class="cx">     {
</span><span class="cx">         // genericUnwind() leaves the handler CallFrame* in vm-&gt;callFrameForThrow,
</span><del>-        // the topVMEntryFrame for the handler in vm-&gt;vmEntryFrameForThrow,
</del><span class="cx">         // and the address of the handler in vm-&gt;targetMachinePCForThrow.
</span><span class="cx">         loadPtr(&amp;vm()-&gt;targetMachinePCForThrow, GPRInfo::regT1);
</span><span class="cx">         jump(GPRInfo::regT1);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITExceptionscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITExceptions.cpp (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITExceptions.cpp        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/jit/JITExceptions.cpp        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -40,7 +40,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-void genericUnwind(VM* vm, ExecState* callFrame)
</del><ins>+void genericUnwind(VM* vm, ExecState* callFrame, UnwindStart unwindStart)
</ins><span class="cx"> {
</span><span class="cx">     if (Options::breakOnThrow()) {
</span><span class="cx">         dataLog(&quot;In call frame &quot;, RawPointer(callFrame), &quot; for code block &quot;, *callFrame-&gt;codeBlock(), &quot;\n&quot;);
</span><span class="lines">@@ -49,8 +49,7 @@
</span><span class="cx">     
</span><span class="cx">     Exception* exception = vm-&gt;exception();
</span><span class="cx">     RELEASE_ASSERT(exception);
</span><del>-    VMEntryFrame* vmEntryFrame = vm-&gt;topVMEntryFrame;
-    HandlerInfo* handler = vm-&gt;interpreter-&gt;unwind(vmEntryFrame, callFrame, exception); // This may update vmEntryFrame and callFrame.
</del><ins>+    HandlerInfo* handler = vm-&gt;interpreter-&gt;unwind(*vm, callFrame, exception, unwindStart); // This may update callFrame.
</ins><span class="cx"> 
</span><span class="cx">     void* catchRoutine;
</span><span class="cx">     Instruction* catchPCForInterpreter = 0;
</span><span class="lines">@@ -64,7 +63,6 @@
</span><span class="cx">     } else
</span><span class="cx">         catchRoutine = LLInt::getCodePtr(handleUncaughtException);
</span><span class="cx">     
</span><del>-    vm-&gt;vmEntryFrameForThrow = vmEntryFrame;
</del><span class="cx">     vm-&gt;callFrameForThrow = callFrame;
</span><span class="cx">     vm-&gt;targetMachinePCForThrow = catchRoutine;
</span><span class="cx">     vm-&gt;targetInterpreterPCForThrow = catchPCForInterpreter;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITExceptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITExceptions.h (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITExceptions.h        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/jit/JITExceptions.h        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #ifndef JITExceptions_h
</span><span class="cx"> #define JITExceptions_h
</span><span class="cx"> 
</span><ins>+#include &quot;Interpreter.h&quot;
</ins><span class="cx"> #include &quot;JSCJSValue.h&quot;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -33,7 +34,7 @@
</span><span class="cx"> class ExecState;
</span><span class="cx"> class VM;
</span><span class="cx"> 
</span><del>-void genericUnwind(VM*, ExecState*);
</del><ins>+void genericUnwind(VM*, ExecState*, UnwindStart = UnwindFromCurrentFrame);
</ins><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -501,8 +501,6 @@
</span><span class="cx">     
</span><span class="cx">     move(TrustedImmPtr(m_vm), regT3);
</span><span class="cx">     load64(Address(regT3, VM::callFrameForThrowOffset()), callFrameRegister);
</span><del>-    load64(Address(regT3, VM::vmEntryFrameForThrowOffset()), regT0);
-    store64(regT0, Address(regT3, VM::topVMEntryFrameOffset()));
</del><span class="cx"> 
</span><span class="cx">     addPtr(TrustedImm32(stackPointerOffsetFor(codeBlock()) * sizeof(Register)), callFrameRegister, stackPointerRegister);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodes32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -803,8 +803,6 @@
</span><span class="cx">     move(TrustedImmPtr(m_vm), regT3);
</span><span class="cx">     // operationThrow returns the callFrame for the handler.
</span><span class="cx">     load32(Address(regT3, VM::callFrameForThrowOffset()), callFrameRegister);
</span><del>-    load32(Address(regT3, VM::vmEntryFrameForThrowOffset()), regT0);
-    store32(regT0, Address(regT3, VM::topVMEntryFrameOffset()));
</del><span class="cx"> 
</span><span class="cx">     addPtr(TrustedImm32(stackPointerOffsetFor(codeBlock()) * sizeof(Register)), callFrameRegister, stackPointerRegister);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOperations.cpp (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOperations.cpp        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/jit/JITOperations.cpp        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -91,8 +91,7 @@
</span><span class="cx">         callerFrame = exec;
</span><span class="cx"> 
</span><span class="cx">     NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame);
</span><del>-    ErrorHandlingScope errorScope(*vm);
-    vm-&gt;throwException(callerFrame, createStackOverflowError(callerFrame));
</del><ins>+    throwStackOverflowError(callerFrame);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(WEBASSEMBLY)
</span><span class="lines">@@ -111,13 +110,12 @@
</span><span class="cx"> int32_t JIT_OPERATION operationCallArityCheck(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     VM* vm = &amp;exec-&gt;vm();
</span><del>-    VMEntryFrame* vmEntryFrame = vm-&gt;topVMEntryFrame;
-    CallFrame* callerFrame = exec-&gt;callerFrame(vmEntryFrame);
-
</del><span class="cx">     JSStack&amp; stack = vm-&gt;interpreter-&gt;stack();
</span><span class="cx"> 
</span><span class="cx">     int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &amp;stack, CodeForCall);
</span><span class="cx">     if (missingArgCount &lt; 0) {
</span><ins>+        VMEntryFrame* vmEntryFrame = vm-&gt;topVMEntryFrame;
+        CallFrame* callerFrame = exec-&gt;callerFrame(vmEntryFrame);
</ins><span class="cx">         NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame);
</span><span class="cx">         throwStackOverflowError(callerFrame);
</span><span class="cx">     }
</span><span class="lines">@@ -128,13 +126,12 @@
</span><span class="cx"> int32_t JIT_OPERATION operationConstructArityCheck(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     VM* vm = &amp;exec-&gt;vm();
</span><del>-    VMEntryFrame* vmEntryFrame = vm-&gt;topVMEntryFrame;
-    CallFrame* callerFrame = exec-&gt;callerFrame(vmEntryFrame);
-
</del><span class="cx">     JSStack&amp; stack = vm-&gt;interpreter-&gt;stack();
</span><span class="cx"> 
</span><span class="cx">     int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &amp;stack, CodeForConstruct);
</span><span class="cx">     if (missingArgCount &lt; 0) {
</span><ins>+        VMEntryFrame* vmEntryFrame = vm-&gt;topVMEntryFrame;
+        CallFrame* callerFrame = exec-&gt;callerFrame(vmEntryFrame);
</ins><span class="cx">         NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame);
</span><span class="cx">         throwStackOverflowError(callerFrame);
</span><span class="cx">     }
</span><span class="lines">@@ -2036,7 +2033,7 @@
</span><span class="cx">     JSValue exceptionValue = JSValue::decode(encodedExceptionValue);
</span><span class="cx">     vm-&gt;throwException(exec, exceptionValue);
</span><span class="cx"> 
</span><del>-    // Results stored out-of-band in vm.targetMachinePCForThrow, vm.callFrameForThrow &amp; vm.vmEntryFrameForThrow
</del><ins>+    // Results stored out-of-band in vm.targetMachinePCForThrow &amp; vm.callFrameForThrow
</ins><span class="cx">     genericUnwind(vm, exec);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -2082,12 +2079,8 @@
</span><span class="cx"> 
</span><span class="cx"> void JIT_OPERATION lookupExceptionHandlerFromCallerFrame(VM* vm, ExecState* exec)
</span><span class="cx"> {
</span><del>-    VMEntryFrame* vmEntryFrame = vm-&gt;topVMEntryFrame;
-    CallFrame* callerFrame = exec-&gt;callerFrame(vmEntryFrame);
-    ASSERT(callerFrame);
-
-    NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame);
-    genericUnwind(vm, callerFrame);
</del><ins>+    NativeCallFrameTracer tracer(vm, exec);
+    genericUnwind(vm, exec, UnwindFromCallerFrame);
</ins><span class="cx">     ASSERT(vm-&gt;targetMachinePCForThrow);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -1879,8 +1879,6 @@
</span><span class="cx">     andp MarkedBlockMask, t3
</span><span class="cx">     loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
</span><span class="cx">     loadp VM::callFrameForThrow[t3], cfr
</span><del>-    loadp VM::vmEntryFrameForThrow[t3], t0
-    storep t0, VM::topVMEntryFrame[t3]
</del><span class="cx">     restoreStackPointerAfterCall()
</span><span class="cx"> 
</span><span class="cx">     loadi VM::targetInterpreterPCForThrow[t3], PC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -1775,8 +1775,6 @@
</span><span class="cx">     andp MarkedBlockMask, t3
</span><span class="cx">     loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
</span><span class="cx">     loadp VM::callFrameForThrow[t3], cfr
</span><del>-    loadp VM::vmEntryFrameForThrow[t3], t0
-    storep t0, VM::topVMEntryFrame[t3]
</del><span class="cx">     restoreStackPointerAfterCall()
</span><span class="cx"> 
</span><span class="cx">     loadp CodeBlock[cfr], PB
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeVMh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/VM.h (189453 => 189454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/VM.h        2015-09-07 03:10:31 UTC (rev 189453)
+++ trunk/Source/JavaScriptCore/runtime/VM.h        2015-09-07 05:19:28 UTC (rev 189454)
</span><span class="lines">@@ -377,16 +377,6 @@
</span><span class="cx">         return OBJECT_OFFSETOF(VM, m_exception);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    static ptrdiff_t vmEntryFrameForThrowOffset()
-    {
-        return OBJECT_OFFSETOF(VM, vmEntryFrameForThrow);
-    }
-
-    static ptrdiff_t topVMEntryFrameOffset()
-    {
-        return OBJECT_OFFSETOF(VM, topVMEntryFrame);
-    }
-
</del><span class="cx">     static ptrdiff_t callFrameForThrowOffset()
</span><span class="cx">     {
</span><span class="cx">         return OBJECT_OFFSETOF(VM, callFrameForThrow);
</span><span class="lines">@@ -451,7 +441,6 @@
</span><span class="cx">     JSValue hostCallReturnValue;
</span><span class="cx">     unsigned varargsLength;
</span><span class="cx">     ExecState* newCallFrameReturnValue;
</span><del>-    VMEntryFrame* vmEntryFrameForThrow;
</del><span class="cx">     ExecState* callFrameForThrow;
</span><span class="cx">     void* targetMachinePCForThrow;
</span><span class="cx">     Instruction* targetInterpreterPCForThrow;
</span></span></pre>
</div>
</div>

</body>
</html>