<!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>[209850] 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/209850">209850</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2016-12-14 19:30:44 -0800 (Wed, 14 Dec 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>WebAssembly: Add various low hanging fruit that will allow us to run the LLVM torture tests in Wasm
https://bugs.webkit.org/show_bug.cgi?id=165883
Reviewed by Keith Miller.
JSTests:
* wasm/Builder.js:
(export.default.Builder.prototype._registerSectionBuilders.switch.case.string_appeared_here.this.section):
* wasm/Builder_WebAssemblyBinary.js:
(const.emitters.Export):
* wasm/js-api/table.js:
(assertBadBinary):
(assertBadTable):
(assert.truthy):
* wasm/js-api/test_memory.js:
(binaryShouldNotParse):
(test):
(test.testMemImportError):
(assert.truthy):
(assert): Deleted.
Source/JavaScriptCore:
This patch implements some low hanging fruit:
- Exporting Table
- Exporting Memory
- Load16 with zero extension to both 32 and 64 bit values.
- Fixes Unreachable to emit code that will prevent B3 from having a validation error.
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::addUnreachable):
(JSC::Wasm::sizeOfLoadOp):
(JSC::Wasm::B3IRGenerator::emitLoadOp):
* wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser<Context>::parseExpression):
* wasm/WasmModuleParser.cpp:
(JSC::Wasm::ModuleParser::parseExport):
* wasm/WasmValidate.cpp:
(JSC::Wasm::Validate::addUnreachable):
* wasm/js/WebAssemblyInstanceConstructor.cpp:
(JSC::constructJSWebAssemblyInstance):
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::finishCreation):
(JSC::WebAssemblyModuleRecord::link):</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkJSTestswasmBuilderjs">trunk/JSTests/wasm/Builder.js</a></li>
<li><a href="#trunkJSTestswasmBuilder_WebAssemblyBinaryjs">trunk/JSTests/wasm/Builder_WebAssemblyBinary.js</a></li>
<li><a href="#trunkJSTestswasmjsapitablejs">trunk/JSTests/wasm/js-api/table.js</a></li>
<li><a href="#trunkJSTestswasmjsapitest_memoryjs">trunk/JSTests/wasm/js-api/test_memory.js</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="#trunkSourceJavaScriptCorewasmWasmFunctionParserh">trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmModuleParsercpp">trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmValidatecpp">trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyInstanceConstructorcpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyModuleRecordcpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (209849 => 209850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2016-12-15 02:31:37 UTC (rev 209849)
+++ trunk/JSTests/ChangeLog        2016-12-15 03:30:44 UTC (rev 209850)
</span><span class="lines">@@ -1,3 +1,25 @@
</span><ins>+2016-12-14 Saam Barati <sbarati@apple.com>
+
+ WebAssembly: Add various low hanging fruit that will allow us to run the LLVM torture tests in Wasm
+ https://bugs.webkit.org/show_bug.cgi?id=165883
+
+ Reviewed by Keith Miller.
+
+ * wasm/Builder.js:
+ (export.default.Builder.prototype._registerSectionBuilders.switch.case.string_appeared_here.this.section):
+ * wasm/Builder_WebAssemblyBinary.js:
+ (const.emitters.Export):
+ * wasm/js-api/table.js:
+ (assertBadBinary):
+ (assertBadTable):
+ (assert.truthy):
+ * wasm/js-api/test_memory.js:
+ (binaryShouldNotParse):
+ (test):
+ (test.testMemImportError):
+ (assert.truthy):
+ (assert): Deleted.
+
</ins><span class="cx"> 2016-12-14 Filip Pizlo <fpizlo@apple.com>
</span><span class="cx">
</span><span class="cx"> DirectTailCall implementation needs to tell the shuffler what to put into the ArgumentCount explicitly
</span></span></pre></div>
<a id="trunkJSTestswasmBuilderjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/Builder.js (209849 => 209850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/Builder.js        2016-12-15 02:31:37 UTC (rev 209849)
+++ trunk/JSTests/wasm/Builder.js        2016-12-15 03:30:44 UTC (rev 209850)
</span><span class="lines">@@ -191,6 +191,22 @@
</span><span class="cx"> }
</span><span class="cx"> };
</span><span class="cx">
</span><ins>+const _exportMemoryContinuation = (builder, section, nextBuilder) => {
+ return (field, index) => {
+ assert.isNumber(index, `Memory exports only support number indices`);
+ section.data.push({field, kind: "Memory", index});
+ return nextBuilder;
+ }
+};
+
+const _exportTableContinuation = (builder, section, nextBuilder) => {
+ return (field, index) => {
+ assert.isNumber(index, `Table exports only support number indices`);
+ section.data.push({field, kind: "Table", index});
+ return nextBuilder;
+ }
+};
+
</ins><span class="cx"> const _importGlobalContinuation = (builder, section, nextBuilder) => {
</span><span class="cx"> return () => {
</span><span class="cx"> const globalBuilder = {
</span><span class="lines">@@ -516,11 +532,11 @@
</span><span class="cx"> const s = this._addSection(section);
</span><span class="cx"> const exportBuilder = {
</span><span class="cx"> End: () => this,
</span><del>- Table: () => { throw new Error(`Unimplemented: export table`); },
- Memory: () => { throw new Error(`Unimplemented: export memory`); },
</del><span class="cx"> };
</span><span class="cx"> exportBuilder.Global = _exportGlobalContinuation(this, s, exportBuilder);
</span><span class="cx"> exportBuilder.Function = _exportFunctionContinuation(this, s, exportBuilder);
</span><ins>+ exportBuilder.Memory = _exportMemoryContinuation(this, s, exportBuilder);
+ exportBuilder.Table = _exportTableContinuation(this, s, exportBuilder);
</ins><span class="cx"> return exportBuilder;
</span><span class="cx"> };
</span><span class="cx"> break;
</span></span></pre></div>
<a id="trunkJSTestswasmBuilder_WebAssemblyBinaryjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/Builder_WebAssemblyBinary.js (209849 => 209850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/Builder_WebAssemblyBinary.js        2016-12-15 02:31:37 UTC (rev 209849)
+++ trunk/JSTests/wasm/Builder_WebAssemblyBinary.js        2016-12-15 03:30:44 UTC (rev 209850)
</span><span class="lines">@@ -167,14 +167,13 @@
</span><span class="cx"> put(bin, "string", entry.field);
</span><span class="cx"> put(bin, "uint8", WASM.externalKindValue[entry.kind]);
</span><span class="cx"> switch (entry.kind) {
</span><del>- default: throw new Error(`Implementation problem: unexpected kind ${entry.kind}`);
</del><span class="cx"> case "Global":
</span><span class="cx"> case "Function":
</span><ins>+ case "Memory":
+ case "Table":
</ins><span class="cx"> put(bin, "varuint32", entry.index);
</span><span class="cx"> break;
</span><del>- case "Table": throw new Error(`Not yet implemented`);
- case "Memory": throw new Error(`Not yet implemented`);
-
</del><ins>+ default: throw new Error(`Implementation problem: unexpected kind ${entry.kind}`);
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> },
</span></span></pre></div>
<a id="trunkJSTestswasmjsapitablejs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/js-api/table.js (209849 => 209850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/table.js        2016-12-15 02:31:37 UTC (rev 209849)
+++ trunk/JSTests/wasm/js-api/table.js        2016-12-15 03:30:44 UTC (rev 209850)
</span><span class="lines">@@ -1,19 +1,13 @@
</span><span class="cx"> import Builder from '../Builder.js';
</span><span class="cx"> import * as assert from '../assert.js';
</span><span class="cx">
</span><del>-const badTableString = "couldn't parse section Table";
-const badImportString = "couldn't parse section Import";
</del><ins>+const badTableString = "couldn't parse section Table: Indirect function table and other tables (evaluating 'new WebAssembly.Module(bin)')";
+const badImportString = "couldn't parse section Import: Import declarations (evaluating 'new WebAssembly.Module(bin)')";
+const badExportString = "couldn't parse section Export: Exports (evaluating 'new WebAssembly.Module(bin)')";
+
</ins><span class="cx"> function assertBadBinary(builder, str) {
</span><span class="cx"> const bin = builder.WebAssembly().get();
</span><del>- let threw = false;
- try {
- new WebAssembly.Module(bin);
- } catch(e) {
- threw = true;
- assert.truthy(e.toString().indexOf(str) !== -1);
- assert.truthy(e instanceof WebAssembly.CompileError);
- }
- assert.truthy(threw);
</del><ins>+ assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, str);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -57,7 +51,7 @@
</span><span class="cx"> .CallIndirect(0, 0)
</span><span class="cx"> .End()
</span><span class="cx"> .End();
</span><del>- assertBadBinary(builder, "call_indirect is only valid when a table is defined or imported");
</del><ins>+ assertBadBinary(builder, "call_indirect is only valid when a table is defined or imported (evaluating 'new WebAssembly.Module(bin)')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -76,9 +70,38 @@
</span><span class="cx"> .CallIndirect(0, 1)
</span><span class="cx"> .End()
</span><span class="cx"> .End();
</span><del>- assertBadBinary(builder, "call_indirect 'reserved' varuint1 must be 0x0");
</del><ins>+ assertBadBinary(builder, "call_indirect 'reserved' varuint1 must be 0x0 (evaluating 'new WebAssembly.Module(bin)')");
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+{
+ // Can't export an undefined table
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Export()
+ .Table("foo", 0)
+ .End()
+ .Code()
+ .End();
+ assertBadBinary(builder, badExportString);
+}
+
+{
+ // Can't export a table at index 1.
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 20, maximum: 30, element: "anyfunc"})
+ .End()
+ .Export()
+ .Table("foo", 1)
+ .End()
+ .Code()
+ .End();
+ assertBadBinary(builder, badExportString);
+}
+
</ins><span class="cx"> function assertBadTable(tableDescription) {
</span><span class="cx"> const builder = new Builder()
</span><span class="cx"> .Type().End()
</span><span class="lines">@@ -228,3 +251,43 @@
</span><span class="cx"> assertBadTable([]);
</span><span class="cx"> assertBadTable(new WebAssembly.Memory({initial:1}));
</span><span class="cx"> }
</span><ins>+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Import()
+ .Table("imp", "table", {initial: 25, element: "anyfunc"})
+ .End()
+ .Function().End()
+ .Export()
+ .Table("table", 0)
+ .Table("table2", 0)
+ .End()
+ .Code().End();
+
+ const module = new WebAssembly.Module(builder.WebAssembly().get());
+ const table = new WebAssembly.Table({element: "anyfunc", initial: 25});
+ const instance = new WebAssembly.Instance(module, {imp: {table}});
+ assert.truthy(table === instance.exports.table);
+ assert.truthy(table === instance.exports.table2);
+}
+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 20, maximum: 30, element: "anyfunc"})
+ .End()
+ .Export()
+ .Table("table", 0)
+ .Table("table2", 0)
+ .End()
+ .Code().End();
+
+ const module = new WebAssembly.Module(builder.WebAssembly().get());
+ const instance = new WebAssembly.Instance(module);
+ assert.eq(instance.exports.table, instance.exports.table2);
+ assert.eq(instance.exports.table.length, 20);
+ assert.truthy(instance.exports.table instanceof WebAssembly.Table);
+}
</ins></span></pre></div>
<a id="trunkJSTestswasmjsapitest_memoryjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/js-api/test_memory.js (209849 => 209850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/test_memory.js        2016-12-15 02:31:37 UTC (rev 209849)
+++ trunk/JSTests/wasm/js-api/test_memory.js        2016-12-15 03:30:44 UTC (rev 209850)
</span><span class="lines">@@ -1,12 +1,7 @@
</span><span class="cx"> // FIXME: use the assert library: https://bugs.webkit.org/show_bug.cgi?id=165684
</span><span class="cx"> import Builder from '../Builder.js';
</span><ins>+import * as assert from '../assert.js';
</ins><span class="cx">
</span><del>-function assert(b) {
- if (!b) {
- throw new Error("Bad assertion");
- }
-}
-
</del><span class="cx"> const pageSize = 64 * 1024;
</span><span class="cx"> const maxPageCount = (2**32) / pageSize;
</span><span class="cx">
</span><span class="lines">@@ -18,7 +13,7 @@
</span><span class="cx"> } catch(e) {
</span><span class="cx"> threw = true;
</span><span class="cx"> }
</span><del>- assert(threw);
</del><ins>+ assert.truthy(threw);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -102,29 +97,37 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><del>- let threw = false;
- try {
- new WebAssembly.Memory(20);
- } catch(e) {
- assert(e instanceof TypeError);
- assert(e.message === "WebAssembly.Memory expects its first argument to be an object");
- threw = true;
- }
- assert(threw);
</del><ins>+ // Can't export an undefined memory.
+ const builder = (new Builder())
+ .Type().End()
+ .Function().End()
+ .Export()
+ .Memory("memory", 0)
+ .End()
+ .Code()
+ .End();
+ binaryShouldNotParse(builder);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><del>- let threw = false;
- try {
- new WebAssembly.Memory({}, {});
- } catch(e) {
- assert(e instanceof TypeError);
- assert(e.message === "WebAssembly.Memory expects exactly one argument");
- threw = true;
- }
- assert(threw);
</del><ins>+ // Can't export a non-zero memory index.
+ const builder = (new Builder())
+ .Type().End()
+ .Import().Memory("imp", "memory", {initial: 20}).End()
+ .Function().End()
+ .Export()
+ .Memory("memory", 1)
+ .End()
+ .Code()
+ .End();
+ binaryShouldNotParse(builder);
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+{
+ assert.throws(() => new WebAssembly.Memory(20), TypeError, "WebAssembly.Memory expects its first argument to be an object");
+ assert.throws(() => new WebAssembly.Memory({}, {}), TypeError, "WebAssembly.Memory expects exactly one argument");
+}
+
</ins><span class="cx"> function test(f) {
</span><span class="cx"> noInline(f);
</span><span class="cx"> for (let i = 0; i < 2; i++) {
</span><span class="lines">@@ -164,10 +167,10 @@
</span><span class="cx"> let value = i + 1;
</span><span class="cx"> let address = i * 4;
</span><span class="cx"> let result = foo(value, address);
</span><del>- assert(result === value);
</del><ins>+ assert.truthy(result === value);
</ins><span class="cx"> let arrayBuffer = memory.buffer;
</span><span class="cx"> let buffer = new Uint32Array(arrayBuffer);
</span><del>- assert(buffer[i] === value);
</del><ins>+ assert.truthy(buffer[i] === value);
</ins><span class="cx"> }
</span><span class="cx"> });
</span><span class="cx">
</span><span class="lines">@@ -204,10 +207,10 @@
</span><span class="cx"> let address = i;
</span><span class="cx"> let result = foo(value, address);
</span><span class="cx"> let expectedValue = (value & ((2**8) - 1));
</span><del>- assert(result === expectedValue);
</del><ins>+ assert.truthy(result === expectedValue);
</ins><span class="cx"> let arrayBuffer = memory.buffer;
</span><span class="cx"> let buffer = new Uint8Array(arrayBuffer);
</span><del>- assert(buffer[i] === expectedValue);
</del><ins>+ assert.truthy(buffer[i] === expectedValue);
</ins><span class="cx"> }
</span><span class="cx"> });
</span><span class="cx">
</span><span class="lines">@@ -241,14 +244,14 @@
</span><span class="cx"> const bytes = memoryDescription.initial * pageSize;
</span><span class="cx"> for (let i = 0; i < (bytes/4); i++) {
</span><span class="cx"> let value = i + 1 + .0128213781289;
</span><del>- assert(value !== Math.fround(value));
</del><ins>+ assert.truthy(value !== Math.fround(value));
</ins><span class="cx"> let address = i * 4;
</span><span class="cx"> let result = foo(value, address);
</span><span class="cx"> let expectedValue = Math.fround(result);
</span><del>- assert(result === expectedValue);
</del><ins>+ assert.truthy(result === expectedValue);
</ins><span class="cx"> let arrayBuffer = memory.buffer;
</span><span class="cx"> let buffer = new Float32Array(arrayBuffer);
</span><del>- assert(buffer[i] === expectedValue);
</del><ins>+ assert.truthy(buffer[i] === expectedValue);
</ins><span class="cx"> }
</span><span class="cx"> });
</span><span class="cx">
</span><span class="lines">@@ -285,10 +288,10 @@
</span><span class="cx"> let address = i * 8;
</span><span class="cx"> let result = foo(value, address);
</span><span class="cx"> let expectedValue = result;
</span><del>- assert(result === expectedValue);
</del><ins>+ assert.truthy(result === expectedValue);
</ins><span class="cx"> let arrayBuffer = memory.buffer;
</span><span class="cx"> let buffer = new Float64Array(arrayBuffer);
</span><del>- assert(buffer[i] === expectedValue);
</del><ins>+ assert.truthy(buffer[i] === expectedValue);
</ins><span class="cx"> }
</span><span class="cx"> });
</span><span class="cx">
</span><span class="lines">@@ -320,13 +323,13 @@
</span><span class="cx"> try {
</span><span class="cx"> new WebAssembly.Instance(module, instanceObj);
</span><span class="cx"> } catch(e) {
</span><del>- assert(e instanceof TypeError);
</del><ins>+ assert.truthy(e instanceof TypeError);
</ins><span class="cx"> threw = true;
</span><span class="cx"> if (expectedError) {
</span><del>- assert(e.message === expectedError);
</del><ins>+ assert.truthy(e.message === expectedError);
</ins><span class="cx"> }
</span><span class="cx"> }
</span><del>- assert(threw);
</del><ins>+ assert.truthy(threw);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> testMemImportError(20);
</span><span class="lines">@@ -363,17 +366,7 @@
</span><span class="cx"> const module = new WebAssembly.Module(bin);
</span><span class="cx">
</span><span class="cx"> function testMemImportError(instanceObj, expectedError) {
</span><del>- let threw = false;
- try {
- new WebAssembly.Instance(module, instanceObj);
- } catch(e) {
- assert(e instanceof TypeError);
- threw = true;
- if (expectedError) {
- assert(e.message === expectedError);
- }
- }
- assert(threw);
</del><ins>+ assert.throws(() => new WebAssembly.Instance(module, instanceObj), TypeError, expectedError);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> testMemImportError({imp: { memory: new WebAssembly.Memory({initial: 19, maximum: 25}) } }, "Memory import provided an 'initial' that is too small");
</span><span class="lines">@@ -383,3 +376,41 @@
</span><span class="cx"> new WebAssembly.Instance(module, {imp: {memory: new WebAssembly.Memory({initial:20})}});
</span><span class="cx"> new WebAssembly.Instance(module, {imp: {memory: new WebAssembly.Memory({initial:20, maximum:20})}});
</span><span class="cx"> });
</span><ins>+
+{
+ const builder = (new Builder())
+ .Type().End()
+ .Import().Memory("imp", "memory", {initial: 20}).End()
+ .Function().End()
+ .Export()
+ .Memory("memory", 0)
+ .Memory("memory2", 0)
+ .End()
+ .Code()
+ .End();
+ const bin = builder.WebAssembly().get();
+ const module = new WebAssembly.Module(bin);
+ const memory = new WebAssembly.Memory({initial: 20});
+ const instance = new WebAssembly.Instance(module, {imp: {memory}});
+ assert.truthy(memory === instance.exports.memory);
+ assert.truthy(memory === instance.exports.memory2);
+}
+
+{
+ const builder = (new Builder())
+ .Type().End()
+ .Function().End()
+ .Memory().InitialMaxPages(20, 25).End()
+ .Export()
+ .Memory("memory", 0)
+ .Memory("memory2", 0)
+ .End()
+ .Code()
+ .End();
+ const bin = builder.WebAssembly().get();
+ const module = new WebAssembly.Module(bin);
+ const instance = new WebAssembly.Instance(module);
+ assert.eq(instance.exports.memory, instance.exports.memory2);
+ assert.eq(instance.exports.memory.buffer.byteLength, 20 * pageSize);
+ assert.truthy(instance.exports.memory instanceof WebAssembly.Memory);
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (209849 => 209850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-12-15 02:31:37 UTC (rev 209849)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-12-15 03:30:44 UTC (rev 209850)
</span><span class="lines">@@ -1,3 +1,32 @@
</span><ins>+2016-12-14 Saam Barati <sbarati@apple.com>
+
+ WebAssembly: Add various low hanging fruit that will allow us to run the LLVM torture tests in Wasm
+ https://bugs.webkit.org/show_bug.cgi?id=165883
+
+ Reviewed by Keith Miller.
+
+ This patch implements some low hanging fruit:
+ - Exporting Table
+ - Exporting Memory
+ - Load16 with zero extension to both 32 and 64 bit values.
+ - Fixes Unreachable to emit code that will prevent B3 from having a validation error.
+
+ * wasm/WasmB3IRGenerator.cpp:
+ (JSC::Wasm::B3IRGenerator::addUnreachable):
+ (JSC::Wasm::sizeOfLoadOp):
+ (JSC::Wasm::B3IRGenerator::emitLoadOp):
+ * wasm/WasmFunctionParser.h:
+ (JSC::Wasm::FunctionParser<Context>::parseExpression):
+ * wasm/WasmModuleParser.cpp:
+ (JSC::Wasm::ModuleParser::parseExport):
+ * wasm/WasmValidate.cpp:
+ (JSC::Wasm::Validate::addUnreachable):
+ * wasm/js/WebAssemblyInstanceConstructor.cpp:
+ (JSC::constructJSWebAssemblyInstance):
+ * wasm/js/WebAssemblyModuleRecord.cpp:
+ (JSC::WebAssemblyModuleRecord::finishCreation):
+ (JSC::WebAssemblyModuleRecord::link):
+
</ins><span class="cx"> 2016-12-14 Yusuke Suzuki <utatane.tea@gmail.com>
</span><span class="cx">
</span><span class="cx"> Update ModuleLoader code by using the latest builtin primitives
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmB3IRGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp (209849 => 209850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp        2016-12-15 02:31:37 UTC (rev 209849)
+++ trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp        2016-12-15 03:30:44 UTC (rev 209850)
</span><span class="lines">@@ -178,6 +178,7 @@
</span><span class="cx"> // Calls
</span><span class="cx"> bool WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature*, Vector<ExpressionType>& args, ExpressionType& result);
</span><span class="cx"> bool WARN_UNUSED_RETURN addCallIndirect(const Signature*, Vector<ExpressionType>& args, ExpressionType& result);
</span><ins>+ void addUnreachable();
</ins><span class="cx">
</span><span class="cx"> void dump(const Vector<ControlEntry>& controlStack, const ExpressionList& expressionStack);
</span><span class="cx">
</span><span class="lines">@@ -326,6 +327,15 @@
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void B3IRGenerator::addUnreachable()
+{
+ B3::PatchpointValue* unreachable = m_currentBlock->appendNew<B3::PatchpointValue>(m_proc, B3::Void, Origin());
+ unreachable->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+ jit.breakpoint();
+ });
+ unreachable->effects.terminal = true;
+}
+
</ins><span class="cx"> bool B3IRGenerator::setLocal(uint32_t index, ExpressionType value)
</span><span class="cx"> {
</span><span class="cx"> ASSERT(m_locals[index]);
</span><span class="lines">@@ -367,6 +377,8 @@
</span><span class="cx"> return 1;
</span><span class="cx"> case LoadOpType::I32Load16S:
</span><span class="cx"> case LoadOpType::I64Load16S:
</span><ins>+ case LoadOpType::I32Load16U:
+ case LoadOpType::I64Load16U:
</ins><span class="cx"> return 2;
</span><span class="cx"> case LoadOpType::I32Load:
</span><span class="cx"> case LoadOpType::I64Load32S:
</span><span class="lines">@@ -376,9 +388,6 @@
</span><span class="cx"> case LoadOpType::I64Load:
</span><span class="cx"> case LoadOpType::F64Load:
</span><span class="cx"> return 8;
</span><del>- case LoadOpType::I32Load16U:
- case LoadOpType::I64Load16U:
- break;
</del><span class="cx"> }
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="lines">@@ -438,11 +447,21 @@
</span><span class="cx"> return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Double, origin, pointer);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- // B3 doesn't support Load16Z yet.
- case LoadOpType::I32Load16U:
- case LoadOpType::I64Load16U:
- break;
</del><ins>+ // FIXME: B3 doesn't support Load16Z yet. We should lower to that value when
+ // it's added. https://bugs.webkit.org/show_bug.cgi?id=165884
+ case LoadOpType::I32Load16U: {
+ Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load16S, origin, pointer, offset);
+ return m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(), value,
+ m_currentBlock->appendNew<Const32Value>(m_proc, Origin(), 0x0000ffff));
</ins><span class="cx"> }
</span><ins>+ case LoadOpType::I64Load16U: {
+ Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load16S, origin, pointer, offset);
+ Value* partialResult = m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(), value,
+ m_currentBlock->appendNew<Const32Value>(m_proc, Origin(), 0x0000ffff));
+
+ return m_currentBlock->appendNew<Value>(m_proc, ZExt32, Origin(), partialResult);
+ }
+ }
</ins><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmFunctionParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h (209849 => 209850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h        2016-12-15 02:31:37 UTC (rev 209849)
+++ trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h        2016-12-15 03:30:44 UTC (rev 209850)
</span><span class="lines">@@ -566,6 +566,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::Unreachable: {
</span><ins>+ m_context.addUnreachable();
</ins><span class="cx"> m_unreachableBlocks = 1;
</span><span class="cx"> return true;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmModuleParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp (209849 => 209850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp        2016-12-15 02:31:37 UTC (rev 209849)
+++ trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp        2016-12-15 03:30:44 UTC (rev 209850)
</span><span class="lines">@@ -511,11 +511,17 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case External::Table: {
</span><del>- // FIXME https://bugs.webkit.org/show_bug.cgi?id=165782
</del><ins>+ if (!m_hasTable)
+ return false;
+ if (exp.kindIndex != 0)
+ return false;
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case External::Memory: {
</span><del>- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=165671
</del><ins>+ if (!m_module->memory)
+ return false;
+ if (exp.kindIndex != 0)
+ return false;
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case External::Global: {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmValidatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp (209849 => 209850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp        2016-12-15 02:31:37 UTC (rev 209849)
+++ trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp        2016-12-15 03:30:44 UTC (rev 209850)
</span><span class="lines">@@ -114,6 +114,8 @@
</span><span class="cx"> bool WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);
</span><span class="cx"> bool WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);
</span><span class="cx">
</span><ins>+ void addUnreachable() { }
+
</ins><span class="cx"> // Calls
</span><span class="cx"> bool WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature*, const Vector<ExpressionType>& args, ExpressionType& result);
</span><span class="cx"> bool WARN_UNUSED_RETURN addCallIndirect(const Signature*, const Vector<ExpressionType>& args, ExpressionType& result);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyInstanceConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp (209849 => 209850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp        2016-12-15 02:31:37 UTC (rev 209849)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp        2016-12-15 03:30:44 UTC (rev 209850)
</span><span class="lines">@@ -245,7 +245,7 @@
</span><span class="cx"> if (!!moduleInformation.tableInformation && !hasTableImport) {
</span><span class="cx"> RELEASE_ASSERT(!moduleInformation.tableInformation.isImport());
</span><span class="cx"> // We create a Table when it's a Table definition.
</span><del>- JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(),
</del><ins>+ JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyTableStructure(),
</ins><span class="cx"> moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum());
</span><span class="cx"> // We should always be able to allocate a JSWebAssemblyTable we've defined.
</span><span class="cx"> // If it's defined to be too large, we should have thrown a validation error.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyModuleRecordcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp (209849 => 209850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp        2016-12-15 02:31:37 UTC (rev 209849)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp        2016-12-15 03:30:44 UTC (rev 209850)
</span><span class="lines">@@ -70,27 +70,8 @@
</span><span class="cx"> {
</span><span class="cx"> Base::finishCreation(exec, vm);
</span><span class="cx"> ASSERT(inherits(info()));
</span><del>- for (const auto& exp : moduleInformation.exports) {
- switch (exp.kind) {
- case Wasm::External::Function: {
- addExportEntry(ExportEntry::createLocal(exp.field, exp.field));
- break;
- }
- case Wasm::External::Table: {
- // FIXME https://bugs.webkit.org/show_bug.cgi?id=165782
- break;
- }
- case Wasm::External::Memory: {
- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=165671
- break;
- }
- case Wasm::External::Global: {
- // In the MVP, only immutable global variables can be exported.
- addExportEntry(ExportEntry::createLocal(exp.field, exp.field));
- break;
- }
- }
- }
</del><ins>+ for (const auto& exp : moduleInformation.exports)
+ addExportEntry(ExportEntry::createLocal(exp.field, exp.field));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void WebAssemblyModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
</span><span class="lines">@@ -146,14 +127,21 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case Wasm::External::Table: {
</span><del>- // FIXME https://bugs.webkit.org/show_bug.cgi?id=165782
</del><ins>+ // This should be guaranteed by module verification.
+ RELEASE_ASSERT(instance->table());
+ ASSERT(exp.kindIndex == 0);
+
+ exportedValue = instance->table();
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case Wasm::External::Memory: {
</span><del>- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=165671
</del><ins>+ // This should be guaranteed by module verification.
+ RELEASE_ASSERT(instance->memory());
+ ASSERT(exp.kindIndex == 0);
+
+ exportedValue = instance->memory();
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><del>-
</del><span class="cx"> case Wasm::External::Global: {
</span><span class="cx"> // Assert: the global is immutable by MVP validation constraint.
</span><span class="cx"> const Wasm::Global& global = moduleInformation.globals[exp.kindIndex];
</span></span></pre>
</div>
</div>
</body>
</html>