<!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>[218868] 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/218868">218868</a></dd>
<dt>Author</dt> <dd>jfbastien@apple.com</dd>
<dt>Date</dt> <dd>2017-06-27 23:42:13 -0700 (Tue, 27 Jun 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>WebAssembly: running out of executable memory should throw OoM
https://bugs.webkit.org/show_bug.cgi?id=171537
<rdar://problem/32963338>

Reviewed by Saam Barati.

JSTests:

* wasm.yaml:
* wasm/lowExecutableMemory/executable-memory-oom.js: Added.
(const.invoke):
(failCount.0.catch):
(failCount.0.module.undefined.catch):
* wasm/lowExecutableMemory/exports-oom.js: Added.
(const.type):
(const.params):
(const.randomProgram):
(failCount.0.catch):
(failCount.0.module.undefined.catch):
* wasm/lowExecutableMemory/imports-oom.js: Added.
(const.type):
(const.params):
(const.randomProgram):
(f.imports.push):
(failCount.0.catch):
(failCount.0.module.undefined.catch):

Source/JavaScriptCore:

Both on first compile with BBQ as well as on tier-up with OMG,
running out of X memory shouldn't cause the entire program to
terminate. An exception will do when compiling initial code (since
we don't have any other fallback at the moment), and refusal to
tier up will do as well (it'll just be slower).

This is useful because programs which generate huge amounts of
code simply look like crashes, which developers report to
us. Getting a JavaScript exception instead is much clearer.

* jit/ExecutableAllocator.cpp:
(JSC::ExecutableAllocator::allocate):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::shouldJIT):
* runtime/Options.h:
* wasm/WasmBBQPlan.cpp:
(JSC::Wasm::BBQPlan::prepare):
(JSC::Wasm::BBQPlan::complete):
* wasm/WasmBinding.cpp:
(JSC::Wasm::wasmToJs):
(JSC::Wasm::wasmToWasm):
* wasm/WasmBinding.h:
* wasm/WasmOMGPlan.cpp:
(JSC::Wasm::OMGPlan::work):
* wasm/js/JSWebAssemblyCodeBlock.cpp:
(JSC::JSWebAssemblyCodeBlock::JSWebAssemblyCodeBlock):
* wasm/js/JSWebAssemblyCodeBlock.h:
* wasm/js/JSWebAssemblyInstance.cpp:
(JSC::JSWebAssemblyInstance::finalizeCreation):

Tools:

* Scripts/run-jsc-stress-tests: add a configuration which runs the
tests under limited executable memory and avoids non-WebAssembly
code generation so that we more reliably run out of executable
memory in WebAssembly.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkJSTestswasmyaml">trunk/JSTests/wasm.yaml</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorejitExecutableAllocatorcpp">trunk/Source/JavaScriptCore/jit/ExecutableAllocator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLLIntSlowPathscpp">trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionsh">trunk/Source/JavaScriptCore/runtime/Options.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmBBQPlancpp">trunk/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmBindingcpp">trunk/Source/JavaScriptCore/wasm/WasmBinding.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmBindingh">trunk/Source/JavaScriptCore/wasm/WasmBinding.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmOMGPlancpp">trunk/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsJSWebAssemblyCodeBlockcpp">trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsJSWebAssemblyCodeBlockh">trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsJSWebAssemblyInstancecpp">trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsScriptsrunjscstresstests">trunk/Tools/Scripts/run-jsc-stress-tests</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>trunk/JSTests/wasm/lowExecutableMemory/</li>
<li><a href="#trunkJSTestswasmlowExecutableMemoryexecutablememoryoomjs">trunk/JSTests/wasm/lowExecutableMemory/executable-memory-oom.js</a></li>
<li><a href="#trunkJSTestswasmlowExecutableMemoryexportsoomjs">trunk/JSTests/wasm/lowExecutableMemory/exports-oom.js</a></li>
<li><a href="#trunkJSTestswasmlowExecutableMemoryimportsoomjs">trunk/JSTests/wasm/lowExecutableMemory/imports-oom.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog  2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/JSTests/ChangeLog     2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -1,3 +1,30 @@
</span><ins>+2017-06-27  JF Bastien  <jfbastien@apple.com>
+
+        WebAssembly: running out of executable memory should throw OoM
+        https://bugs.webkit.org/show_bug.cgi?id=171537
+        <rdar://problem/32963338>
+
+        Reviewed by Saam Barati.
+
+        * wasm.yaml:
+        * wasm/lowExecutableMemory/executable-memory-oom.js: Added.
+        (const.invoke):
+        (failCount.0.catch):
+        (failCount.0.module.undefined.catch):
+        * wasm/lowExecutableMemory/exports-oom.js: Added.
+        (const.type):
+        (const.params):
+        (const.randomProgram):
+        (failCount.0.catch):
+        (failCount.0.module.undefined.catch):
+        * wasm/lowExecutableMemory/imports-oom.js: Added.
+        (const.type):
+        (const.params):
+        (const.randomProgram):
+        (f.imports.push):
+        (failCount.0.catch):
+        (failCount.0.module.undefined.catch):
+
</ins><span class="cx"> 2017-06-27  Caio Lima  <ticaiolima@gmail.com>
</span><span class="cx"> 
</span><span class="cx">         [ESnext] Implement Object Rest - Implementing Object Rest Destructuring
</span></span></pre></div>
<a id="trunkJSTestswasmlowExecutableMemoryexecutablememoryoomjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/wasm/lowExecutableMemory/executable-memory-oom.js (0 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/lowExecutableMemory/executable-memory-oom.js                          (rev 0)
+++ trunk/JSTests/wasm/lowExecutableMemory/executable-memory-oom.js     2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -0,0 +1,121 @@
</span><ins>+import * as assert from '../assert.js'
+import Builder from '../Builder.js'
+
+const verbose = false;
+const maxInstructionCount = 500;
+const instancesTotal = 8;
+const invocationsTotal = 8;
+const tierUpCalls = 20000; // Call enough to trigger tier up and get it to compile.
+
+// This test starts running with a few bytes of executable memory available. Try
+// to create and instantiate a module which will fail to fit.
+
+const randomProgram = instructionCount => {
+    let b = new Builder()
+        .Type().End()
+        .Function().End()
+        .Export()
+            .Function("foo")
+            .Function("bar")
+        .End()
+        .Code()
+            .Function("foo", { params: [], ret: "f32" })
+                .F32Const(2.0)
+                .Return()
+            .End()
+            .Function("bar", { params: ["f32", "f32"], ret: "f32" })
+              .GetLocal(0);
+
+    // Insert a bunch of dependent instructions in a single basic block so that
+    // our compiler won't be able to strength-reduce.
+    const actions = [
+        b => b.GetLocal(0).F32Sub(),
+        b => b.GetLocal(1).F32Sub(),
+        b => b.GetLocal(0).F32Add(),
+        b => b.GetLocal(1).F32Add(),
+        b => b.GetLocal(0).F32Mul(),
+        b => b.GetLocal(1).F32Mul(),
+    ];
+
+    while (--instructionCount)
+        b = actions[(Math.random() * actions.length) | 0](b);
+
+    b = b.Return().End().End();
+
+    return b.WebAssembly().get();
+}
+
+let failCount = 0;
+let callCount = 0;
+let instances = [];
+
+const invoke = (instance, count) => {
+    if (verbose)
+        print(`Invoking`);
+    for (let i = 0; i < count; ++i)
+        assert.eq(instance.exports["foo"](), 2.0);
+    for (let i = 0; i < count; ++i)
+        instance.exports["bar"](2.0, 6.0);
+    ++callCount;
+};
+
+while (failCount === 0) {
+    const instructionCount = (Math.random() * maxInstructionCount + 1) | 0;
+
+    if (verbose)
+        print(`Trying module with ${instructionCount} instructions.`);
+
+    const buf = randomProgram(instructionCount);
+    let module;
+
+    try {
+        module = new WebAssembly.Module(buf);
+    } catch (e) {
+        if (e instanceof WebAssembly.CompileError) {
+            if (verbose)
+                print(`Caught: ${e}`);
+            ++failCount;
+        }
+        else
+            throw new Error(`Expected a WebAssembly.CompileError, got ${e}`);
+    }
+
+    if (module !== undefined) {
+        if (verbose)
+            print(`Creating instance`);
+
+        let instance;
+        try {
+            instance = new WebAssembly.Instance(module);
+        } catch (e) {
+            if (e instanceof WebAssembly.LinkError) {
+                if (verbose)
+                    print(`Caught: ${e}`);
+                ++failCount;
+            }
+            else
+                throw new Error(`Expected a WebAssembly.LinkError, got ${e}`);
+        }
+
+        if (instance !== undefined) {
+            instances.push(instance);
+            invoke(instance, 1);
+        }
+    }
+}
+
+if (callCount === 0)
+    throw new Error(`Expected to be able to allocate a WebAssembly module, instantiate it, and call its exports at least once`);
+
+// Make sure we can still call all the instances we create, even after going
+// OOM. This will try to force tier-up as well, which should fail.
+
+if (verbose)
+    print(`Invoking all previously created instances`);
+
+for (let instance of instances)
+    invoke(instance, tierUpCalls);
+
+// Do it twice to revisit what should have gotten tiered up.
+for (let instance of instances)
+    invoke(instance, 1);
</ins></span></pre></div>
<a id="trunkJSTestswasmlowExecutableMemoryexportsoomjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/wasm/lowExecutableMemory/exports-oom.js (0 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/lowExecutableMemory/exports-oom.js                            (rev 0)
+++ trunk/JSTests/wasm/lowExecutableMemory/exports-oom.js       2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -0,0 +1,107 @@
</span><ins>+import * as assert from '../assert.js'
+import Builder from '../Builder.js'
+
+const verbose = false;
+const numFunctions = 2;
+const maxParams = 128;
+
+// This test starts running with a few bytes of executable memory available. Try
+// to create and instantiate modules which have way more exports than anything
+// else. Hopefully they'll fail when trying to instantiate their entrypoints.
+
+const type = () => {
+    const types = ["i32", "f32", "f64"]; // Can't export i64.
+    return types[(Math.random() * types.length) | 0];
+};
+
+const params = () => {
+    let p = [];
+    let count = (Math.random() * maxParams) | 0;
+    while (count--)
+        p.push(type());
+    return p;
+};
+
+const randomProgram = () => {
+    let b = new Builder()
+        .Type().End()
+        .Function().End()
+        .Export();
+    for (let f = 0; f < numFunctions; ++f)
+        b = b.Function(`f${f}`);
+    b = b.End().Code();
+    for (let f = 0; f < numFunctions; ++f)
+        b = b.Function(`f${f}`, { params: params() }).Return().End();
+    b = b.End();
+    return b.WebAssembly().get();
+}
+
+let failCount = 0;
+let callCount = 0;
+let instances = [];
+
+const invoke = instance => {
+    let result = 0;
+    for (let f = 0; f < numFunctions; ++f) {
+        const name = `f${f}`;
+        if (verbose)
+            print(`Invoking ${name}`);
+        result += instance.exports[name]();
+        ++callCount;
+    }
+    return result;
+};
+
+while (failCount === 0) {
+    if (verbose)
+        print(`Trying...`);
+
+    const buf = randomProgram();
+    let module;
+
+    try {
+        module = new WebAssembly.Module(buf);
+    } catch (e) {
+        if (e instanceof WebAssembly.CompileError) {
+            if (verbose)
+                print(`Caught: ${e}`);
+            ++failCount;
+        }
+        else
+            throw new Error(`Expected a WebAssembly.CompileError, got ${e}`);
+    }
+
+    if (module !== undefined) {
+        if (verbose)
+            print(`Creating instance`);
+
+        let instance;
+        try {
+            instance = new WebAssembly.Instance(module);
+        } catch (e) {
+            if (e instanceof WebAssembly.LinkError) {
+                if (verbose)
+                    print(`Caught: ${e}`);
+                ++failCount;
+            }
+            else
+                throw new Error(`Expected a WebAssembly.LinkError, got ${e}`);
+        }
+
+        if (instance !== undefined) {
+            instances.push(instance);
+            invoke(instance);
+        }
+    }
+}
+
+if (callCount === 0)
+    throw new Error(`Expected to be able to allocate a WebAssembly module, instantiate it, and call its exports at least once`);
+
+// Make sure we can still call all the instances we create, even after going OOM.
+
+if (verbose)
+    print(`Invoking all previously created instances`);
+
+for (let instance of instances)
+    invoke(instance);
</ins></span></pre></div>
<a id="trunkJSTestswasmlowExecutableMemoryimportsoomjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/wasm/lowExecutableMemory/imports-oom.js (0 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/lowExecutableMemory/imports-oom.js                            (rev 0)
+++ trunk/JSTests/wasm/lowExecutableMemory/imports-oom.js       2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -0,0 +1,124 @@
</span><ins>+import * as assert from '../assert.js'
+import Builder from '../Builder.js'
+
+const verbose = false;
+const numFunctions = 2;
+const maxParams = 32;
+
+// This test starts running with a few bytes of executable memory available. Try
+// to create and instantiate modules which have way more imports than anything
+// else. Hopefully they'll fail when trying to instantiate their entrypoints.
+
+const type = () => {
+    const types = ["i32", "f32", "f64"];
+    return types[(Math.random() * types.length) | 0];
+};
+
+const params = () => {
+    let p = [];
+    let count = (Math.random() * maxParams) | 0;
+    while (count--)
+        p.push(type());
+    return p;
+};
+
+const randomProgram = () => {
+    let b = new Builder()
+        .Type().End()
+        .Import();
+    const ps = params();
+    for (let f = 0; f < numFunctions; ++f)
+        b = b.Function("imp", `${f}`, { params: ps });
+    b = b.End()
+        .Function().End()
+        .Export();
+    for (let f = 0; f < numFunctions; ++f)
+        b = b.Function(`call${f}`);
+    b = b.End()
+        .Code();
+    for (let f = 0; f < numFunctions; ++f) {
+        b = b.Function(`call${f}`, { params: ps });
+        for (let p = 0; p < ps.length; ++p)
+            b = b.GetLocal(p);
+        b = b.Call(f).End();
+    }
+    b = b.End();
+    return b.WebAssembly().get();
+}
+
+let failCount = 0;
+let callCount = 0;
+let instances = [];
+
+let imports = [];
+for (let f = 0; f < numFunctions; ++f)
+    imports.push((...args) => {
+        if (verbose)
+            print(`Invoked ${f} with: ${args}`);
+        ++callCount;
+    });
+
+const invoke = instance => {
+    let result = 0;
+    for (let f = 0; f < numFunctions; ++f) {
+        const name = `call${f}`;
+        if (verbose)
+            print(`Invoking ${name}`);
+        result += instance.exports[name]();
+    }
+    return result;
+};
+
+while (failCount === 0) {
+    if (verbose)
+        print(`Trying...`);
+
+    const buf = randomProgram();
+    let module;
+
+    try {
+        module = new WebAssembly.Module(buf);
+    } catch (e) {
+        if (e instanceof WebAssembly.CompileError) {
+            if (verbose)
+                print(`Caught: ${e}`);
+            ++failCount;
+        }
+        else
+            throw new Error(`Expected a WebAssembly.CompileError, got ${e}`);
+    }
+
+    if (module !== undefined) {
+        if (verbose)
+            print(`Creating instance`);
+
+        let instance;
+        try {
+            instance = new WebAssembly.Instance(module, { imp: imports });
+        } catch (e) {
+            if (e instanceof WebAssembly.LinkError) {
+                if (verbose)
+                    print(`Caught: ${e}`);
+                ++failCount;
+            }
+            else
+                throw new Error(`Expected a WebAssembly.LinkError, got ${e}`);
+        }
+
+        if (instance !== undefined) {
+            instances.push(instance);
+            invoke(instance);
+        }
+    }
+}
+
+if (callCount === 0)
+    throw new Error(`Expected to be able to allocate a WebAssembly module, instantiate it, and call its exports at least once`);
+
+// Make sure we can still call all the instances we create, even after going OOM.
+
+if (verbose)
+    print(`Invoking all previously created instances`);
+
+for (let instance of instances)
+    invoke(instance);
</ins></span></pre></div>
<a id="trunkJSTestswasmyaml"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm.yaml (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm.yaml  2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/JSTests/wasm.yaml     2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -33,6 +33,8 @@
</span><span class="cx">   cmd: runWebAssembly unless parseRunCommands
</span><span class="cx"> - path: wasm/stress
</span><span class="cx">   cmd: runWebAssembly unless parseRunCommands
</span><ins>+- path: wasm/lowExecutableMemory
+  cmd: runWebAssemblyLowExecutableMemory unless parseRunCommands
</ins><span class="cx"> 
</span><span class="cx"> - path: wasm/spec-tests/address.wast.js
</span><span class="cx">   cmd: runWebAssemblySpecTest :normal
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Source/JavaScriptCore/ChangeLog       2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -1,3 +1,41 @@
</span><ins>+2017-06-27  JF Bastien  <jfbastien@apple.com>
+
+        WebAssembly: running out of executable memory should throw OoM
+        https://bugs.webkit.org/show_bug.cgi?id=171537
+        <rdar://problem/32963338>
+
+        Reviewed by Saam Barati.
+
+        Both on first compile with BBQ as well as on tier-up with OMG,
+        running out of X memory shouldn't cause the entire program to
+        terminate. An exception will do when compiling initial code (since
+        we don't have any other fallback at the moment), and refusal to
+        tier up will do as well (it'll just be slower).
+
+        This is useful because programs which generate huge amounts of
+        code simply look like crashes, which developers report to
+        us. Getting a JavaScript exception instead is much clearer.
+
+        * jit/ExecutableAllocator.cpp:
+        (JSC::ExecutableAllocator::allocate):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::shouldJIT):
+        * runtime/Options.h:
+        * wasm/WasmBBQPlan.cpp:
+        (JSC::Wasm::BBQPlan::prepare):
+        (JSC::Wasm::BBQPlan::complete):
+        * wasm/WasmBinding.cpp:
+        (JSC::Wasm::wasmToJs):
+        (JSC::Wasm::wasmToWasm):
+        * wasm/WasmBinding.h:
+        * wasm/WasmOMGPlan.cpp:
+        (JSC::Wasm::OMGPlan::work):
+        * wasm/js/JSWebAssemblyCodeBlock.cpp:
+        (JSC::JSWebAssemblyCodeBlock::JSWebAssemblyCodeBlock):
+        * wasm/js/JSWebAssemblyCodeBlock.h:
+        * wasm/js/JSWebAssemblyInstance.cpp:
+        (JSC::JSWebAssemblyInstance::finalizeCreation):
+
</ins><span class="cx"> 2017-06-27  Saam Barati  <sbarati@apple.com>
</span><span class="cx"> 
</span><span class="cx">         JITStubRoutine::passesFilter should use isJITPC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitExecutableAllocatorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/ExecutableAllocator.cpp (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/ExecutableAllocator.cpp  2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Source/JavaScriptCore/jit/ExecutableAllocator.cpp     2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -412,8 +412,11 @@
</span><span class="cx">         size_t bytesAllocated = statistics.bytesAllocated + sizeInBytes;
</span><span class="cx">         size_t bytesAvailable = static_cast<size_t>(
</span><span class="cx">             statistics.bytesReserved * (1 - executablePoolReservationFraction));
</span><del>-        if (bytesAllocated > bytesAvailable)
</del><ins>+        if (bytesAllocated > bytesAvailable) {
+            if (Options::logExecutableAllocation())
+                dataLog("Allocation failed because bytes allocated ", bytesAllocated,  " > ", bytesAvailable, " bytes available.\n");
</ins><span class="cx">             return nullptr;
</span><ins>+        }
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     RefPtr<ExecutableMemoryHandle> result = allocator->allocate(sizeInBytes, ownerUID);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLLIntSlowPathscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp     2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp        2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -318,8 +318,7 @@
</span><span class="cx">         || !ensureGlobalJITWhitelist().contains(codeBlock))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    // You can modify this to turn off JITting without rebuilding the world.
-    return exec->vm().canUseJIT();
</del><ins>+    return exec->vm().canUseJIT() && Options::useBaselineJIT();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // Returns true if we should try to OSR.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.h (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.h    2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Source/JavaScriptCore/runtime/Options.h       2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -112,7 +112,8 @@
</span><span class="cx">     v(optionString, configFile, nullptr, Normal, "file to configure JSC options and logging location") \
</span><span class="cx">     \
</span><span class="cx">     v(bool, useLLInt,  true, Normal, "allows the LLINT to be used if true") \
</span><del>-    v(bool, useJIT,    true, Normal, "allows the baseline JIT to be used if true") \
</del><ins>+    v(bool, useJIT,    true, Normal, "allows the executable pages to be allocated for JIT and thunks if true") \
+    v(bool, useBaselineJIT, true, Normal, "allows the baseline JIT to be used if true") \
</ins><span class="cx">     v(bool, useDFGJIT, true, Normal, "allows the DFG JIT to be used if true") \
</span><span class="cx">     v(bool, useRegExpJIT, true, Normal, "allows the RegExp JIT to be used if true") \
</span><span class="cx">     v(bool, useDOMJIT, true, Normal, "allows the DOMJIT to be used if true") \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmBBQPlancpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp 2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp    2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -175,7 +175,15 @@
</span><span class="cx">             continue;
</span><span class="cx">         unsigned importFunctionIndex = m_wasmToWasmExitStubs.size();
</span><span class="cx">         dataLogLnIf(verbose, "Processing import function number ", importFunctionIndex, ": ", makeString(import->module), ": ", makeString(import->field));
</span><del>-        m_wasmToWasmExitStubs.uncheckedAppend(wasmToWasm(importFunctionIndex));
</del><ins>+        auto binding = wasmToWasm(importFunctionIndex);
+        if (UNLIKELY(!binding)) {
+            switch (binding.error()) {
+            case BindingFailure::OutOfMemory:
+                return fail(holdLock(m_lock), makeString("Out of executable memory at import ", String::number(importIndex)));
+            }
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+        m_wasmToWasmExitStubs.uncheckedAppend(binding.value());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     const uint32_t importFunctionCount = m_moduleInformation->importFunctionCount();
</span><span class="lines">@@ -288,12 +296,17 @@
</span><span class="cx">     ASSERT(m_state != State::Compiled || m_currentIndex >= m_moduleInformation->functionLocationInBinary.size());
</span><span class="cx">     dataLogLnIf(verbose, "Starting Completion");
</span><span class="cx"> 
</span><del>-    if (m_state == State::Compiled) {
</del><ins>+    if (!failed() && m_state == State::Compiled) {
</ins><span class="cx">         for (uint32_t functionIndex = 0; functionIndex < m_moduleInformation->functionLocationInBinary.size(); functionIndex++) {
</span><span class="cx">             CompilationContext& context = m_compilationContexts[functionIndex];
</span><span class="cx">             SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
</span><span class="cx">             {
</span><del>-                LinkBuffer linkBuffer(*context.wasmEntrypointJIT, nullptr);
</del><ins>+                LinkBuffer linkBuffer(*context.wasmEntrypointJIT, nullptr, JITCompilationCanFail);
+                if (UNLIKELY(linkBuffer.didFailToAllocate())) {
+                    Base::fail(locker, makeString("Out of executable memory in function at index ", String::number(functionIndex)));
+                    return;
+                }
+
</ins><span class="cx">                 m_wasmInternalFunctions[functionIndex]->entrypoint.compilation = std::make_unique<B3::Compilation>(
</span><span class="cx">                     FINALIZE_CODE(linkBuffer, ("WebAssembly function[%i] %s", functionIndex, SignatureInformation::get(signatureIndex).toString().ascii().data())),
</span><span class="cx">                     WTFMove(context.wasmEntrypointByproducts));
</span><span class="lines">@@ -300,7 +313,12 @@
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             if (auto jsToWasmInternalFunction = m_jsToWasmInternalFunctions.get(functionIndex)) {
</span><del>-                LinkBuffer linkBuffer(*context.jsEntrypointJIT, nullptr);
</del><ins>+                LinkBuffer linkBuffer(*context.jsEntrypointJIT, nullptr, JITCompilationCanFail);
+                if (UNLIKELY(linkBuffer.didFailToAllocate())) {
+                    Base::fail(locker, makeString("Out of executable memory in function entrypoint at index ", String::number(functionIndex)));
+                    return;
+                }
+
</ins><span class="cx">                 jsToWasmInternalFunction->entrypoint.compilation = std::make_unique<B3::Compilation>(
</span><span class="cx">                     FINALIZE_CODE(linkBuffer, ("JavaScript->WebAssembly entrypoint[%i] %s", functionIndex, SignatureInformation::get(signatureIndex).toString().ascii().data())),
</span><span class="cx">                     WTFMove(context.jsEntrypointByproducts));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmBindingcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmBinding.cpp (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmBinding.cpp 2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Source/JavaScriptCore/wasm/WasmBinding.cpp    2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -51,7 +51,7 @@
</span><span class="cx">     jit.loadPtr(JIT::Address(result, JSWebAssemblyInstance::offsetOfImportFunction(importIndex)), result);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-MacroAssemblerCodeRef wasmToJs(VM* vm, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex signatureIndex, unsigned importIndex)
</del><ins>+Expected<MacroAssemblerCodeRef, BindingFailure> wasmToJs(VM* vm, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex signatureIndex, unsigned importIndex)
</ins><span class="cx"> {
</span><span class="cx">     // FIXME: This function doesn't properly abstract away the calling convention.
</span><span class="cx">     // It'd be super easy to do so: https://bugs.webkit.org/show_bug.cgi?id=169401
</span><span class="lines">@@ -119,7 +119,10 @@
</span><span class="cx">                 ASSERT(!!vm->callFrameForCatch);
</span><span class="cx">             };
</span><span class="cx"> 
</span><del>-            LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID);
</del><ins>+            LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID, JITCompilationCanFail);
+            if (UNLIKELY(linkBuffer.didFailToAllocate()))
+                return makeUnexpected(BindingFailure::OutOfMemory);
+
</ins><span class="cx">             linkBuffer.link(call, throwBadI64);
</span><span class="cx">             return FINALIZE_CODE(linkBuffer, ("WebAssembly->JavaScript invalid i64 use in import[%i]", importIndex));
</span><span class="cx">         }
</span><span class="lines">@@ -303,7 +306,10 @@
</span><span class="cx">         jit.emitFunctionEpilogue();
</span><span class="cx">         jit.ret();
</span><span class="cx"> 
</span><del>-        LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID);
</del><ins>+        LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID, JITCompilationCanFail);
+        if (UNLIKELY(linkBuffer.didFailToAllocate()))
+            return makeUnexpected(BindingFailure::OutOfMemory);
+
</ins><span class="cx">         linkBuffer.link(call, callFunc);
</span><span class="cx">         linkBuffer.link(exceptionCall, doUnwinding);
</span><span class="cx"> 
</span><span class="lines">@@ -600,7 +606,10 @@
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    LinkBuffer patchBuffer(jit, GLOBAL_THUNK_ID);
</del><ins>+    LinkBuffer patchBuffer(jit, GLOBAL_THUNK_ID, JITCompilationCanFail);
+    if (UNLIKELY(patchBuffer.didFailToAllocate()))
+        return makeUnexpected(BindingFailure::OutOfMemory);
+
</ins><span class="cx">     patchBuffer.link(slowCall, FunctionPtr(vm->getCTIStub(linkCallThunkGenerator).code().executableAddress()));
</span><span class="cx">     CodeLocationLabel callReturnLocation(patchBuffer.locationOfNearCall(slowCall));
</span><span class="cx">     CodeLocationLabel hotPathBegin(patchBuffer.locationOf(targetToCheck));
</span><span class="lines">@@ -610,7 +619,7 @@
</span><span class="cx">     return FINALIZE_CODE(patchBuffer, ("WebAssembly->JavaScript import[%i] %s", importIndex, signature.toString().ascii().data()));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-MacroAssemblerCodeRef wasmToWasm(unsigned importIndex)
</del><ins>+Expected<MacroAssemblerCodeRef, BindingFailure> wasmToWasm(unsigned importIndex)
</ins><span class="cx"> {
</span><span class="cx">     const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
</span><span class="cx">     JIT jit;
</span><span class="lines">@@ -653,7 +662,10 @@
</span><span class="cx">     jit.loadPtr(scratch, scratch);
</span><span class="cx">     jit.jump(scratch);
</span><span class="cx"> 
</span><del>-    LinkBuffer patchBuffer(jit, GLOBAL_THUNK_ID);
</del><ins>+    LinkBuffer patchBuffer(jit, GLOBAL_THUNK_ID, JITCompilationCanFail);
+    if (UNLIKELY(patchBuffer.didFailToAllocate()))
+        return makeUnexpected(BindingFailure::OutOfMemory);
+
</ins><span class="cx">     return FINALIZE_CODE(patchBuffer, ("WebAssembly->WebAssembly import[%i]", importIndex));
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmBindingh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmBinding.h (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmBinding.h   2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Source/JavaScriptCore/wasm/WasmBinding.h      2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include "VM.h"
</span><span class="cx"> #include "WasmFormat.h"
</span><span class="cx"> #include <wtf/Bag.h>
</span><ins>+#include <wtf/Expected.h>
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -38,9 +39,13 @@
</span><span class="cx"> 
</span><span class="cx"> namespace Wasm {
</span><span class="cx"> 
</span><del>-MacroAssemblerCodeRef wasmToWasm(unsigned importIndex);
-MacroAssemblerCodeRef wasmToJs(VM*, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex, unsigned importIndex);
</del><ins>+enum class BindingFailure {
+    OutOfMemory,
+};
</ins><span class="cx"> 
</span><ins>+Expected<MacroAssemblerCodeRef, BindingFailure> wasmToWasm(unsigned importIndex);
+Expected<MacroAssemblerCodeRef, BindingFailure> wasmToJs(VM*, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex, unsigned importIndex);
+
</ins><span class="cx"> } } // namespace JSC::Wasm
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(WEBASSEMBLY)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmOMGPlancpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp 2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp    2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -88,7 +88,12 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Entrypoint omgEntrypoint;
</span><del>-    LinkBuffer linkBuffer(*context.wasmEntrypointJIT, nullptr);
</del><ins>+    LinkBuffer linkBuffer(*context.wasmEntrypointJIT, nullptr, JITCompilationCanFail);
+    if (UNLIKELY(linkBuffer.didFailToAllocate())) {
+        Base::fail(holdLock(m_lock), makeString("Out of executable memory while tiering up function at index ", String::number(m_functionIndex)));
+        return;
+    }
+
</ins><span class="cx">     omgEntrypoint.compilation = std::make_unique<B3::Compilation>(
</span><span class="cx">         FINALIZE_CODE(linkBuffer, ("WebAssembly OMG function[%i] %s", m_functionIndex, SignatureInformation::get(signatureIndex).toString().ascii().data())),
</span><span class="cx">         WTFMove(context.wasmEntrypointByproducts));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsJSWebAssemblyCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.cpp (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.cpp   2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.cpp      2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -58,7 +58,16 @@
</span><span class="cx">     m_wasmToJSExitStubs.reserveCapacity(m_codeBlock->functionImportCount());
</span><span class="cx">     for (unsigned importIndex = 0; importIndex < m_codeBlock->functionImportCount(); ++importIndex) {
</span><span class="cx">         Wasm::SignatureIndex signatureIndex = moduleInformation.importFunctionSignatureIndices.at(importIndex);
</span><del>-        m_wasmToJSExitStubs.uncheckedAppend(Wasm::wasmToJs(&vm, m_callLinkInfos, signatureIndex, importIndex));
</del><ins>+        auto binding = Wasm::wasmToJs(&vm, m_callLinkInfos, signatureIndex, importIndex);
+        if (UNLIKELY(!binding)) {
+            switch (binding.error()) {
+            case Wasm::BindingFailure::OutOfMemory:
+                m_errorMessage = ASCIILiteral("Out of executable memory");
+                return;
+            }
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+        m_wasmToJSExitStubs.uncheckedAppend(binding.value());
</ins><span class="cx">         importWasmToJSStub(importIndex) = m_wasmToJSExitStubs[importIndex].code().executableAddress();
</span><span class="cx">     }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsJSWebAssemblyCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.h (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.h     2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.h        2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -75,15 +75,18 @@
</span><span class="cx"> 
</span><span class="cx">     Wasm::Callee& jsEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
</span><span class="cx">     {
</span><ins>+        ASSERT(runnable());
</ins><span class="cx">         return m_codeBlock->jsEntrypointCalleeFromFunctionIndexSpace(functionIndexSpace);
</span><span class="cx">     }
</span><span class="cx">     Wasm::WasmEntrypointLoadLocation wasmEntrypointLoadLocationFromFunctionIndexSpace(unsigned functionIndexSpace)
</span><span class="cx">     {
</span><ins>+        ASSERT(runnable());
</ins><span class="cx">         return m_codeBlock->wasmEntrypointLoadLocationFromFunctionIndexSpace(functionIndexSpace);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Wasm::WasmEntrypointLoadLocation wasmToJsCallStubForImport(unsigned importIndex)
</span><span class="cx">     {
</span><ins>+        ASSERT(runnable());
</ins><span class="cx">         return &importWasmToJSStub(importIndex);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -96,6 +99,14 @@
</span><span class="cx"> 
</span><span class="cx">     void clearJSCallICs(VM&);
</span><span class="cx"> 
</span><ins>+    bool runnable() const { return !m_errorMessage; }
+
+    String errorMessage()
+    {
+        ASSERT(!runnable());
+        return m_errorMessage;
+    }
+
</ins><span class="cx"> private:
</span><span class="cx">     JSWebAssemblyCodeBlock(VM&, Ref<Wasm::CodeBlock>&&, const Wasm::ModuleInformation&);
</span><span class="cx">     DECLARE_EXPORT_INFO;
</span><span class="lines">@@ -127,6 +138,7 @@
</span><span class="cx">     Vector<MacroAssemblerCodeRef> m_wasmToJSExitStubs;
</span><span class="cx">     UnconditionalFinalizer m_unconditionalFinalizer;
</span><span class="cx">     Bag<CallLinkInfo> m_callLinkInfos;
</span><ins>+    String m_errorMessage;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsJSWebAssemblyInstancecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp    2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp       2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -112,6 +112,10 @@
</span><span class="cx">         m_codeBlock.set(vm, this, codeBlock);
</span><span class="cx">     } else {
</span><span class="cx">         codeBlock = JSWebAssemblyCodeBlock::create(vm, wasmCodeBlock.copyRef(), m_module.get());
</span><ins>+        if (UNLIKELY(!codeBlock->runnable())) {
+            throwException(exec, scope, JSWebAssemblyLinkError::create(exec, vm, globalObject()->WebAssemblyLinkErrorStructure(), codeBlock->errorMessage()));
+            return;
+        }
</ins><span class="cx">         m_codeBlock.set(vm, this, codeBlock);
</span><span class="cx">         module()->setCodeBlock(vm, memoryMode(), codeBlock);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Tools/ChangeLog       2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2017-06-27  JF Bastien  <jfbastien@apple.com>
+
+        WebAssembly: running out of executable memory should throw OoM
+        https://bugs.webkit.org/show_bug.cgi?id=171537
+        <rdar://problem/32963338>
+
+        Reviewed by Saam Barati.
+
+        * Scripts/run-jsc-stress-tests: add a configuration which runs the
+        tests under limited executable memory and avoids non-WebAssembly
+        code generation so that we more reliably run out of executable
+        memory in WebAssembly.
+
</ins><span class="cx"> 2017-06-27  Wenson Hsieh  <wenson_hsieh@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [iOS DnD] Support dragging out of contenteditable areas without a prior selection
</span></span></pre></div>
<a id="trunkToolsScriptsrunjscstresstests"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/run-jsc-stress-tests (218867 => 218868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/run-jsc-stress-tests 2017-06-28 06:23:23 UTC (rev 218867)
+++ trunk/Tools/Scripts/run-jsc-stress-tests    2017-06-28 06:42:13 UTC (rev 218868)
</span><span class="lines">@@ -1234,7 +1234,6 @@
</span><span class="cx">     when :skip
</span><span class="cx">         return
</span><span class="cx">     end
</span><del>-
</del><span class="cx">     return if !$jitTests
</span><span class="cx">     return if !$isFTLPlatform
</span><span class="cx">     prepareExtraAbsoluteFiles(WASMTESTS_PATH, ["wasm.json"])
</span><span class="lines">@@ -1246,12 +1245,24 @@
</span><span class="cx">     prepareExtraRelativeFiles(harness.map { |f| "../../spec-harness/" + f }, $collection)
</span><span class="cx"> 
</span><span class="cx">     runWithOutputHandler("default-wasm", noisyOutputHandler, "../spec-harness.js", *FTL_OPTIONS)
</span><del>-    runWithOutputHandler("wasm-no-cjit-yes-tls-context", noisyOutputHandler, "../spec-harness.js",  "--useFastTLSForWasmContext=true", *(FTL_OPTIONS + NO_CJIT_OPTIONS))
-    runWithOutputHandler("wasm-eager-jettison", noisyOutputHandler, "../spec-harness.js", "--forceCodeBlockToJettisonDueToOldAge=true", *FTL_OPTIONS)
-    runWithOutputHandler("wasm-no-call-ic", noisyOutputHandler, "../spec-harness.js", "--useCallICsForWebAssemblyToJSCalls=false", *FTL_OPTIONS)
-    runWithOutputHandler("wasm-no-tls-context", noisyOutputHandler, "../spec-harness.js", "--useFastTLSForWasmContext=false", *FTL_OPTIONS)
</del><ins>+    if !$quickMode
+      runWithOutputHandler("wasm-no-cjit-yes-tls-context", noisyOutputHandler, "../spec-harness.js",  "--useFastTLSForWasmContext=true", *(FTL_OPTIONS + NO_CJIT_OPTIONS))
+      runWithOutputHandler("wasm-eager-jettison", noisyOutputHandler, "../spec-harness.js", "--forceCodeBlockToJettisonDueToOldAge=true", *FTL_OPTIONS)
+      runWithOutputHandler("wasm-no-call-ic", noisyOutputHandler, "../spec-harness.js", "--useCallICsForWebAssemblyToJSCalls=false", *FTL_OPTIONS)
+      runWithOutputHandler("wasm-no-tls-context", noisyOutputHandler, "../spec-harness.js", "--useFastTLSForWasmContext=false", *FTL_OPTIONS)
+    end
</ins><span class="cx"> end
</span><span class="cx"> 
</span><ins>+def runWebAssemblyLowExecutableMemory(*optionalTestSpecificOptions)
+    return if !$jitTests
+    return if !$isFTLPlatform
+    modules = Dir[WASMTESTS_PATH + "*.js"].map { |f| File.basename(f) }
+    prepareExtraAbsoluteFiles(WASMTESTS_PATH, ["wasm.json"])
+    prepareExtraRelativeFiles(modules.map { |f| "../" + f }, $collection)
+    # Only let WebAssembly get executable memory.
+    run("default-wasm", "--useConcurrentGC=0" , "--useConcurrentJIT=0", "--jitMemoryReservationSize=15000", "--useBaselineJIT=0", "--useDFGJIT=0", "--useFTLJIT=0", "-m")
+end
+
</ins><span class="cx"> def runChakra(mode, exception, baselineFile, extraFiles)
</span><span class="cx">     raise unless $benchmark.to_s =~ /\.js$/
</span><span class="cx">     failsWithException = exception != "NoException"
</span></span></pre>
</div>
</div>

</body>
</html>