<!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>[225411] trunk</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/225411">225411</a></dd>
<dt>Author</dt> <dd>jfbastien@apple.com</dd>
<dt>Date</dt> <dd>2017-12-01 13:58:36 -0800 (Fri, 01 Dec 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>WebAssembly: restore cached stack limit after out-call
https://bugs.webkit.org/show_bug.cgi?id=179106
<rdar://problem/35337525>

Reviewed by Saam Barati.

JSTests:

* wasm/function-tests/double-instance.js: Added.
(const.imp.boom):
(const.imp.get callAnother):

Source/JavaScriptCore:

We cache the stack limit on the Instance so that we can do fast
stack checks where required. In regular usage the stack limit
never changes because we always run on the same thread, but in
rare cases an API user can totally migrate which thread (and
therefore stack) is used for execution between WebAssembly
traces. For that reason we set the cached stack limit to
UINTPTR_MAX on the outgoing Instance when transitioning back into
a different Instance. We usually restore the cached stack limit in
Context::store, but this wasn't called on all code paths. We had a
bug where an Instance calling into itself indirectly would
therefore fail to restore its cached stack limit properly.

This patch therefore restores the cached stack limit after direct
calls which could be to imports (both wasm->wasm and
wasm->embedder). We have to do all of them because we have no way
of knowing what imports will do (they're known at instantiation
time, not compilation time, and different instances can have
different imports). To make this efficient we also add a pointer
to the canonical location of the stack limit (i.e. the extra
indirection we're trying to save by caching the stack limit on the
Instance in the first place). This is potentially a small perf hit
on imported direct calls.

It's hard to say what the performance cost will be because we
haven't seen much code in the wild which does this. We're adding
two dependent loads and a store of the loaded value, which is
unlikely to get used soon after. It's more code, but on an
out-of-order processor it doesn't contribute to the critical path.

* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::restoreWebAssemblyGlobalState):
(JSC::Wasm::B3IRGenerator::addGrowMemory):
(JSC::Wasm::B3IRGenerator::addCall):
(JSC::Wasm::B3IRGenerator::addCallIndirect):
* wasm/WasmInstance.cpp:
(JSC::Wasm::Instance::Instance):
(JSC::Wasm::Instance::create):
* wasm/WasmInstance.h:
(JSC::Wasm::Instance::offsetOfPointerToActualStackLimit):
(JSC::Wasm::Instance::cachedStackLimit const):
(JSC::Wasm::Instance::setCachedStackLimit):
* wasm/js/JSWebAssemblyInstance.cpp:
(JSC::JSWebAssemblyInstance::create):
* wasm/js/WebAssemblyFunction.cpp:
(JSC::callWebAssemblyFunction):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmB3IRGeneratorcpp">trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmInstancecpp">trunk/Source/JavaScriptCore/wasm/WasmInstance.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmInstanceh">trunk/Source/JavaScriptCore/wasm/WasmInstance.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmThunkscpp">trunk/Source/JavaScriptCore/wasm/WasmThunks.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsJSWebAssemblyInstancecpp">trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyFunctioncpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestswasmfunctiontestsdoubleinstancejs">trunk/JSTests/wasm/function-tests/double-instance.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (225410 => 225411)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog  2017-12-01 21:58:10 UTC (rev 225410)
+++ trunk/JSTests/ChangeLog     2017-12-01 21:58:36 UTC (rev 225411)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2017-12-01  JF Bastien  <jfbastien@apple.com>
+
+        WebAssembly: restore cached stack limit after out-call
+        https://bugs.webkit.org/show_bug.cgi?id=179106
+        <rdar://problem/35337525>
+
+        Reviewed by Saam Barati.
+
+        * wasm/function-tests/double-instance.js: Added.
+        (const.imp.boom):
+        (const.imp.get callAnother):
+
</ins><span class="cx"> 2017-11-30  JF Bastien  <jfbastien@apple.com>
</span><span class="cx"> 
</span><span class="cx">         WebAssembly: improve stack trace
</span></span></pre></div>
<a id="trunkJSTestswasmfunctiontestsdoubleinstancejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/wasm/function-tests/double-instance.js (0 => 225411)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/function-tests/double-instance.js                             (rev 0)
+++ trunk/JSTests/wasm/function-tests/double-instance.js        2017-12-01 21:58:36 UTC (rev 225411)
</span><span class="lines">@@ -0,0 +1,64 @@
</span><ins>+import Builder from '../Builder.js'
+import * as assert from '../assert.js'
+
+// The call sequence is as follows:
+//
+// js -js2wasm-> i1.callAnother()
+//               -wasm2wasm-> i0.callAnother()
+//                            -wasm2js-> i1.boom()
+//                                       -calldirect-> i1.doStackCheck()
+//                                                     -calldirect-> dummy()
+//               -calldirect-> i1.doStackCheck()
+//                             -calldirect-> dummy()
+//
+// We therefore have i1 indirectly calling into itself, through another
+// instance. When returning its cached stack limit should still be valid, but
+// our implementation used to set it to UINTPTR_MAX causing an erroneous stack
+// check failure at the second doStackCheck() call.
+
+const builder = new Builder()
+    .Type()
+    .End()
+    .Import()
+        .Function("imp", "boom", {params:["i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32"], ret:"i32"})
+        .Function("imp", "callAnother", {params:["i32"], ret:"i32"})
+    .End()
+    .Function().End()
+    .Export()
+        .Function("boom")
+        .Function("callAnother")
+    .End()
+    .Code()
+        .Function("boom", {params:["i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32"], ret:"i32"})
+            /* call doStackCheck */.GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).Call(4)
+            .Return()
+        .End()
+        .Function("callAnother", {params:["i32"], ret:"i32"})
+            /* call imp:callAnother */.GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).Call(1)
+            /* call doStackCheck */.GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).Call(4)
+            .Return()
+        .End()
+        .Function("doStackCheck", {params:["i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32"], ret:"i32"})
+            /* call dummy */.GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).GetLocal(0).Call(5)
+            .Return()
+        .End()
+        .Function("dummy", {params:["i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32"], ret:"i32"})
+            .GetLocal(0)
+            .Return()
+        .End()
+    .End();
+
+const bin = builder.WebAssembly().get();
+const module = new WebAssembly.Module(bin);
+
+let i1;
+
+const imp = {
+    boom: () => { throw new Error(`This boom should not get called!`); },
+    callAnother: () => { i1.exports["boom"](0xdeadbeef); },
+}
+
+const i0 = new WebAssembly.Instance(module, { imp });
+i1 = new WebAssembly.Instance(module, { imp: i0.exports });
+
+i1.exports["callAnother"](0xc0defefe);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (225410 => 225411)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2017-12-01 21:58:10 UTC (rev 225410)
+++ trunk/Source/JavaScriptCore/ChangeLog       2017-12-01 21:58:36 UTC (rev 225411)
</span><span class="lines">@@ -1,3 +1,57 @@
</span><ins>+2017-12-01  JF Bastien  <jfbastien@apple.com>
+
+        WebAssembly: restore cached stack limit after out-call
+        https://bugs.webkit.org/show_bug.cgi?id=179106
+        <rdar://problem/35337525>
+
+        Reviewed by Saam Barati.
+
+        We cache the stack limit on the Instance so that we can do fast
+        stack checks where required. In regular usage the stack limit
+        never changes because we always run on the same thread, but in
+        rare cases an API user can totally migrate which thread (and
+        therefore stack) is used for execution between WebAssembly
+        traces. For that reason we set the cached stack limit to
+        UINTPTR_MAX on the outgoing Instance when transitioning back into
+        a different Instance. We usually restore the cached stack limit in
+        Context::store, but this wasn't called on all code paths. We had a
+        bug where an Instance calling into itself indirectly would
+        therefore fail to restore its cached stack limit properly.
+
+        This patch therefore restores the cached stack limit after direct
+        calls which could be to imports (both wasm->wasm and
+        wasm->embedder). We have to do all of them because we have no way
+        of knowing what imports will do (they're known at instantiation
+        time, not compilation time, and different instances can have
+        different imports). To make this efficient we also add a pointer
+        to the canonical location of the stack limit (i.e. the extra
+        indirection we're trying to save by caching the stack limit on the
+        Instance in the first place). This is potentially a small perf hit
+        on imported direct calls.
+
+        It's hard to say what the performance cost will be because we
+        haven't seen much code in the wild which does this. We're adding
+        two dependent loads and a store of the loaded value, which is
+        unlikely to get used soon after. It's more code, but on an
+        out-of-order processor it doesn't contribute to the critical path.
+
+        * wasm/WasmB3IRGenerator.cpp:
+        (JSC::Wasm::B3IRGenerator::restoreWebAssemblyGlobalState):
+        (JSC::Wasm::B3IRGenerator::addGrowMemory):
+        (JSC::Wasm::B3IRGenerator::addCall):
+        (JSC::Wasm::B3IRGenerator::addCallIndirect):
+        * wasm/WasmInstance.cpp:
+        (JSC::Wasm::Instance::Instance):
+        (JSC::Wasm::Instance::create):
+        * wasm/WasmInstance.h:
+        (JSC::Wasm::Instance::offsetOfPointerToActualStackLimit):
+        (JSC::Wasm::Instance::cachedStackLimit const):
+        (JSC::Wasm::Instance::setCachedStackLimit):
+        * wasm/js/JSWebAssemblyInstance.cpp:
+        (JSC::JSWebAssemblyInstance::create):
+        * wasm/js/WebAssemblyFunction.cpp:
+        (JSC::callWebAssemblyFunction):
+
</ins><span class="cx"> 2017-11-30  Yusuke Suzuki  <utatane.tea@gmail.com>
</span><span class="cx"> 
</span><span class="cx">         [JSC] Use JSFixedArray for op_new_array_buffer
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmB3IRGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp (225410 => 225411)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp   2017-12-01 21:58:10 UTC (rev 225410)
+++ trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp      2017-12-01 21:58:36 UTC (rev 225411)
</span><span class="lines">@@ -246,7 +246,8 @@
</span><span class="cx">     int32_t WARN_UNUSED_RETURN fixupPointerPlusOffset(ExpressionType&, uint32_t);
</span><span class="cx"> 
</span><span class="cx">     void restoreWasmContextInstance(Procedure&, BasicBlock*, Value*);
</span><del>-    void restoreWebAssemblyGlobalState(const MemoryInformation&, Value* instance, Procedure&, BasicBlock*);
</del><ins>+    enum class RestoreCachedStackLimit { No, Yes };
+    void restoreWebAssemblyGlobalState(RestoreCachedStackLimit, const MemoryInformation&, Value* instance, Procedure&, BasicBlock*);
</ins><span class="cx"> 
</span><span class="cx">     Origin origin();
</span><span class="cx"> 
</span><span class="lines">@@ -450,10 +451,17 @@
</span><span class="cx">     emitTierUpCheck(TierUpCount::functionEntryDecrement(), Origin());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void B3IRGenerator::restoreWebAssemblyGlobalState(const MemoryInformation& memory, Value* instance, Procedure& proc, BasicBlock* block)
</del><ins>+void B3IRGenerator::restoreWebAssemblyGlobalState(RestoreCachedStackLimit restoreCachedStackLimit, const MemoryInformation& memory, Value* instance, Procedure& proc, BasicBlock* block)
</ins><span class="cx"> {
</span><span class="cx">     restoreWasmContextInstance(proc, block, instance);
</span><span class="cx"> 
</span><ins>+    if (restoreCachedStackLimit == RestoreCachedStackLimit::Yes) {
+        // The Instance caches the stack limit, but also knows where its canonical location is.
+        Value* pointerToActualStackLimit = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), instanceValue(), safeCast<int32_t>(Instance::offsetOfPointerToActualStackLimit()));
+        Value* actualStackLimit = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), pointerToActualStackLimit);
+        m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin(), actualStackLimit, instanceValue(), safeCast<int32_t>(Instance::offsetOfCachedStackLimit()));
+    }
+
</ins><span class="cx">     if (!!memory) {
</span><span class="cx">         const PinnedRegisterInfo* pinnedRegs = &PinnedRegisterInfo::get();
</span><span class="cx">         RegisterSet clobbers;
</span><span class="lines">@@ -583,7 +591,7 @@
</span><span class="cx">         m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), bitwise_cast<void*>(growMemory)),
</span><span class="cx">         m_currentBlock->appendNew<B3::Value>(m_proc, B3::FramePointer, origin()), instanceValue(), delta);
</span><span class="cx"> 
</span><del>-    restoreWebAssemblyGlobalState(m_info.memory, instanceValue(), m_proc, m_currentBlock);
</del><ins>+    restoreWebAssemblyGlobalState(RestoreCachedStackLimit::No, m_info.memory, instanceValue(), m_proc, m_currentBlock);
</ins><span class="cx"> 
</span><span class="cx">     return { };
</span><span class="cx"> }
</span><span class="lines">@@ -1149,7 +1157,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // The call could have been to another WebAssembly instance, and / or could have modified our Memory.
</span><del>-        restoreWebAssemblyGlobalState(m_info.memory, instanceValue(), m_proc, continuation);
</del><ins>+        restoreWebAssemblyGlobalState(RestoreCachedStackLimit::Yes, m_info.memory, instanceValue(), m_proc, continuation);
</ins><span class="cx">     } else {
</span><span class="cx">         result = wasmCallingConvention().setupCall(m_proc, m_currentBlock, origin(), args, toB3Type(returnType),
</span><span class="cx">             [=] (PatchpointValue* patchpoint) {
</span><span class="lines">@@ -1308,7 +1316,7 @@
</span><span class="cx">         });
</span><span class="cx"> 
</span><span class="cx">     // The call could have been to another WebAssembly instance, and / or could have modified our Memory.
</span><del>-    restoreWebAssemblyGlobalState(m_info.memory, instanceValue(), m_proc, m_currentBlock);
</del><ins>+    restoreWebAssemblyGlobalState(RestoreCachedStackLimit::Yes, m_info.memory, instanceValue(), m_proc, m_currentBlock);
</ins><span class="cx"> 
</span><span class="cx">     return { };
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmInstancecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmInstance.cpp (225410 => 225411)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmInstance.cpp        2017-12-01 21:58:10 UTC (rev 225410)
+++ trunk/Source/JavaScriptCore/wasm/WasmInstance.cpp   2017-12-01 21:58:36 UTC (rev 225411)
</span><span class="lines">@@ -41,11 +41,12 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Instance::Instance(Context* context, Ref<Module>&& module, EntryFrame** topEntryFramePointer, StoreTopCallFrameCallback&& storeTopCallFrame)
</del><ins>+Instance::Instance(Context* context, Ref<Module>&& module, EntryFrame** pointerToTopEntryFrame, void** pointerToActualStackLimit, StoreTopCallFrameCallback&& storeTopCallFrame)
</ins><span class="cx">     : m_context(context)
</span><span class="cx">     , m_module(WTFMove(module))
</span><span class="cx">     , m_globals(MallocPtr<uint64_t>::malloc(globalMemoryByteSize(m_module.get())))
</span><del>-    , m_topEntryFramePointer(topEntryFramePointer)
</del><ins>+    , m_pointerToTopEntryFrame(pointerToTopEntryFrame)
+    , m_pointerToActualStackLimit(pointerToActualStackLimit)
</ins><span class="cx">     , m_storeTopCallFrame(WTFMove(storeTopCallFrame))
</span><span class="cx">     , m_numImportFunctions(m_module->moduleInformation().importFunctionCount())
</span><span class="cx"> {
</span><span class="lines">@@ -53,9 +54,9 @@
</span><span class="cx">         new (importFunctionInfo(i)) ImportFunctionInfo();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Ref<Instance> Instance::create(Context* context, Ref<Module>&& module, EntryFrame** topEntryFramePointer, StoreTopCallFrameCallback&& storeTopCallFrame)
</del><ins>+Ref<Instance> Instance::create(Context* context, Ref<Module>&& module, EntryFrame** pointerToTopEntryFrame, void** pointerToActualStackLimit, StoreTopCallFrameCallback&& storeTopCallFrame)
</ins><span class="cx"> {
</span><del>-    return adoptRef(*new (NotNull, fastMalloc(allocationSize(module->moduleInformation().importFunctionCount()))) Instance(context, WTFMove(module), topEntryFramePointer, WTFMove(storeTopCallFrame)));
</del><ins>+    return adoptRef(*new (NotNull, fastMalloc(allocationSize(module->moduleInformation().importFunctionCount()))) Instance(context, WTFMove(module), pointerToTopEntryFrame, pointerToActualStackLimit, WTFMove(storeTopCallFrame)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Instance::~Instance() { }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmInstanceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmInstance.h (225410 => 225411)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmInstance.h  2017-12-01 21:58:10 UTC (rev 225410)
+++ trunk/Source/JavaScriptCore/wasm/WasmInstance.h     2017-12-01 21:58:36 UTC (rev 225411)
</span><span class="lines">@@ -44,7 +44,7 @@
</span><span class="cx"> public:
</span><span class="cx">     using StoreTopCallFrameCallback = WTF::Function<void(void*)>;
</span><span class="cx"> 
</span><del>-    static Ref<Instance> create(Context*, Ref<Module>&&, EntryFrame** topEntryFramePointer, StoreTopCallFrameCallback&&);
</del><ins>+    static Ref<Instance> create(Context*, Ref<Module>&&, EntryFrame** pointerToTopEntryFrame, void** pointerToActualStackLimit, StoreTopCallFrameCallback&&);
</ins><span class="cx"> 
</span><span class="cx">     void finalizeCreation(void* owner, Ref<CodeBlock>&& codeBlock)
</span><span class="cx">     {
</span><span class="lines">@@ -78,11 +78,20 @@
</span><span class="cx">     static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(Instance, m_memory); }
</span><span class="cx">     static ptrdiff_t offsetOfGlobals() { return OBJECT_OFFSETOF(Instance, m_globals); }
</span><span class="cx">     static ptrdiff_t offsetOfTable() { return OBJECT_OFFSETOF(Instance, m_table); }
</span><del>-    static ptrdiff_t offsetOfTopEntryFramePointer() { return OBJECT_OFFSETOF(Instance, m_topEntryFramePointer); }
</del><ins>+    static ptrdiff_t offsetOfPointerToTopEntryFrame() { return OBJECT_OFFSETOF(Instance, m_pointerToTopEntryFrame); }
</ins><span class="cx"> 
</span><ins>+    static ptrdiff_t offsetOfPointerToActualStackLimit() { return OBJECT_OFFSETOF(Instance, m_pointerToActualStackLimit); }
</ins><span class="cx">     static ptrdiff_t offsetOfCachedStackLimit() { return OBJECT_OFFSETOF(Instance, m_cachedStackLimit); }
</span><del>-    void* cachedStackLimit() const { return m_cachedStackLimit; }
-    void setCachedStackLimit(void* limit) { m_cachedStackLimit = limit; }
</del><ins>+    void* cachedStackLimit() const
+    {
+        ASSERT(*m_pointerToActualStackLimit == m_cachedStackLimit);
+        return m_cachedStackLimit;
+    }
+    void setCachedStackLimit(void* limit)
+    {
+        ASSERT(*m_pointerToActualStackLimit == limit || bitwise_cast<void*>(std::numeric_limits<uintptr_t>::max()) == limit);
+        m_cachedStackLimit = limit;
+    }
</ins><span class="cx"> 
</span><span class="cx">     // Tail accessors.
</span><span class="cx">     static size_t offsetOfTail() { return WTF::roundUpToMultipleOf<sizeof(uint64_t)>(sizeof(Instance)); }
</span><span class="lines">@@ -111,7 +120,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    Instance(Context*, Ref<Module>&&, EntryFrame**, StoreTopCallFrameCallback&&);
</del><ins>+    Instance(Context*, Ref<Module>&&, EntryFrame**, void**, StoreTopCallFrameCallback&&);
</ins><span class="cx">     
</span><span class="cx">     static size_t allocationSize(Checked<size_t> numImportFunctions)
</span><span class="cx">     {
</span><span class="lines">@@ -125,7 +134,8 @@
</span><span class="cx">     RefPtr<Memory> m_memory;
</span><span class="cx">     RefPtr<Table> m_table;
</span><span class="cx">     MallocPtr<uint64_t> m_globals;
</span><del>-    EntryFrame** m_topEntryFramePointer { nullptr };
</del><ins>+    EntryFrame** m_pointerToTopEntryFrame { nullptr };
+    void** m_pointerToActualStackLimit { nullptr };
</ins><span class="cx">     void* m_cachedStackLimit { bitwise_cast<void*>(std::numeric_limits<uintptr_t>::max()) };
</span><span class="cx">     StoreTopCallFrameCallback m_storeTopCallFrame;
</span><span class="cx">     unsigned m_numImportFunctions { 0 };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmThunkscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmThunks.cpp (225410 => 225411)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmThunks.cpp  2017-12-01 21:58:10 UTC (rev 225410)
+++ trunk/Source/JavaScriptCore/wasm/WasmThunks.cpp     2017-12-01 21:58:36 UTC (rev 225411)
</span><span class="lines">@@ -47,7 +47,7 @@
</span><span class="cx">     // The thing that jumps here must move ExceptionType into the argumentGPR1 before jumping here.
</span><span class="cx">     // We're allowed to use temp registers here. We are not allowed to use callee saves.
</span><span class="cx">     jit.loadWasmContextInstance(GPRInfo::argumentGPR2);
</span><del>-    jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR2, Instance::offsetOfTopEntryFramePointer()), GPRInfo::argumentGPR0);
</del><ins>+    jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR2, Instance::offsetOfPointerToTopEntryFrame()), GPRInfo::argumentGPR0);
</ins><span class="cx">     jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR0), GPRInfo::argumentGPR0);
</span><span class="cx">     jit.copyCalleeSavesToEntryFrameCalleeSavesBuffer(GPRInfo::argumentGPR0);
</span><span class="cx">     jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsJSWebAssemblyInstancecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp (225410 => 225411)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp    2017-12-01 21:58:10 UTC (rev 225410)
+++ trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp       2017-12-01 21:58:36 UTC (rev 225411)
</span><span class="lines">@@ -170,7 +170,7 @@
</span><span class="cx"> 
</span><span class="cx">     // FIXME: These objects could be pretty big we should try to throw OOM here.
</span><span class="cx">     auto* jsInstance = new (NotNull, allocateCell<JSWebAssemblyInstance>(vm.heap)) JSWebAssemblyInstance(vm, instanceStructure, 
</span><del>-        Wasm::Instance::create(&vm.wasmContext, WTFMove(module), &vm.topEntryFrame, WTFMove(storeTopCallFrame)));
</del><ins>+        Wasm::Instance::create(&vm.wasmContext, WTFMove(module), &vm.topEntryFrame, vm.addressOfSoftStackLimit(), WTFMove(storeTopCallFrame)));
</ins><span class="cx">     jsInstance->finishCreation(vm, jsModule, moduleNamespace);
</span><span class="cx">     RETURN_IF_EXCEPTION(throwScope, nullptr);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyFunctioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp (225410 => 225411)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp      2017-12-01 21:58:10 UTC (rev 225410)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp 2017-12-01 21:58:36 UTC (rev 225411)
</span><span class="lines">@@ -150,7 +150,9 @@
</span><span class="cx">         // This is just for some extra safety instead of leaving a cached
</span><span class="cx">         // value in there. If we ever forget to set the value to be a real
</span><span class="cx">         // bounds, this will force every stack overflow check to immediately
</span><del>-        // fire.
</del><ins>+        // fire. The stack limit never changes while executing except when
+        // WebAssembly is used through the JSC API: API users can ask the code
+        // to migrate threads.
</ins><span class="cx">         wasmInstance->setCachedStackLimit(bitwise_cast<void*>(std::numeric_limits<uintptr_t>::max()));
</span><span class="cx">     }
</span><span class="cx">     vm.wasmContext.store(prevWasmInstance, vm.softStackLimit());
</span></span></pre>
</div>
</div>

</body>
</html>