<!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>[209771] 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/209771">209771</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2016-12-13 12:32:40 -0800 (Tue, 13 Dec 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>WebAssembly: implement the table section and table import
https://bugs.webkit.org/show_bug.cgi?id=165716
Reviewed by Keith Miller.
JSTests:
* wasm/Builder.js:
(const._importMemoryContinuation):
(const._importTableContinuation):
(export.default.Builder.prototype._registerSectionBuilders.switch.case.string_appeared_here.this.section):
(const._importMemoryContinuation.section): Deleted.
(const): Deleted.
(const._importMemoryContinuation.assert): Deleted.
* wasm/Builder_WebAssemblyBinary.js:
(const.putResizableLimits):
(const.putTable):
(const.emitters.Import):
(const.emitters.Table):
* wasm/function-tests/call-indirect-params.js:
* wasm/function-tests/call-indirect.js:
* wasm/function-tests/table-basic-2.js: Added.
(import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.makeInstance):
(func):
* wasm/function-tests/table-basic.js: Added.
(import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.makeInstance):
* wasm/js-api/call-indirect-results.js:
(const.wasmModuleWhichImportJS): Deleted.
(MonomorphicImport): Deleted.
* wasm/js-api/call-indirect.js:
(const.wasmModuleWhichImportJS):
(const.makeTable):
(Polyphic2Import):
(VirtualImport):
(MonomorphicImport): Deleted.
* wasm/js-api/table.js: Added.
(assertBadBinary):
(assert.truthy):
(assertBadTable):
(assertBadTableImport):
(assertBadBinary.assertBadTableInstance):
(assertBadTableInstance):
(new.WebAssembly.Table):
* wasm/js-api/test_basic_api.js:
(const.c.in.constructorProperties.switch):
Source/JavaScriptCore:
This patch implements the Table space for wasm:
https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#table-section
It only implements defining and importing a table. The bulk
of this patch is implementing the various wasm Table prototype
methods and the underlying Table object:
https://github.com/WebAssembly/design/blob/master/JS.md#webassemblytable-constructor
This patch also fixes a bug in our implementation with call_indirect.
We initially implemented call_indirect as a way to call functions that
are imported or defined in the module. This was the wrong
interpretation of the spec. Instead, call_indirect can only index into
the table index space.
* JavaScriptCore.xcodeproj/project.pbxproj:
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::B3IRGenerator::addCallIndirect):
(JSC::Wasm::parseAndCompile):
* wasm/WasmFormat.h:
(JSC::Wasm::TableInformation::TableInformation):
(JSC::Wasm::TableInformation::operator bool):
(JSC::Wasm::TableInformation::isImport):
(JSC::Wasm::TableInformation::initial):
(JSC::Wasm::TableInformation::maximum):
(JSC::Wasm::CallableFunction::CallableFunction):
* wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser<Context>::parseExpression):
* wasm/WasmModuleParser.cpp:
(JSC::Wasm::ModuleParser::parseImport):
(JSC::Wasm::ModuleParser::parseResizableLimits):
(JSC::Wasm::ModuleParser::parseTableHelper):
(JSC::Wasm::ModuleParser::parseTable):
(JSC::Wasm::ModuleParser::parseMemoryHelper):
(JSC::Wasm::ModuleParser::parseExport):
* wasm/WasmModuleParser.h:
* wasm/js/JSWebAssemblyHelpers.h: Added.
(JSC::toNonWrappingUint32):
* wasm/js/JSWebAssemblyInstance.cpp:
(JSC::JSWebAssemblyInstance::visitChildren):
* wasm/js/JSWebAssemblyInstance.h:
(JSC::JSWebAssemblyInstance::table):
(JSC::JSWebAssemblyInstance::setTable):
(JSC::JSWebAssemblyInstance::offsetOfTable):
* wasm/js/JSWebAssemblyTable.cpp:
(JSC::JSWebAssemblyTable::create):
(JSC::JSWebAssemblyTable::JSWebAssemblyTable):
(JSC::JSWebAssemblyTable::visitChildren):
(JSC::JSWebAssemblyTable::grow):
(JSC::JSWebAssemblyTable::clearFunction):
(JSC::JSWebAssemblyTable::setFunction):
* wasm/js/JSWebAssemblyTable.h:
(JSC::JSWebAssemblyTable::maximum):
(JSC::JSWebAssemblyTable::size):
(JSC::JSWebAssemblyTable::getFunction):
(JSC::JSWebAssemblyTable::offsetOfSize):
(JSC::JSWebAssemblyTable::offsetOfFunctions):
(JSC::JSWebAssemblyTable::isValidSize):
* wasm/js/WebAssemblyFunction.cpp:
(JSC::WebAssemblyFunction::call):
(JSC::WebAssemblyFunction::create):
(JSC::WebAssemblyFunction::visitChildren):
(JSC::WebAssemblyFunction::finishCreation):
* wasm/js/WebAssemblyFunction.h:
(JSC::WebAssemblyFunction::signature):
(JSC::WebAssemblyFunction::wasmEntrypoint):
(JSC::WebAssemblyFunction::webAssemblyCallee): Deleted.
* wasm/js/WebAssemblyInstanceConstructor.cpp:
(JSC::constructJSWebAssemblyInstance):
* wasm/js/WebAssemblyMemoryConstructor.cpp:
(JSC::constructJSWebAssemblyMemory):
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::finishCreation):
(JSC::WebAssemblyModuleRecord::link):
* wasm/js/WebAssemblyTableConstructor.cpp:
(JSC::constructJSWebAssemblyTable):
* wasm/js/WebAssemblyTablePrototype.cpp:
(JSC::getTable):
(JSC::webAssemblyTableProtoFuncLength):
(JSC::webAssemblyTableProtoFuncGrow):
(JSC::webAssemblyTableProtoFuncGet):
(JSC::webAssemblyTableProtoFuncSet):
(JSC::WebAssemblyTablePrototype::create):
(JSC::WebAssemblyTablePrototype::finishCreation):
* wasm/js/WebAssemblyTablePrototype.h:</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="#trunkJSTestswasmfunctiontestscallindirectparamsjs">trunk/JSTests/wasm/function-tests/call-indirect-params.js</a></li>
<li><a href="#trunkJSTestswasmfunctiontestscallindirectjs">trunk/JSTests/wasm/function-tests/call-indirect.js</a></li>
<li><a href="#trunkJSTestswasmjsapicallindirectresultsjs">trunk/JSTests/wasm/js-api/call-indirect-results.js</a></li>
<li><a href="#trunkJSTestswasmjsapicallindirectjs">trunk/JSTests/wasm/js-api/call-indirect.js</a></li>
<li><a href="#trunkJSTestswasmjsapitest_basic_apijs">trunk/JSTests/wasm/js-api/test_basic_api.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmB3IRGeneratorcpp">trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmFormath">trunk/Source/JavaScriptCore/wasm/WasmFormat.h</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="#trunkSourceJavaScriptCorewasmWasmModuleParserh">trunk/Source/JavaScriptCore/wasm/WasmModuleParser.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsJSWebAssemblyInstancecpp">trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsJSWebAssemblyInstanceh">trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsJSWebAssemblyTablecpp">trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsJSWebAssemblyTableh">trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyFunctioncpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyFunctionh">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyInstanceConstructorcpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyMemoryConstructorcpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryConstructor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyModuleRecordcpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyTableConstructorcpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyTableConstructor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyTablePrototypecpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyTablePrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyTablePrototypeh">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyTablePrototype.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestswasmfunctionteststablebasic2js">trunk/JSTests/wasm/function-tests/table-basic-2.js</a></li>
<li><a href="#trunkJSTestswasmfunctionteststablebasicjs">trunk/JSTests/wasm/function-tests/table-basic.js</a></li>
<li><a href="#trunkJSTestswasmjsapitablejs">trunk/JSTests/wasm/js-api/table.js</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsJSWebAssemblyHelpersh">trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyHelpers.h</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/ChangeLog        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -1,3 +1,49 @@
</span><ins>+2016-12-13 Saam Barati <sbarati@apple.com>
+
+ WebAssembly: implement the table section and table import
+ https://bugs.webkit.org/show_bug.cgi?id=165716
+
+ Reviewed by Keith Miller.
+
+ * wasm/Builder.js:
+ (const._importMemoryContinuation):
+ (const._importTableContinuation):
+ (export.default.Builder.prototype._registerSectionBuilders.switch.case.string_appeared_here.this.section):
+ (const._importMemoryContinuation.section): Deleted.
+ (const): Deleted.
+ (const._importMemoryContinuation.assert): Deleted.
+ * wasm/Builder_WebAssemblyBinary.js:
+ (const.putResizableLimits):
+ (const.putTable):
+ (const.emitters.Import):
+ (const.emitters.Table):
+ * wasm/function-tests/call-indirect-params.js:
+ * wasm/function-tests/call-indirect.js:
+ * wasm/function-tests/table-basic-2.js: Added.
+ (import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.makeInstance):
+ (func):
+ * wasm/function-tests/table-basic.js: Added.
+ (import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.makeInstance):
+ * wasm/js-api/call-indirect-results.js:
+ (const.wasmModuleWhichImportJS): Deleted.
+ (MonomorphicImport): Deleted.
+ * wasm/js-api/call-indirect.js:
+ (const.wasmModuleWhichImportJS):
+ (const.makeTable):
+ (Polyphic2Import):
+ (VirtualImport):
+ (MonomorphicImport): Deleted.
+ * wasm/js-api/table.js: Added.
+ (assertBadBinary):
+ (assert.truthy):
+ (assertBadTable):
+ (assertBadTableImport):
+ (assertBadBinary.assertBadTableInstance):
+ (assertBadTableInstance):
+ (new.WebAssembly.Table):
+ * wasm/js-api/test_basic_api.js:
+ (const.c.in.constructorProperties.switch):
+
</ins><span class="cx"> 2016-12-13 Commit Queue <commit-queue@webkit.org>
</span><span class="cx">
</span><span class="cx"> Unreviewed, rolling out r209725.
</span></span></pre></div>
<a id="trunkJSTestswasmBuilderjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/Builder.js (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/Builder.js        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/Builder.js        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -103,14 +103,23 @@
</span><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> const _importMemoryContinuation = (builder, section, nextBuilder) => {
</span><del>- return (module, field, memoryDescription) => {
- assert.isString(module, `Import function module should be a string, got "${module}"`);
- assert.isString(field, `Import function field should be a string, got "${field}"`);
- section.data.push({module, field, kind: "Memory", memoryDescription});
</del><ins>+ return (module, field, {initial, maximum}) => {
+ assert.isString(module, `Import Memory module should be a string, got "${module}"`);
+ assert.isString(field, `Import Memory field should be a string, got "${field}"`);
+ section.data.push({module, field, kind: "Memory", memoryDescription: {initial, maximum}});
</ins><span class="cx"> return nextBuilder;
</span><span class="cx"> };
</span><span class="cx"> };
</span><span class="cx">
</span><ins>+const _importTableContinuation = (builder, section, nextBuilder) => {
+ return (module, field, {initial, maximum, element}) => {
+ assert.isString(module, `Import Table module should be a string, got "${module}"`);
+ assert.isString(field, `Import Table field should be a string, got "${field}"`);
+ section.data.push({module, field, kind: "Table", tableDescription: {initial, maximum, element}});
+ return nextBuilder;
+ };
+};
+
</ins><span class="cx"> const _exportFunctionContinuation = (builder, section, nextBuilder) => {
</span><span class="cx"> return (field, index, type) => {
</span><span class="cx"> assert.isString(field, `Export function field should be a string, got "${field}"`);
</span><span class="lines">@@ -299,12 +308,31 @@
</span><span class="cx">
</span><span class="cx"> if (typeof(signature) === "undefined")
</span><span class="cx"> signature = { params: [] };
</span><del>- assert.hasObjectProperty(signature, "params", `Expect function signature to be an object with a "params" field, got "${signature}"`);
- const [params, ret] = _normalizeFunctionSignature(signature.params, signature.ret);
- signature = { params: params, ret: ret };
</del><ins>+
+ let type;
+ let params;
+ if (typeof signature === "object") {
+ assert.hasObjectProperty(signature, "params", `Expect function signature to be an object with a "params" field, got "${signature}"`);
+ let ret;
+ ([params, ret] = _normalizeFunctionSignature(signature.params, signature.ret));
+ signature = {params, ret};
+ type = _maybeRegisterType(builder, signature);
+ } else {
+ assert.truthy(typeof signature === "number");
+ const typeSection = builder._getSection("Type");
+ assert.truthy(!!typeSection);
+ // FIXME: we should allow indices that exceed this to be able to
+ // test JSCs validator is correct. https://bugs.webkit.org/show_bug.cgi?id=165786
+ assert.truthy(signature < typeSection.data.length);
+ type = signature;
+ signature = typeSection.data[signature];
+ assert.hasObjectProperty(signature, "params", `Expect function signature to be an object with a "params" field, got "${signature}"`);
+ params = signature.params;
+ }
+
</ins><span class="cx"> const func = {
</span><span class="cx"> name: functionName,
</span><del>- type: _maybeRegisterType(builder, signature),
</del><ins>+ type,
</ins><span class="cx"> signature: signature,
</span><span class="cx"> locals: params.concat(locals), // Parameters are the first locals.
</span><span class="cx"> parameterCount: params.length,
</span><span class="lines">@@ -379,11 +407,11 @@
</span><span class="cx"> const s = this._addSection(section);
</span><span class="cx"> const importBuilder = {
</span><span class="cx"> End: () => this,
</span><del>- Table: () => { throw new Error(`Unimplemented: import table`); },
</del><span class="cx"> Global: () => { throw new Error(`Unimplemented: import global`); },
</span><span class="cx"> };
</span><span class="cx"> importBuilder.Function = _importFunctionContinuation(this, s, importBuilder);
</span><span class="cx"> importBuilder.Memory = _importMemoryContinuation(this, s, importBuilder);
</span><ins>+ importBuilder.Table = _importTableContinuation(this, s, importBuilder);
</ins><span class="cx"> return importBuilder;
</span><span class="cx"> };
</span><span class="cx"> break;
</span><span class="lines">@@ -400,8 +428,17 @@
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case "Table":
</span><del>- // FIXME Implement table https://bugs.webkit.org/show_bug.cgi?id=164135
- this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
</del><ins>+ this[section] = function() {
+ const s = this._addSection(section);
+ const exportBuilder = {
+ End: () => this,
+ Table: ({initial, maximum, element}) => {
+ s.data.push({tableDescription: {initial, maximum, element}});
+ return exportBuilder;
+ }
+ };
+ return exportBuilder;
+ };
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case "Memory":
</span></span></pre></div>
<a id="trunkJSTestswasmBuilder_WebAssemblyBinaryjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/Builder_WebAssemblyBinary.js (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/Builder_WebAssemblyBinary.js        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/Builder_WebAssemblyBinary.js        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -29,6 +29,28 @@
</span><span class="cx">
</span><span class="cx"> const put = (bin, type, value) => bin[type](value);
</span><span class="cx">
</span><ins>+const putResizableLimits = (bin, initial, maximum) => {
+ assert.truthy(typeof initial === "number", "We expect 'initial' to be an integer");
+ let hasMaximum = 0;
+ if (typeof maximum === "number") {
+ hasMaximum = 1;
+ } else {
+ assert.truthy(typeof maximum === "undefined", "We expect 'maximum' to be an integer if it's defined");
+ }
+
+ put(bin, "varuint1", hasMaximum);
+ put(bin, "varuint32", initial);
+ if (hasMaximum)
+ put(bin, "varuint32", maximum);
+};
+
+const putTable = (bin, {initial, maximum, element}) => {
+ assert.truthy(WASM.isValidType(element), "We expect 'element' to be a valid type. It was: " + element);
+ put(bin, "varint7", WASM.typeValue[element]);
+
+ putResizableLimits(bin, initial, maximum);
+};
+
</ins><span class="cx"> const emitters = {
</span><span class="cx"> Type: (section, bin) => {
</span><span class="cx"> put(bin, "varuint32", section.data.length);
</span><span class="lines">@@ -57,23 +79,13 @@
</span><span class="cx"> put(bin, "varuint32", entry.type);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case "Table": throw new Error(`Not yet implemented`);
</del><ins>+ case "Table": {
+ putTable(bin, entry.tableDescription);
+ break;
+ }
</ins><span class="cx"> case "Memory": {
</span><span class="cx"> let {initial, maximum} = entry.memoryDescription;
</span><del>- assert.truthy(typeof initial === "number", "We expect 'initial' to be a number");
- initial |= 0;
- let hasMaximum = 0;
- if (typeof maximum === "number") {
- maximum |= 0;
- hasMaximum = 1;
- } else {
- assert.truthy(typeof maximum === "undefined", "We expect 'maximum' to be a number if it's defined");
- }
-
- put(bin, "varuint1", hasMaximum);
- put(bin, "varuint32", initial);
- if (hasMaximum)
- put(bin, "varuint32", maximum);
</del><ins>+ putResizableLimits(bin, initial, maximum);
</ins><span class="cx"> break;
</span><span class="cx"> };
</span><span class="cx"> case "Global": throw new Error(`Not yet implemented`);
</span><span class="lines">@@ -87,7 +99,12 @@
</span><span class="cx"> put(bin, "varuint32", signature);
</span><span class="cx"> },
</span><span class="cx">
</span><del>- Table: (section, bin) => { throw new Error(`Not yet implemented`); },
</del><ins>+ Table: (section, bin) => {
+ put(bin, "varuint32", section.data.length);
+ for (const {tableDescription} of section.data) {
+ putTable(bin, tableDescription);
+ }
+ },
</ins><span class="cx">
</span><span class="cx"> Memory: (section, bin) => {
</span><span class="cx"> // Flags, currently can only be [0,1]
</span></span></pre></div>
<a id="trunkJSTestswasmfunctiontestscallindirectparamsjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/function-tests/call-indirect-params.js (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/function-tests/call-indirect-params.js        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/function-tests/call-indirect-params.js        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -1,28 +0,0 @@
</span><del>-import Builder from '../Builder.js'
-
-const b = new Builder();
-b.Type().End()
- .Function().End()
- .Code()
-
- .Function({ params: ["i32"], ret: "i32" })
- .I32Const(1)
- .End()
-
- .Function({ params: ["i32"], ret: "i32" })
- .GetLocal(0)
- .End()
-
- .Function({ params: ["i32", "i32"], ret: "i32" })
- .GetLocal(1)
- .GetLocal(0)
- .CallIndirect(0, 0)
- .End()
-
-
-const bin = b.WebAssembly()
-bin.trim();
-testWasmModuleFunctions(bin.get(), 3, [], [],
- [[{ type: "i32", value: 1 }, [{ type: "i32", value: 0 }, { type: "i32", value: 4 }]],
- [{ type: "i32", value: 4 }, [{ type: "i32", value: 1 }, { type: "i32", value: 4 }]],
- ]);
</del></span></pre></div>
<a id="trunkJSTestswasmfunctiontestscallindirectjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/function-tests/call-indirect.js (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/function-tests/call-indirect.js        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/function-tests/call-indirect.js        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -1,27 +0,0 @@
</span><del>-import Builder from '../Builder.js'
-
-const b = new Builder();
-b.Type().End()
- .Function().End()
- .Code()
-
- .Function({ params: [], ret: "i32" })
- .I32Const(1)
- .End()
-
- .Function({ params: [], ret: "i32" })
- .I32Const(2)
- .End()
-
- .Function({ params: ["i32"], ret: "i32" })
- .GetLocal(0)
- .CallIndirect(0, 0)
- .End()
-
-
-const bin = b.WebAssembly()
-bin.trim();
-testWasmModuleFunctions(bin.get(), 3, [], [],
- [[{ type: "i32", value: 1 }, [{ type: "i32", value: 0 }]],
- [{ type: "i32", value: 1 }, [{ type: "i32", value: 0 }]],
- ]);
</del></span></pre></div>
<a id="trunkJSTestswasmfunctionteststablebasic2js"></a>
<div class="addfile"><h4>Added: trunk/JSTests/wasm/function-tests/table-basic-2.js (0 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/function-tests/table-basic-2.js         (rev 0)
+++ trunk/JSTests/wasm/function-tests/table-basic-2.js        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -0,0 +1,57 @@
</span><ins>+import Builder from '../Builder.js'
+import * as assert from '../assert.js'
+
+function makeInstance(func) {
+ const builder = new Builder()
+ .Type()
+ .Func(["i32", "i32"], "i32")
+ .Func(["i32"], "i32")
+ .End()
+ .Import()
+ .Table("imp", "table", {initial: 20, element: "anyfunc"})
+ .Function("imp", "func", { params: ["i32"], ret: "i32" })
+ .End()
+ .Function().End()
+ .Export()
+ .Function("foo")
+ .Function("bar")
+ .End()
+ .Code()
+ .Function("foo", 0 /*['i32', 'i32'] => 'i32'*/)
+ .GetLocal(1) // parameter to call
+ .GetLocal(0) // call index
+ .CallIndirect(1, 0) // calling function of type ['i32'] => 'i32'
+ .Return()
+ .End()
+ .Function("bar", 1 /*['i32'] => 'i32'*/)
+ .GetLocal(0)
+ .Call(0)
+ .Return()
+ .End()
+ .End();
+
+
+ const bin = builder.WebAssembly().get();
+ const module = new WebAssembly.Module(bin);
+ const table = new WebAssembly.Table({initial: 20, element: "anyfunc"});
+ return {instance: new WebAssembly.Instance(module, {imp: {table, func}}), table};
+}
+
+{
+ let i;
+ function func(x) {
+ if (x !== i)
+ throw new Error("Bad argument");
+ return x + 44;
+ }
+ const {instance, table} = makeInstance(func);
+ const exports = instance.exports;
+ const foo = exports.foo;
+ table.set(0, exports.bar);
+ assert.eq(table.get(0), exports.bar);
+
+ for (i = 0; i < 10000; i++) {
+ if (foo(0, i) !== i + 44)
+ throw new Error("Bad call indirect");
+ }
+}
</ins></span></pre></div>
<a id="trunkJSTestswasmfunctionteststablebasicjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/wasm/function-tests/table-basic.js (0 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/function-tests/table-basic.js         (rev 0)
+++ trunk/JSTests/wasm/function-tests/table-basic.js        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -0,0 +1,67 @@
</span><ins>+import Builder from '../Builder.js'
+import * as assert from '../assert.js'
+
+function makeInstance() {
+ const builder = new Builder()
+ .Type()
+ .Func(["i32", "i32"], "i32")
+ .Func(["i32"], "i32")
+ .End()
+ .Import()
+ .Table("imp", "table", {initial: 20, element: "anyfunc"})
+ .End()
+ .Function().End()
+ .Export()
+ .Function("foo")
+ .Function("bar")
+ .End()
+ .Code()
+ .Function("foo", 0 /*['i32', 'i32'] => 'i32'*/)
+ .GetLocal(1) // parameter to call
+ .GetLocal(0) // call index
+ .CallIndirect(1, 0) // calling function of type ['i32'] => 'i32'
+ .Return()
+ .End()
+ .Function("bar", 1 /*['i32'] => 'i32'*/)
+ .GetLocal(0)
+ .I32Const(42)
+ .I32Add()
+ .Return()
+ .End()
+ .End();
+
+
+ const bin = builder.WebAssembly().get();
+ const module = new WebAssembly.Module(bin);
+ const table = new WebAssembly.Table({initial: 20, element: "anyfunc"});
+ return {instance: new WebAssembly.Instance(module, {imp: {table}}), table};
+}
+
+{
+ const {instance, table} = makeInstance();
+ const exports = instance.exports;
+ const foo = exports.foo;
+ table.set(0, exports.bar);
+ assert.eq(table.get(0), exports.bar);
+
+ for (let i = 0; i < 1000; i++) {
+ if (foo(0, i) !== i + 42)
+ throw new Error("Bad call indirect");
+ }
+}
+
+// FIXME: make this work cross module. The reason it doesn't
+// now is that we don't unique Signature*.
+// https://bugs.webkit.org/show_bug.cgi?id=165511
+/*
+{
+ const {instance, table} = makeInstance();
+ const foo = instance.exports.foo;
+ //table.set(0, makeInstance().instance.exports.bar); // Cross instance function.
+
+ for (let i = 0; i < 1000; i++) {
+ if (foo(0, i) !== i + 42)
+ throw new Error("Bad call indirect");
+ }
+}
+*/
</ins></span></pre></div>
<a id="trunkJSTestswasmjsapicallindirectresultsjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/js-api/call-indirect-results.js (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/call-indirect-results.js        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/js-api/call-indirect-results.js        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -1,41 +0,0 @@
</span><del>-import * as assert from '../assert.js';
-import Builder from '../Builder.js';
-
-const wasmModuleWhichImportJS = () => {
- const builder = (new Builder())
- .Type().End()
- .Import()
- .Function("imp", "func", { params: ["i32"], ret: "i32" })
- .End()
- .Function().End()
- .Export()
- .Function("changeCounter")
- .End()
- .Code()
- .Function("changeCounter", { params: ["i32", "i32"], ret: "i32" })
- .I32Const(42)
- .GetLocal(0)
- .I32Add()
- .GetLocal(1)
- .CallIndirect(0, 0) // Calls func(param[0] + 42).
- .I32Const(0)
- .CallIndirect(0, 0) // Calls func(param[0] + 42).
- .End()
- .End();
- const bin = builder.WebAssembly().get();
- const module = new WebAssembly.Module(bin);
- return module;
-};
-
-
-(function MonomorphicImport() {
- let counter = 0;
- const counterSetter = v => counter = v;
- const module = wasmModuleWhichImportJS();
- const instance = new WebAssembly.Instance(module, { imp: { func: counterSetter } });
- for (let i = 0; i < 4096; ++i) {
- // Invoke this a bunch of times to make sure the IC in the wasm -> JS stub works correctly.
- instance.exports.changeCounter(i, 0);
- assert.eq(counter, i + 42);
- }
-})();
</del></span></pre></div>
<a id="trunkJSTestswasmjsapicallindirectjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/js-api/call-indirect.js (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/call-indirect.js        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/js-api/call-indirect.js        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -6,10 +6,12 @@
</span><span class="cx"> .Type().End()
</span><span class="cx"> .Import()
</span><span class="cx"> .Function("imp", "func", { params: ["i32"] })
</span><ins>+ .Table("imp", "table", { initial: 1, maximum: 1, element: "anyfunc"})
</ins><span class="cx"> .End()
</span><span class="cx"> .Function().End()
</span><span class="cx"> .Export()
</span><span class="cx"> .Function("changeCounter")
</span><ins>+ .Function("callFunc")
</ins><span class="cx"> .End()
</span><span class="cx"> .Code()
</span><span class="cx"> .Function("changeCounter", { params: ["i32", "i32"] })
</span><span class="lines">@@ -17,8 +19,12 @@
</span><span class="cx"> .GetLocal(0)
</span><span class="cx"> .I32Add()
</span><span class="cx"> .GetLocal(1)
</span><del>- .CallIndirect(0, 0) // Calls func(param[0] + 42).
</del><ins>+ .CallIndirect(0, 0) // Calls table[0](param[0] + 42).
</ins><span class="cx"> .End()
</span><ins>+ .Function("callFunc", { params: ["i32"] })
+ .GetLocal(0)
+ .Call(0) // Calls func(param[0] + 42)
+ .End()
</ins><span class="cx"> .End();
</span><span class="cx"> const bin = builder.WebAssembly().get();
</span><span class="cx"> const module = new WebAssembly.Module(bin);
</span><span class="lines">@@ -25,12 +31,17 @@
</span><span class="cx"> return module;
</span><span class="cx"> };
</span><span class="cx">
</span><ins>+const makeTable = () => {
+ return new WebAssembly.Table({initial: 1, maximum: 1, element: "anyfunc"});
+};
</ins><span class="cx">
</span><span class="cx"> (function MonomorphicImport() {
</span><span class="cx"> let counter = 0;
</span><span class="cx"> const counterSetter = v => counter = v;
</span><ins>+ const table = makeTable();
</ins><span class="cx"> const module = wasmModuleWhichImportJS();
</span><del>- const instance = new WebAssembly.Instance(module, { imp: { func: counterSetter } });
</del><ins>+ const instance = new WebAssembly.Instance(module, { imp: { func: counterSetter, table} });
+ table.set(0, instance.exports.callFunc);
</ins><span class="cx"> for (let i = 0; i < 4096; ++i) {
</span><span class="cx"> // Invoke this a bunch of times to make sure the IC in the wasm -> JS stub works correctly.
</span><span class="cx"> instance.exports.changeCounter(i, 0);
</span><span class="lines">@@ -44,8 +55,14 @@
</span><span class="cx"> const counterASetter = v => counterA = v;
</span><span class="cx"> const counterBSetter = v => counterB = { valueB: v };
</span><span class="cx"> const module = wasmModuleWhichImportJS();
</span><del>- const instanceA = new WebAssembly.Instance(module, { imp: { func: counterASetter } });
- const instanceB = new WebAssembly.Instance(module, { imp: { func: counterBSetter } });
</del><ins>+
+ const tableA = makeTable();
+ const instanceA = new WebAssembly.Instance(module, { imp: { func: counterASetter, table: tableA} });
+ tableA.set(0, instanceA.exports.callFunc);
+
+ const tableB = makeTable();
+ const instanceB = new WebAssembly.Instance(module, { imp: { func: counterBSetter, table: tableB} });
+ tableB.set(0, instanceB.exports.callFunc);
</ins><span class="cx"> for (let i = 0; i < 2048; ++i) {
</span><span class="cx"> instanceA.exports.changeCounter(i, 0);
</span><span class="cx"> assert.isA(counterA, "number");
</span><span class="lines">@@ -57,8 +74,6 @@
</span><span class="cx"> })();
</span><span class="cx">
</span><span class="cx"> (function VirtualImport() {
</span><del>- const num = 10; // It's definitely going virtual at 10!
- let counters = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
</del><span class="cx"> const counterSetters = [
</span><span class="cx"> v => counters[0] = v,
</span><span class="cx"> v => counters[1] = v + 1,
</span><span class="lines">@@ -71,12 +86,16 @@
</span><span class="cx"> v => counters[8] = v + 8,
</span><span class="cx"> v => counters[9] = v + 9,
</span><span class="cx"> ];
</span><ins>+ const num = counterSetters.length;
+ let counters = counterSetters.map(() => 0);
</ins><span class="cx"> assert.eq(counters.length, num);
</span><del>- assert.eq(counterSetters.length, num);
</del><span class="cx"> const module = wasmModuleWhichImportJS();
</span><span class="cx"> let instances = [];
</span><del>- for (let i = 0; i < num; ++i)
- instances[i] = new WebAssembly.Instance(module, { imp: { func: counterSetters[i] } });
</del><ins>+ for (let i = 0; i < num; ++i) {
+ let table = makeTable();
+ instances[i] = new WebAssembly.Instance(module, { imp: { func: counterSetters[i], table} });
+ table.set(0, instances[i].exports.callFunc);
+ }
</ins><span class="cx"> for (let i = 0; i < 2048; ++i) {
</span><span class="cx"> for (let j = 0; j < num; ++j) {
</span><span class="cx"> instances[j].exports.changeCounter(i, 0);
</span></span></pre></div>
<a id="trunkJSTestswasmjsapitablejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/wasm/js-api/table.js (0 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/table.js         (rev 0)
+++ trunk/JSTests/wasm/js-api/table.js        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -0,0 +1,230 @@
</span><ins>+import Builder from '../Builder.js';
+import * as assert from '../assert.js';
+
+const badTableString = "couldn't parse section Table";
+const badImportString = "couldn't parse section Import";
+function assertBadBinary(builder, str) {
+ const bin = builder.WebAssembly().get();
+ 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);
+}
+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Import()
+ .Table("imp", "table", {initial: 20, element: "anyfunc"})
+ .End()
+ .Function().End()
+ .Table()
+ .Table({initial: 20, maximum: 30, element: "anyfunc"})
+ .End()
+ .Code()
+ .End();
+ assertBadBinary(builder, badTableString);
+}
+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 20, maximum: 30, element: "anyfunc"})
+ .Table({initial: 20, maximum: 30, element: "anyfunc"})
+ .End()
+ .Code()
+ .End();
+ assertBadBinary(builder, badTableString);
+}
+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Export()
+ .Function("foo")
+ .End()
+ .Code()
+ .Function("foo", {params: ["i32"]})
+ .GetLocal(0)
+ .CallIndirect(0, 0)
+ .End()
+ .End();
+ assertBadBinary(builder, "call_indirect is only valid when a table is defined or imported");
+}
+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial:20, element:"anyfunc"})
+ .End()
+ .Export()
+ .Function("foo")
+ .End()
+ .Code()
+ .Function("foo", {params: ["i32"]})
+ .GetLocal(0)
+ .CallIndirect(0, 1)
+ .End()
+ .End();
+ assertBadBinary(builder, "call_indirect 'reserved' varuint1 must be 0x0");
+}
+
+function assertBadTable(tableDescription) {
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table(tableDescription)
+ .End()
+ .Code()
+ .End();
+ assertBadBinary(builder, badTableString);
+}
+
+function assertBadTableImport(tableDescription) {
+ const builder = new Builder()
+ .Type().End()
+ .Import()
+ .Table("imp", "table", tableDescription)
+ .End()
+ .Function().End()
+ .Code()
+ .End();
+ assertBadBinary(builder, badImportString);
+}
+
+{
+ let badDescriptions = [
+ {initial: 10, element: "i32"},
+ {initial: 10, element: "f32"},
+ {initial: 10, element: "f64"},
+ {initial: 10, element: "i64"},
+ {initial: 10, maximum: 20, element: "i32"},
+ {initial: 10, maximum: 20, element: "f32"},
+ {initial: 10, maximum: 20, element: "f64"},
+ {initial: 10, maximum: 20, element: "i64"},
+
+ {initial: 10, maximum: 9, element: "anyfunc"},
+ {initial: 1, maximum: 0, element: "anyfunc"},
+ {initial: 2**32 - 1, maximum: 2**32 - 2, element: "anyfunc"},
+ {initial: 2**31, element: "anyfunc"},
+ ];
+
+ for (const d of badDescriptions) {
+ assertBadTable(d);
+ assertBadTableImport(d);
+ }
+}
+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Import()
+ .Table("imp", "table", {initial: 20, element: "anyfunc"})
+ .Table("imp", "table", {initial: 20, element: "anyfunc"})
+ .End()
+ .Function().End()
+ .Code()
+ .End();
+ assertBadBinary(builder, badImportString);
+}
+
+
+{
+ function assertBadTableInstance(tableDescription, table, message) {
+ const builder = new Builder()
+ .Type().End()
+ .Import()
+ .Table("imp", "table", tableDescription)
+ .End()
+ .Function().End()
+ .Code()
+ .End();
+
+ let threw = false;
+ const module = new WebAssembly.Module(builder.WebAssembly().get());
+ try {
+ new WebAssembly.Instance(module, {imp: {table}});
+ } catch (e) {
+ assert.eq(e.toString(), message);
+ threw = true;
+ }
+ assert.truthy(threw);
+ }
+
+ const badTables = [
+ [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, element: "anyfunc"}), "TypeError: Table import does not have a 'maximum' but the module requires that it does"],
+ [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, maximum:101, element: "anyfunc"}), "TypeError: Imported Table's 'maximum' is larger than the module's expected 'maximum'"],
+ [{initial: 100, element:"anyfunc"}, new WebAssembly.Table({initial:10, element: "anyfunc"}), "TypeError: Table import provided an 'initial' that is too small"],
+ [{initial: 10, element:"anyfunc"}, new WebAssembly.Table({initial:9, element: "anyfunc"}), "TypeError: Table import provided an 'initial' that is too small"],
+ ];
+ for (const [d, t, m] of badTables) {
+ assertBadTableInstance(d, t, m);
+ }
+}
+
+{
+ {
+ const table = new WebAssembly.Table({element: "anyfunc", initial: 20, maximum: 30});
+ table.grow(30);
+ assert.throws(() => table.grow(31), TypeError, "WebAssembly.Table.prototype.grow could not grow the table");
+ assert.throws(() => table.grow(29), TypeError, "WebAssembly.Table.prototype.grow could not grow the table");
+ }
+
+ {
+ const table = new WebAssembly.Table({element: "anyfunc", initial: 20});
+ assert.throws(() => table.grow({valueOf() { return 19; }}), TypeError, "WebAssembly.Table.prototype.grow could not grow the table");
+ let called = false;
+ table.grow({valueOf() { called = true; return 21; }});
+ assert.truthy(called);
+ }
+
+ {
+ const table = new WebAssembly.Table({element: "anyfunc", initial: 20});
+ assert.throws(() => table.get(20), RangeError, "WebAssembly.Table.prototype.get expects an integer less than the size of the table");
+ for (let i = 0; i < 20; i++)
+ assert.eq(table.get(i), null);
+ }
+
+ {
+ const table = new WebAssembly.Table({element: "anyfunc", initial: 20});
+ assert.throws(() => table.set(20, null), RangeError, "WebAssembly.Table.prototype.set expects an integer less than the size of the table");
+ for (let i = 0; i < 20; i++)
+ table.set(i, null);
+ }
+
+ {
+ // This should not throw
+ new WebAssembly.Table({initial: 2**20, maximum: 2**32 - 1, element: "anyfunc"});
+ }
+}
+
+{
+
+ function assertBadTable(table) {
+ const builder = new Builder()
+ .Type().End()
+ .Import()
+ .Table("imp", "table", {initial: 25, element: "anyfunc"})
+ .End()
+ .Function().End()
+ .Code()
+ .End();
+ const module = new WebAssembly.Module(builder.WebAssembly().get());
+ assert.throws(() => new WebAssembly.Instance(module, {imp: {table}}), TypeError, "Table import is not an instance of WebAssembly.Table");
+ }
+ assertBadTable(25);
+ assertBadTable(new Object);
+ assertBadTable([]);
+ assertBadTable(new WebAssembly.Memory({initial:1}));
+}
</ins></span></pre></div>
<a id="trunkJSTestswasmjsapitest_basic_apijs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/js-api/test_basic_api.js (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/test_basic_api.js        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/js-api/test_basic_api.js        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -78,8 +78,9 @@
</span><span class="cx"> new WebAssembly.Memory({initial: 20});
</span><span class="cx"> break;
</span><span class="cx"> case "Table":
</span><del>- // FIXME Implement and test these APIs further. For now they just throw. https://bugs.webkit.org/show_bug.cgi?id=159775
- assert.throws(() => new WebAssembly[c](), Error, `WebAssembly doesn't yet implement the ${c} constructor property`);
</del><ins>+ new WebAssembly.Table({initial: 20, element: "anyfunc"});
+ new WebAssembly.Table({initial: 20, maximum: 20, element: "anyfunc"});
+ new WebAssembly.Table({initial: 20, maximum: 25, element: "anyfunc"});
</ins><span class="cx"> break;
</span><span class="cx"> case "CompileError":
</span><span class="cx"> case "RuntimeError": {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -1,3 +1,96 @@
</span><ins>+2016-12-13 Saam Barati <sbarati@apple.com>
+
+ WebAssembly: implement the table section and table import
+ https://bugs.webkit.org/show_bug.cgi?id=165716
+
+ Reviewed by Keith Miller.
+
+ This patch implements the Table space for wasm:
+ https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#table-section
+
+ It only implements defining and importing a table. The bulk
+ of this patch is implementing the various wasm Table prototype
+ methods and the underlying Table object:
+ https://github.com/WebAssembly/design/blob/master/JS.md#webassemblytable-constructor
+
+ This patch also fixes a bug in our implementation with call_indirect.
+ We initially implemented call_indirect as a way to call functions that
+ are imported or defined in the module. This was the wrong
+ interpretation of the spec. Instead, call_indirect can only index into
+ the table index space.
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * wasm/WasmB3IRGenerator.cpp:
+ (JSC::Wasm::B3IRGenerator::B3IRGenerator):
+ (JSC::Wasm::B3IRGenerator::addCallIndirect):
+ (JSC::Wasm::parseAndCompile):
+ * wasm/WasmFormat.h:
+ (JSC::Wasm::TableInformation::TableInformation):
+ (JSC::Wasm::TableInformation::operator bool):
+ (JSC::Wasm::TableInformation::isImport):
+ (JSC::Wasm::TableInformation::initial):
+ (JSC::Wasm::TableInformation::maximum):
+ (JSC::Wasm::CallableFunction::CallableFunction):
+ * wasm/WasmFunctionParser.h:
+ (JSC::Wasm::FunctionParser<Context>::parseExpression):
+ * wasm/WasmModuleParser.cpp:
+ (JSC::Wasm::ModuleParser::parseImport):
+ (JSC::Wasm::ModuleParser::parseResizableLimits):
+ (JSC::Wasm::ModuleParser::parseTableHelper):
+ (JSC::Wasm::ModuleParser::parseTable):
+ (JSC::Wasm::ModuleParser::parseMemoryHelper):
+ (JSC::Wasm::ModuleParser::parseExport):
+ * wasm/WasmModuleParser.h:
+ * wasm/js/JSWebAssemblyHelpers.h: Added.
+ (JSC::toNonWrappingUint32):
+ * wasm/js/JSWebAssemblyInstance.cpp:
+ (JSC::JSWebAssemblyInstance::visitChildren):
+ * wasm/js/JSWebAssemblyInstance.h:
+ (JSC::JSWebAssemblyInstance::table):
+ (JSC::JSWebAssemblyInstance::setTable):
+ (JSC::JSWebAssemblyInstance::offsetOfTable):
+ * wasm/js/JSWebAssemblyTable.cpp:
+ (JSC::JSWebAssemblyTable::create):
+ (JSC::JSWebAssemblyTable::JSWebAssemblyTable):
+ (JSC::JSWebAssemblyTable::visitChildren):
+ (JSC::JSWebAssemblyTable::grow):
+ (JSC::JSWebAssemblyTable::clearFunction):
+ (JSC::JSWebAssemblyTable::setFunction):
+ * wasm/js/JSWebAssemblyTable.h:
+ (JSC::JSWebAssemblyTable::maximum):
+ (JSC::JSWebAssemblyTable::size):
+ (JSC::JSWebAssemblyTable::getFunction):
+ (JSC::JSWebAssemblyTable::offsetOfSize):
+ (JSC::JSWebAssemblyTable::offsetOfFunctions):
+ (JSC::JSWebAssemblyTable::isValidSize):
+ * wasm/js/WebAssemblyFunction.cpp:
+ (JSC::WebAssemblyFunction::call):
+ (JSC::WebAssemblyFunction::create):
+ (JSC::WebAssemblyFunction::visitChildren):
+ (JSC::WebAssemblyFunction::finishCreation):
+ * wasm/js/WebAssemblyFunction.h:
+ (JSC::WebAssemblyFunction::signature):
+ (JSC::WebAssemblyFunction::wasmEntrypoint):
+ (JSC::WebAssemblyFunction::webAssemblyCallee): Deleted.
+ * wasm/js/WebAssemblyInstanceConstructor.cpp:
+ (JSC::constructJSWebAssemblyInstance):
+ * wasm/js/WebAssemblyMemoryConstructor.cpp:
+ (JSC::constructJSWebAssemblyMemory):
+ * wasm/js/WebAssemblyModuleRecord.cpp:
+ (JSC::WebAssemblyModuleRecord::finishCreation):
+ (JSC::WebAssemblyModuleRecord::link):
+ * wasm/js/WebAssemblyTableConstructor.cpp:
+ (JSC::constructJSWebAssemblyTable):
+ * wasm/js/WebAssemblyTablePrototype.cpp:
+ (JSC::getTable):
+ (JSC::webAssemblyTableProtoFuncLength):
+ (JSC::webAssemblyTableProtoFuncGrow):
+ (JSC::webAssemblyTableProtoFuncGet):
+ (JSC::webAssemblyTableProtoFuncSet):
+ (JSC::WebAssemblyTablePrototype::create):
+ (JSC::WebAssemblyTablePrototype::finishCreation):
+ * wasm/js/WebAssemblyTablePrototype.h:
+
</ins><span class="cx"> 2016-12-13 Filip Pizlo <fpizlo@apple.com>
</span><span class="cx">
</span><span class="cx"> Add null checks to opaque root APIs.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -1413,6 +1413,7 @@
</span><span class="cx">                 795B19971D78BE3500262FA0 /* MapBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 795B19951D78BE3500262FA0 /* MapBase.cpp */; };
</span><span class="cx">                 795B19981D78BE3500262FA0 /* MapBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 795B19961D78BE3500262FA0 /* MapBase.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 7964656A1B952FF0003059EE /* GetPutInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 796465681B952FF0003059EE /* GetPutInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                796FB43A1DFF8C3F0039C95D /* JSWebAssemblyHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 796FB4391DFF8C3F0039C95D /* JSWebAssemblyHelpers.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 797E07A91B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */; };
</span><span class="cx">                 797E07AA1B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 798937781DCAB57300F8D4FB /* JSFixedArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 798937761DCAB57300F8D4FB /* JSFixedArray.cpp */; };
</span><span class="lines">@@ -3842,6 +3843,7 @@
</span><span class="cx">                 795B19951D78BE3500262FA0 /* MapBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MapBase.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 795B19961D78BE3500262FA0 /* MapBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapBase.h; sourceTree = "<group>"; };
</span><span class="cx">                 796465681B952FF0003059EE /* GetPutInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetPutInfo.h; sourceTree = "<group>"; };
</span><ins>+                796FB4391DFF8C3F0039C95D /* JSWebAssemblyHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSWebAssemblyHelpers.h; path = js/JSWebAssemblyHelpers.h; sourceTree = "<group>"; };
</ins><span class="cx">                 797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalLexicalEnvironment.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalLexicalEnvironment.h; sourceTree = "<group>"; };
</span><span class="cx">                 798937761DCAB57300F8D4FB /* JSFixedArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFixedArray.cpp; sourceTree = "<group>"; };
</span><span class="lines">@@ -7586,6 +7588,7 @@
</span><span class="cx">                                 79E423E11DEE65320078D355 /* JSWebAssemblyCallee.h */,
</span><span class="cx">                                 AD2FCBA61DB58DA400B3E736 /* JSWebAssemblyCompileError.cpp */,
</span><span class="cx">                                 AD2FCBA71DB58DA400B3E736 /* JSWebAssemblyCompileError.h */,
</span><ins>+                                796FB4391DFF8C3F0039C95D /* JSWebAssemblyHelpers.h */,
</ins><span class="cx">                                 AD2FCBA81DB58DA400B3E736 /* JSWebAssemblyInstance.cpp */,
</span><span class="cx">                                 AD2FCBA91DB58DA400B3E736 /* JSWebAssemblyInstance.h */,
</span><span class="cx">                                 AD2FCBAA1DB58DA400B3E736 /* JSWebAssemblyMemory.cpp */,
</span><span class="lines">@@ -8695,6 +8698,7 @@
</span><span class="cx">                                 43422A671C16267800E2EB98 /* B3ReduceDoubleToFloat.h in Headers */,
</span><span class="cx">                                 0F070A4B1D543A98006E7232 /* LargeAllocation.h in Headers */,
</span><span class="cx">                                 86D3B2C610156BDE002865E7 /* MacroAssemblerARM.h in Headers */,
</span><ins>+                                796FB43A1DFF8C3F0039C95D /* JSWebAssemblyHelpers.h in Headers */,
</ins><span class="cx">                                 A1A009C01831A22D00CF8711 /* MacroAssemblerARM64.h in Headers */,
</span><span class="cx">                                 86ADD1460FDDEA980006EEC2 /* MacroAssemblerARMv7.h in Headers */,
</span><span class="cx">                                 863B23E00FC6118900703AA4 /* MacroAssemblerCodeRef.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmB3IRGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -137,7 +137,7 @@
</span><span class="cx">
</span><span class="cx"> static constexpr ExpressionType emptyExpression = nullptr;
</span><span class="cx">
</span><del>- B3IRGenerator(const MemoryInformation&, Procedure&, WasmInternalFunction*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&);
</del><ins>+ B3IRGenerator(VM&, const MemoryInformation&, Procedure&, WasmInternalFunction*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&);
</ins><span class="cx">
</span><span class="cx"> bool WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
</span><span class="cx"> bool WARN_UNUSED_RETURN addLocal(Type, uint32_t);
</span><span class="lines">@@ -188,6 +188,7 @@
</span><span class="cx"> void unifyValuesWithBlock(const ExpressionList& resultStack, ResultList& stack);
</span><span class="cx"> Value* zeroForType(Type);
</span><span class="cx">
</span><ins>+ VM& m_vm;
</ins><span class="cx"> const ImmutableFunctionIndexSpace& m_functionIndexSpace;
</span><span class="cx"> Procedure& m_proc;
</span><span class="cx"> BasicBlock* m_currentBlock;
</span><span class="lines">@@ -199,8 +200,9 @@
</span><span class="cx"> Value* m_functionIndexSpaceValue;
</span><span class="cx"> };
</span><span class="cx">
</span><del>-B3IRGenerator::B3IRGenerator(const MemoryInformation& memory, Procedure& procedure, WasmInternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace)
- : m_functionIndexSpace(functionIndexSpace)
</del><ins>+B3IRGenerator::B3IRGenerator(VM& vm, const MemoryInformation& memory, Procedure& procedure, WasmInternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace)
+ : m_vm(vm)
+ , m_functionIndexSpace(functionIndexSpace)
</ins><span class="cx"> , m_proc(procedure)
</span><span class="cx"> , m_unlinkedWasmToWasmCalls(unlinkedWasmToWasmCalls)
</span><span class="cx"> {
</span><span class="lines">@@ -669,12 +671,23 @@
</span><span class="cx"> ExpressionType calleeIndex = args.takeLast();
</span><span class="cx"> ASSERT(signature->arguments.size() == args.size());
</span><span class="cx">
</span><ins>+ ExpressionType callableFunctionBuffer;
+ ExpressionType callableFunctionBufferSize;
+ {
+ ExpressionType topInstance = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(),
+ m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), &m_vm.topJSWebAssemblyInstance));
+ ExpressionType table = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(),
+ topInstance, JSWebAssemblyInstance::offsetOfTable());
+ callableFunctionBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(),
+ table, JSWebAssemblyTable::offsetOfFunctions());
+ callableFunctionBufferSize = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, Origin(),
+ table, JSWebAssemblyTable::offsetOfSize());
+ }
+
</ins><span class="cx"> // Check the index we are looking for is valid.
</span><span class="cx"> {
</span><del>- ExpressionType maxValidIndex = m_currentBlock->appendIntConstant(m_proc, Origin(), Int32, m_functionIndexSpace.size);
</del><span class="cx"> CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(),
</span><del>- m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), m_zeroValues[linearizeType(I32)],
- m_currentBlock->appendNew<Value>(m_proc, LessThan, Origin(), calleeIndex, maxValidIndex)));
</del><ins>+ m_currentBlock->appendNew<Value>(m_proc, AboveEqual, Origin(), calleeIndex, callableFunctionBufferSize));
</ins><span class="cx">
</span><span class="cx"> check->setGenerator([] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
</span><span class="cx"> jit.breakpoint();
</span><span class="lines">@@ -681,15 +694,27 @@
</span><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><del>- // Compute the offset in the function index space we are looking for.
</del><ins>+ // Compute the offset in the table index space we are looking for.
</ins><span class="cx"> ExpressionType offset = m_currentBlock->appendNew<Value>(m_proc, Mul, Origin(),
</span><span class="cx"> m_currentBlock->appendNew<Value>(m_proc, ZExt32, Origin(), calleeIndex),
</span><span class="cx"> m_currentBlock->appendIntConstant(m_proc, Origin(), pointerType(), sizeof(CallableFunction)));
</span><del>- ExpressionType callableFunction = m_currentBlock->appendNew<Value>(m_proc, Add, Origin(), m_functionIndexSpaceValue, offset);
</del><ins>+ ExpressionType callableFunction = m_currentBlock->appendNew<Value>(m_proc, Add, Origin(), callableFunctionBuffer, offset);
</ins><span class="cx">
</span><ins>+ // Check that the CallableFunction is initialized. We trap if it isn't. A null Signature* indicates it's not initialized.
+ ExpressionType calleeSignature = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, signature));
+ {
+ CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(),
+ m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(),
+ calleeSignature,
+ m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), 0)));
+
+ check->setGenerator([] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+ jit.breakpoint();
+ });
+ }
+
</ins><span class="cx"> // Check the signature matches the value we expect.
</span><span class="cx"> {
</span><del>- ExpressionType calleeSignature = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, signature));
</del><span class="cx"> ExpressionType expectedSignature = m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), signature);
</span><span class="cx"> CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(),
</span><span class="cx"> m_currentBlock->appendNew<Value>(m_proc, NotEqual, Origin(), calleeSignature, expectedSignature));
</span><span class="lines">@@ -713,6 +738,7 @@
</span><span class="cx"> jit.call(params[returnType == Void ? 0 : 1].gpr());
</span><span class="cx"> });
</span><span class="cx"> });
</span><ins>+
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -846,7 +872,7 @@
</span><span class="cx"> auto result = std::make_unique<WasmInternalFunction>();
</span><span class="cx">
</span><span class="cx"> Procedure procedure;
</span><del>- B3IRGenerator context(info.memory, procedure, result.get(), unlinkedWasmToWasmCalls, functionIndexSpace);
</del><ins>+ B3IRGenerator context(vm, info.memory, procedure, result.get(), unlinkedWasmToWasmCalls, functionIndexSpace);
</ins><span class="cx"> FunctionParser<B3IRGenerator> parser(context, functionStart, functionLength, signature, functionIndexSpace, info);
</span><span class="cx"> if (!parser.parse())
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmFormath"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmFormat.h (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmFormat.h        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/WasmFormat.h        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -106,7 +106,7 @@
</span><span class="cx"> External::Kind kind;
</span><span class="cx"> union {
</span><span class="cx"> uint32_t functionIndex;
</span><del>- // FIXME implement Table https://bugs.webkit.org/show_bug.cgi?id=164135
</del><ins>+ // FIXME implement Table https://bugs.webkit.org/show_bug.cgi?id=165782
</ins><span class="cx"> // FIXME implement Memory https://bugs.webkit.org/show_bug.cgi?id=165671
</span><span class="cx"> // FIXME implement Global https://bugs.webkit.org/show_bug.cgi?id=164133
</span><span class="cx"> };
</span><span class="lines">@@ -147,11 +147,38 @@
</span><span class="cx"> }
</span><span class="cx"> };
</span><span class="cx">
</span><ins>+class TableInformation {
+public:
+ TableInformation()
+ {
+ ASSERT(!*this);
+ }
+
+ TableInformation(uint32_t initial, std::optional<uint32_t> maximum, bool isImport)
+ : m_initial(initial)
+ , m_maximum(maximum)
+ , m_isImport(isImport)
+ , m_isValid(true)
+ {
+ ASSERT(*this);
+ }
+
+ explicit operator bool() const { return m_isValid; }
+ bool isImport() const { return m_isImport; }
+ uint32_t initial() const { return m_initial; }
+ std::optional<uint32_t> maximum() const { return m_maximum; }
+
+private:
+ uint32_t m_initial;
+ std::optional<uint32_t> m_maximum;
+ bool m_isImport { false };
+ bool m_isValid { false };
+};
+
</ins><span class="cx"> struct ModuleInformation {
</span><span class="cx"> Vector<Signature> signatures;
</span><span class="cx"> Vector<Import> imports;
</span><span class="cx"> Vector<Signature*> importFunctions;
</span><del>- // FIXME implement import Table https://bugs.webkit.org/show_bug.cgi?id=164135
</del><span class="cx"> // FIXME implement import Global https://bugs.webkit.org/show_bug.cgi?id=164133
</span><span class="cx"> Vector<Signature*> internalFunctionSignatures;
</span><span class="cx"> MemoryInformation memory;
</span><span class="lines">@@ -158,6 +185,7 @@
</span><span class="cx"> Vector<Export> exports;
</span><span class="cx"> std::optional<uint32_t> startFunctionIndexSpace;
</span><span class="cx"> Vector<Segment::Ptr> data;
</span><ins>+ TableInformation tableInformation;
</ins><span class="cx">
</span><span class="cx"> ~ModuleInformation();
</span><span class="cx"> };
</span><span class="lines">@@ -185,13 +213,18 @@
</span><span class="cx"> // WebAssembly direct calls and call_indirect use indices into "function index space". This space starts with all imports, and then all internal functions.
</span><span class="cx"> // CallableFunction and FunctionIndexSpace are only meant as fast lookup tables for these opcodes, and do not own code.
</span><span class="cx"> struct CallableFunction {
</span><del>- CallableFunction(Signature* signature)
</del><ins>+ CallableFunction() = default;
+
+ CallableFunction(Signature* signature, void* code = nullptr)
</ins><span class="cx"> : signature(signature)
</span><del>- , code(nullptr)
</del><ins>+ , code(code)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><del>- Signature* signature; // FIXME pack this inside a (uniqued) integer (for correctness the parser should unique Signatures), and then pack that integer into the code pointer. https://bugs.webkit.org/show_bug.cgi?id=165511
- void* code;
</del><ins>+
+ // FIXME pack this inside a (uniqued) integer (for correctness the parser should unique Signatures),
+ // and then pack that integer into the code pointer. https://bugs.webkit.org/show_bug.cgi?id=165511
+ Signature* signature { nullptr };
+ void* code { nullptr };
</ins><span class="cx"> };
</span><span class="cx"> typedef Vector<CallableFunction> FunctionIndexSpace;
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmFunctionParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -382,6 +382,8 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::CallIndirect: {
</span><ins>+ if (!m_info.tableInformation)
+ return setErrorMessage("call_indirect is only valid when a table is defined or imported");
</ins><span class="cx"> uint32_t signatureIndex;
</span><span class="cx"> if (!parseVarUInt32(signatureIndex))
</span><span class="cx"> return false;
</span><span class="lines">@@ -390,6 +392,9 @@
</span><span class="cx"> if (!parseVarUInt1(reserved))
</span><span class="cx"> return false;
</span><span class="cx">
</span><ins>+ if (reserved != 0)
+ return setErrorMessage("call_indirect 'reserved' varuint1 must be 0x0");
+
</ins><span class="cx"> if (m_info.signatures.size() <= signatureIndex)
</span><span class="cx"> return setErrorMessage("Tried to use a signature outside the range of valid signatures");
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmModuleParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #if ENABLE(WEBASSEMBLY)
</span><span class="cx">
</span><span class="cx"> #include "IdentifierInlines.h"
</span><ins>+#include "JSWebAssemblyTable.h"
</ins><span class="cx"> #include "WasmFormat.h"
</span><span class="cx"> #include "WasmMemoryInformation.h"
</span><span class="cx"> #include "WasmOps.h"
</span><span class="lines">@@ -250,7 +251,9 @@
</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=164135
</del><ins>+ bool isImport = true;
+ if (!parseTableHelper(isImport))
+ return false;
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case External::Memory: {
</span><span class="lines">@@ -300,45 +303,101 @@
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseTable()
</del><ins>+bool ModuleParser::parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum)
</ins><span class="cx"> {
</span><del>- // FIXME implement table https://bugs.webkit.org/show_bug.cgi?id=164135
- RELEASE_ASSERT_NOT_REACHED();
</del><ins>+ ASSERT(!maximum);
+
+ uint8_t flags;
+ if (!parseVarUInt1(flags))
+ return false;
+
+ if (!parseVarUInt32(initial))
+ return false;
+
+ if (flags) {
+ uint32_t maximumInt;
+ if (!parseVarUInt32(maximumInt))
+ return false;
+
+ if (initial > maximumInt)
+ return false;
+
+ maximum = maximumInt;
+ }
+
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseMemoryHelper(bool isImport)
</del><ins>+bool ModuleParser::parseTableHelper(bool isImport)
</ins><span class="cx"> {
</span><del>- // We don't allow redeclaring memory. Either via import or definition.
- if (m_module->memory)
</del><ins>+ // We're only allowed a total of one Table import or definition.
+ if (m_hasTable)
</ins><span class="cx"> return false;
</span><span class="cx">
</span><del>- uint8_t flags;
- if (!parseVarUInt1(flags))
</del><ins>+ m_hasTable = true;
+
+ int8_t type;
+ if (!parseInt7(type))
</ins><span class="cx"> return false;
</span><ins>+ if (type != Wasm::Anyfunc)
+ return false;
</ins><span class="cx">
</span><span class="cx"> uint32_t initial;
</span><del>- if (!parseVarUInt32(initial))
</del><ins>+ std::optional<uint32_t> maximum;
+ if (!parseResizableLimits(initial, maximum))
</ins><span class="cx"> return false;
</span><span class="cx">
</span><del>- if (!PageCount::isValid(initial))
</del><ins>+ if (!JSWebAssemblyTable::isValidSize(initial))
</ins><span class="cx"> return false;
</span><span class="cx">
</span><del>- PageCount initialPageCount(initial);
</del><ins>+ ASSERT(!maximum || *maximum >= initial);
</ins><span class="cx">
</span><ins>+ m_module->tableInformation = TableInformation(initial, maximum, isImport);
+
+ return true;
+}
+
+bool ModuleParser::parseTable()
+{
+ uint32_t count;
+ if (!parseVarUInt32(count))
+ return false;
+
+ // We only allow one table for now.
+ if (count != 1)
+ return false;
+
+ bool isImport = false;
+ return parseTableHelper(isImport);
+}
+
+bool ModuleParser::parseMemoryHelper(bool isImport)
+{
+ // We don't allow redeclaring memory. Either via import or definition.
+ if (m_module->memory)
+ return false;
+
+ PageCount initialPageCount;
</ins><span class="cx"> PageCount maximumPageCount;
</span><del>- if (flags) {
- uint32_t maximum;
- if (!parseVarUInt32(maximum))
</del><ins>+ {
+ uint32_t initial;
+ std::optional<uint32_t> maximum;
+ if (!parseResizableLimits(initial, maximum))
</ins><span class="cx"> return false;
</span><del>-
- if (!PageCount::isValid(maximum))
</del><ins>+ ASSERT(!maximum || *maximum >= initial);
+ if (!PageCount::isValid(initial))
</ins><span class="cx"> return false;
</span><span class="cx">
</span><del>- maximumPageCount = PageCount(maximum);
- if (initialPageCount > maximumPageCount)
- return false;
</del><ins>+ initialPageCount = PageCount(initial);
+
+ if (maximum) {
+ if (!PageCount::isValid(*maximum))
+ return false;
+ maximumPageCount = PageCount(*maximum);
+ }
</ins><span class="cx"> }
</span><ins>+ ASSERT(initialPageCount);
+ ASSERT(!maximumPageCount || maximumPageCount >= initialPageCount);
</ins><span class="cx">
</span><span class="cx"> Vector<unsigned> pinnedSizes = { 0 };
</span><span class="cx"> m_module->memory = MemoryInformation(initialPageCount, maximumPageCount, pinnedSizes, isImport);
</span><span class="lines">@@ -397,7 +456,7 @@
</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=164135
</del><ins>+ // FIXME https://bugs.webkit.org/show_bug.cgi?id=165782
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case External::Memory: {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmModuleParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmModuleParser.h (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmModuleParser.h        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/WasmModuleParser.h        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -79,6 +79,8 @@
</span><span class="cx"> #undef WASM_SECTION_DECLARE_PARSER
</span><span class="cx">
</span><span class="cx"> bool WARN_UNUSED_RETURN parseMemoryHelper(bool isImport);
</span><ins>+ bool WARN_UNUSED_RETURN parseTableHelper(bool isImport);
+ bool WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum);
</ins><span class="cx">
</span><span class="cx"> VM* m_vm;
</span><span class="cx"> std::unique_ptr<ModuleInformation> m_module;
</span><span class="lines">@@ -85,6 +87,7 @@
</span><span class="cx"> FunctionIndexSpace m_functionIndexSpace;
</span><span class="cx"> Vector<FunctionLocationInBinary> m_functionLocationInBinary;
</span><span class="cx"> bool m_failed { true };
</span><ins>+ bool m_hasTable { false };
</ins><span class="cx"> String m_errorMessage;
</span><span class="cx"> };
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsJSWebAssemblyHelpersh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyHelpers.h (0 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyHelpers.h         (rev 0)
+++ trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyHelpers.h        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "JSCJSValue.h"
+
+namespace JSC {
+
+ALWAYS_INLINE uint32_t toNonWrappingUint32(ExecState* exec, JSValue value)
+{
+ VM& vm = exec->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ double doubleValue = value.toInteger(exec);
+ RETURN_IF_EXCEPTION(throwScope, { });
+ if (doubleValue < 0 || doubleValue > UINT_MAX) {
+ throwException(exec, throwScope,
+ createRangeError(exec, ASCIILiteral("Expect an integer argument in the range: [0, 2^32 - 1]")));
+ return { };
+ }
+
+ return static_cast<uint32_t>(doubleValue);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsJSWebAssemblyInstancecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -80,6 +80,7 @@
</span><span class="cx"> visitor.append(&thisObject->m_module);
</span><span class="cx"> visitor.append(&thisObject->m_moduleNamespaceObject);
</span><span class="cx"> visitor.append(&thisObject->m_memory);
</span><ins>+ visitor.append(&thisObject->m_table);
</ins><span class="cx"> for (unsigned i = 0; i < thisObject->m_numImportFunctions; ++i)
</span><span class="cx"> visitor.append(thisObject->importFunction(i));
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsJSWebAssemblyInstanceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> #include "JSDestructibleObject.h"
</span><span class="cx"> #include "JSObject.h"
</span><span class="cx"> #include "JSWebAssemblyMemory.h"
</span><ins>+#include "JSWebAssemblyTable.h"
</ins><span class="cx">
</span><span class="cx"> namespace JSC {
</span><span class="cx">
</span><span class="lines">@@ -71,11 +72,16 @@
</span><span class="cx"> JSWebAssemblyMemory* memory() { return m_memory.get(); }
</span><span class="cx"> void setMemory(VM& vm, JSWebAssemblyMemory* memory) { m_memory.set(vm, this, memory); }
</span><span class="cx">
</span><ins>+ JSWebAssemblyTable* table() { return m_table.get(); }
+ void setTable(VM& vm, JSWebAssemblyTable* table) { m_table.set(vm, this, table); }
+
</ins><span class="cx"> static size_t offsetOfImportFunction(unsigned idx)
</span><span class="cx"> {
</span><span class="cx"> return offsetOfImportFunctions() + sizeof(WriteBarrier<JSCell>) * idx;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ static ptrdiff_t offsetOfTable() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_table); }
+
</ins><span class="cx"> protected:
</span><span class="cx"> JSWebAssemblyInstance(VM&, Structure*, unsigned);
</span><span class="cx"> void finishCreation(VM&, JSWebAssemblyModule*, JSModuleNamespaceObject*);
</span><span class="lines">@@ -96,6 +102,7 @@
</span><span class="cx"> WriteBarrier<JSWebAssemblyModule> m_module;
</span><span class="cx"> WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
</span><span class="cx"> WriteBarrier<JSWebAssemblyMemory> m_memory;
</span><ins>+ WriteBarrier<JSWebAssemblyTable> m_table;
</ins><span class="cx"> unsigned m_numImportFunctions;
</span><span class="cx"> };
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsJSWebAssemblyTablecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.cpp (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.cpp        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.cpp        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -29,12 +29,21 @@
</span><span class="cx"> #if ENABLE(WEBASSEMBLY)
</span><span class="cx">
</span><span class="cx"> #include "JSCInlines.h"
</span><ins>+#include "WasmFormat.h"
</ins><span class="cx">
</span><span class="cx"> namespace JSC {
</span><span class="cx">
</span><del>-JSWebAssemblyTable* JSWebAssemblyTable::create(VM& vm, Structure* structure)
</del><ins>+const ClassInfo JSWebAssemblyTable::s_info = { "WebAssembly.Table", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWebAssemblyTable) };
+
+JSWebAssemblyTable* JSWebAssemblyTable::create(ExecState* exec, VM& vm, Structure* structure, uint32_t initial, std::optional<uint32_t> maximum)
</ins><span class="cx"> {
</span><del>- auto* instance = new (NotNull, allocateCell<JSWebAssemblyTable>(vm.heap)) JSWebAssemblyTable(vm, structure);
</del><ins>+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ if (!isValidSize(initial)) {
+ throwException(exec, throwScope, createOutOfMemoryError(exec));
+ return nullptr;
+ }
+
+ auto* instance = new (NotNull, allocateCell<JSWebAssemblyTable>(vm.heap)) JSWebAssemblyTable(vm, structure, initial, maximum);
</ins><span class="cx"> instance->finishCreation(vm);
</span><span class="cx"> return instance;
</span><span class="cx"> }
</span><span class="lines">@@ -44,9 +53,23 @@
</span><span class="cx"> return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
</span><span class="cx"> }
</span><span class="cx">
</span><del>-JSWebAssemblyTable::JSWebAssemblyTable(VM& vm, Structure* structure)
</del><ins>+JSWebAssemblyTable::JSWebAssemblyTable(VM& vm, Structure* structure, uint32_t initial, std::optional<uint32_t> maximum)
</ins><span class="cx"> : Base(vm, structure)
</span><span class="cx"> {
</span><ins>+ m_size = initial;
+ ASSERT(isValidSize(m_size));
+ m_maximum = maximum;
+ ASSERT(!m_maximum || *m_maximum >= m_size);
+
+ // FIXME: It might be worth trying to pre-allocate maximum here. The spec recommends doing so.
+ // But for now, we're not doing that.
+ m_functions = MallocPtr<Wasm::CallableFunction>::malloc(sizeof(Wasm::CallableFunction) * static_cast<size_t>(m_size));
+ m_jsFunctions = MallocPtr<WriteBarrier<WebAssemblyFunction>>::malloc(sizeof(WriteBarrier<WebAssemblyFunction>) * static_cast<size_t>(m_size));
+ for (uint32_t i = 0; i < m_size; ++i) {
+ new (&m_functions.get()[i]) Wasm::CallableFunction();
+ ASSERT(!m_functions.get()[i].signature); // We rely on this in compiled code.
+ new (&m_jsFunctions.get()[i]) WriteBarrier<WebAssemblyFunction>();
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void JSWebAssemblyTable::finishCreation(VM& vm)
</span><span class="lines">@@ -62,14 +85,52 @@
</span><span class="cx">
</span><span class="cx"> void JSWebAssemblyTable::visitChildren(JSCell* cell, SlotVisitor& visitor)
</span><span class="cx"> {
</span><del>- auto* thisObject = jsCast<JSWebAssemblyTable*>(cell);
</del><ins>+ JSWebAssemblyTable* thisObject = jsCast<JSWebAssemblyTable*>(cell);
</ins><span class="cx"> ASSERT_GC_OBJECT_INHERITS(thisObject, info());
</span><span class="cx">
</span><span class="cx"> Base::visitChildren(thisObject, visitor);
</span><ins>+
+ for (unsigned i = 0; i < thisObject->m_size; ++i)
+ visitor.append(&thisObject->m_jsFunctions.get()[i]);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-const ClassInfo JSWebAssemblyTable::s_info = { "WebAssembly.Table", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWebAssemblyTable) };
</del><ins>+bool JSWebAssemblyTable::grow(uint32_t newSize)
+{
+ if (newSize < m_size)
+ return false;
+ if (newSize == m_size)
+ return true;
+ if (maximum() && newSize > *maximum())
+ return false;
+ if (!isValidSize(newSize))
+ return false;
</ins><span class="cx">
</span><ins>+ m_functions.realloc(sizeof(Wasm::CallableFunction) * static_cast<size_t>(newSize));
+ m_jsFunctions.realloc(sizeof(WriteBarrier<WebAssemblyFunction>) * static_cast<size_t>(newSize));
+
+ for (uint32_t i = m_size; i < newSize; ++i) {
+ new (&m_functions.get()[i]) Wasm::CallableFunction();
+ new (&m_jsFunctions.get()[i]) WriteBarrier<WebAssemblyFunction>();
+ }
+ m_size = newSize;
+ return true;
+}
+
+void JSWebAssemblyTable::clearFunction(uint32_t index)
+{
+ RELEASE_ASSERT(index < m_size);
+ m_jsFunctions.get()[index] = WriteBarrier<WebAssemblyFunction>();
+ m_functions.get()[index] = Wasm::CallableFunction();
+ ASSERT(!m_functions.get()[index].signature); // We rely on this in compiled code.
+}
+
+void JSWebAssemblyTable::setFunction(VM& vm, uint32_t index, WebAssemblyFunction* function)
+{
+ RELEASE_ASSERT(index < m_size);
+ m_jsFunctions.get()[index].set(vm, this, function);
+ m_functions.get()[index] = Wasm::CallableFunction(function->signature(), function->wasmEntrypoint());
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx">
</span><span class="cx"> #endif // ENABLE(WEBASSEMBLY)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsJSWebAssemblyTableh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.h (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.h        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.h        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -29,23 +29,54 @@
</span><span class="cx">
</span><span class="cx"> #include "JSDestructibleObject.h"
</span><span class="cx"> #include "JSObject.h"
</span><ins>+#include "WebAssemblyFunction.h"
+#include <wtf/MallocPtr.h>
</ins><span class="cx">
</span><span class="cx"> namespace JSC {
</span><span class="cx">
</span><ins>+namespace Wasm {
+struct CallableFunction;
+}
+
</ins><span class="cx"> class JSWebAssemblyTable : public JSDestructibleObject {
</span><span class="cx"> public:
</span><span class="cx"> typedef JSDestructibleObject Base;
</span><span class="cx">
</span><del>- static JSWebAssemblyTable* create(VM&, Structure*);
</del><ins>+ static JSWebAssemblyTable* create(ExecState*, VM&, Structure*, uint32_t initial, std::optional<uint32_t> maximum);
</ins><span class="cx"> static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
</span><span class="cx">
</span><span class="cx"> DECLARE_INFO;
</span><span class="cx">
</span><del>-protected:
- JSWebAssemblyTable(VM&, Structure*);
</del><ins>+ std::optional<uint32_t> maximum() const { return m_maximum; }
+ uint32_t size() const { return m_size; }
+ bool grow(uint32_t newSize) WARN_UNUSED_RETURN;
+ WebAssemblyFunction* getFunction(uint32_t index)
+ {
+ RELEASE_ASSERT(index < m_size);
+ return m_jsFunctions.get()[index].get();
+ }
+ void clearFunction(uint32_t index);
+ void setFunction(VM&, uint32_t index, WebAssemblyFunction*);
+
+ static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(JSWebAssemblyTable, m_size); }
+ static ptrdiff_t offsetOfFunctions() { return OBJECT_OFFSETOF(JSWebAssemblyTable, m_functions); }
+
+ static bool isValidSize(uint32_t size)
+ {
+ // This tops out at ~384 MB worth of data in this class.
+ return size < (1 << 24);
+ }
+
+private:
+ JSWebAssemblyTable(VM&, Structure*, uint32_t initial, std::optional<uint32_t> maximum);
</ins><span class="cx"> void finishCreation(VM&);
</span><span class="cx"> static void destroy(JSCell*);
</span><span class="cx"> static void visitChildren(JSCell*, SlotVisitor&);
</span><ins>+
+ MallocPtr<Wasm::CallableFunction> m_functions;
+ MallocPtr<WriteBarrier<WebAssemblyFunction>> m_jsFunctions;
+ std::optional<uint32_t> m_maximum;
+ uint32_t m_size;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyFunctioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -117,7 +117,7 @@
</span><span class="cx"> JSWebAssemblyInstance* prevJSWebAssemblyInstance = vm.topJSWebAssemblyInstance;
</span><span class="cx"> vm.topJSWebAssemblyInstance = instance();
</span><span class="cx"> ASSERT(instance());
</span><del>- EncodedJSValue rawResult = vmEntryToWasm(webAssemblyCallee()->entrypoint(), &vm, protoCallFrame);
</del><ins>+ EncodedJSValue rawResult = vmEntryToWasm(m_jsEntrypoint->entrypoint(), &vm, protoCallFrame);
</ins><span class="cx"> vm.topJSWebAssemblyInstance = prevJSWebAssemblyInstance;
</span><span class="cx">
</span><span class="cx"> // FIXME is this correct? https://bugs.webkit.org/show_bug.cgi?id=164876
</span><span class="lines">@@ -140,12 +140,12 @@
</span><span class="cx"> return EncodedJSValue();
</span><span class="cx"> }
</span><span class="cx">
</span><del>-WebAssemblyFunction* WebAssemblyFunction::create(VM& vm, JSGlobalObject* globalObject, unsigned length, const String& name, JSWebAssemblyInstance* instance, JSWebAssemblyCallee* callee, Wasm::Signature* signature)
</del><ins>+WebAssemblyFunction* WebAssemblyFunction::create(VM& vm, JSGlobalObject* globalObject, unsigned length, const String& name, JSWebAssemblyInstance* instance, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::Signature* signature)
</ins><span class="cx"> {
</span><span class="cx"> NativeExecutable* executable = vm.getHostFunction(callWebAssemblyFunction, NoIntrinsic, callHostFunctionAsConstructor, nullptr, name);
</span><span class="cx"> Structure* structure = globalObject->webAssemblyFunctionStructure();
</span><span class="cx"> WebAssemblyFunction* function = new (NotNull, allocateCell<WebAssemblyFunction>(vm.heap)) WebAssemblyFunction(vm, globalObject, structure);
</span><del>- function->finishCreation(vm, executable, length, name, instance, callee, signature);
</del><ins>+ function->finishCreation(vm, executable, length, name, instance, jsEntrypoint, wasmEntrypoint, signature);
</ins><span class="cx"> return function;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -166,15 +166,18 @@
</span><span class="cx"> ASSERT_GC_OBJECT_INHERITS(thisObject, info());
</span><span class="cx"> Base::visitChildren(thisObject, visitor);
</span><span class="cx"> visitor.append(&thisObject->m_instance);
</span><del>- visitor.append(&thisObject->m_wasmCallee);
</del><ins>+ visitor.append(&thisObject->m_jsEntrypoint);
+ visitor.append(&thisObject->m_wasmEntrypoint);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-void WebAssemblyFunction::finishCreation(VM& vm, NativeExecutable* executable, unsigned length, const String& name, JSWebAssemblyInstance* instance, JSWebAssemblyCallee* wasmCallee, Wasm::Signature* signature)
</del><ins>+void WebAssemblyFunction::finishCreation(VM& vm, NativeExecutable* executable, unsigned length, const String& name, JSWebAssemblyInstance* instance, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::Signature* signature)
</ins><span class="cx"> {
</span><span class="cx"> Base::finishCreation(vm, executable, length, name);
</span><span class="cx"> ASSERT(inherits(info()));
</span><span class="cx"> m_instance.set(vm, this, instance);
</span><del>- m_wasmCallee.set(vm, this, wasmCallee);
</del><ins>+ ASSERT(jsEntrypoint != wasmEntrypoint);
+ m_jsEntrypoint.set(vm, this, jsEntrypoint);
+ m_wasmEntrypoint.set(vm, this, wasmEntrypoint);
</ins><span class="cx"> m_signature = signature;
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyFunctionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.h (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.h        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.h        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -28,12 +28,12 @@
</span><span class="cx"> #if ENABLE(WEBASSEMBLY)
</span><span class="cx">
</span><span class="cx"> #include "JSFunction.h"
</span><ins>+#include "JSWebAssemblyCallee.h"
</ins><span class="cx"> #include <wtf/Noncopyable.h>
</span><span class="cx">
</span><span class="cx"> namespace JSC {
</span><span class="cx">
</span><span class="cx"> class JSGlobalObject;
</span><del>-class JSWebAssemblyCallee;
</del><span class="cx"> struct ProtoCallFrame;
</span><span class="cx"> class WebAssemblyInstance;
</span><span class="cx">
</span><span class="lines">@@ -53,28 +53,29 @@
</span><span class="cx">
</span><span class="cx"> DECLARE_EXPORT_INFO;
</span><span class="cx">
</span><del>- JS_EXPORT_PRIVATE static WebAssemblyFunction* create(VM&, JSGlobalObject*, unsigned, const String&, JSWebAssemblyInstance*, JSWebAssemblyCallee*, Wasm::Signature*);
</del><ins>+ JS_EXPORT_PRIVATE static WebAssemblyFunction* create(VM&, JSGlobalObject*, unsigned, const String&, JSWebAssemblyInstance*, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::Signature*);
</ins><span class="cx"> static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
</span><span class="cx">
</span><del>- JSWebAssemblyCallee* webAssemblyCallee() const { return m_wasmCallee.get(); }
</del><span class="cx"> JSWebAssemblyInstance* instance() const { return m_instance.get(); }
</span><del>- const Wasm::Signature* signature()
</del><ins>+ Wasm::Signature* signature()
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(m_signature);
</span><span class="cx"> return m_signature;
</span><span class="cx"> }
</span><span class="cx"> EncodedJSValue call(VM&, ProtoCallFrame*);
</span><ins>+ void* wasmEntrypoint() { return m_wasmEntrypoint->entrypoint(); }
</ins><span class="cx">
</span><span class="cx"> protected:
</span><span class="cx"> static void visitChildren(JSCell*, SlotVisitor&);
</span><span class="cx">
</span><del>- void finishCreation(VM&, NativeExecutable*, unsigned length, const String& name, JSWebAssemblyInstance*, JSWebAssemblyCallee*, Wasm::Signature*);
</del><ins>+ void finishCreation(VM&, NativeExecutable*, unsigned length, const String& name, JSWebAssemblyInstance*, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::Signature*);
</ins><span class="cx">
</span><span class="cx"> private:
</span><span class="cx"> WebAssemblyFunction(VM&, JSGlobalObject*, Structure*);
</span><span class="cx">
</span><span class="cx"> WriteBarrier<JSWebAssemblyInstance> m_instance;
</span><del>- WriteBarrier<JSWebAssemblyCallee> m_wasmCallee;
</del><ins>+ WriteBarrier<JSWebAssemblyCallee> m_jsEntrypoint;
+ WriteBarrier<JSWebAssemblyCallee> m_wasmEntrypoint;
</ins><span class="cx"> Wasm::Signature* m_signature;
</span><span class="cx"> };
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyInstanceConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -88,10 +88,10 @@
</span><span class="cx"> // Let imports be an initially-empty list of external values.
</span><span class="cx"> unsigned numImportFunctions = 0;
</span><span class="cx">
</span><del>- // FIXME implement Table https://bugs.webkit.org/show_bug.cgi?id=164135
</del><span class="cx"> // FIXME implement Global https://bugs.webkit.org/show_bug.cgi?id=164133
</span><span class="cx">
</span><span class="cx"> bool hasMemoryImport = false;
</span><ins>+ bool hasTableImport = false;
</ins><span class="cx"> // For each import i in module.imports:
</span><span class="cx"> for (auto& import : moduleInformation.imports) {
</span><span class="cx"> // 1. Let o be the resultant value of performing Get(importObject, i.module_name).
</span><span class="lines">@@ -131,12 +131,34 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case Wasm::External::Table: {
</span><ins>+ RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure.
</ins><span class="cx"> // 7. Otherwise (i is a table import):
</span><del>- // FIXME implement Table https://bugs.webkit.org/show_bug.cgi?id=164135
</del><ins>+ hasTableImport = true;
+ JSWebAssemblyTable* table = jsDynamicCast<JSWebAssemblyTable*>(value);
</ins><span class="cx"> // i. If v is not a WebAssembly.Table object, throw a TypeError.
</span><ins>+ if (!table)
+ return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("Table import is not an instance of WebAssembly.Table"))));
+
+ uint32_t expectedInitial = moduleInformation.tableInformation.initial();
+ uint32_t actualInitial = table->size();
+ if (actualInitial < expectedInitial)
+ return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("Table import provided an 'initial' that is too small"))));
+
+ if (std::optional<uint32_t> expectedMaximum = moduleInformation.tableInformation.maximum()) {
+ std::optional<uint32_t> actualMaximum = table->maximum();
+ if (!actualMaximum) {
+ return JSValue::encode(
+ throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("Table import does not have a 'maximum' but the module requires that it does"))));
+ }
+ if (*actualMaximum > *expectedMaximum) {
+ return JSValue::encode(
+ throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("Imported Table's 'maximum' is larger than the module's expected 'maximum'"))));
+ }
+ }
+
</ins><span class="cx"> // ii. Append v to tables.
</span><span class="cx"> // iii. Append v.[[Table]] to imports.
</span><del>- RELEASE_ASSERT_NOT_REACHED();
</del><ins>+ instance->setTable(vm, table);
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case Wasm::External::Memory: {
</span><span class="lines">@@ -185,7 +207,7 @@
</span><span class="cx">
</span><span class="cx"> {
</span><span class="cx"> if (!!moduleInformation.memory && moduleInformation.memory.isImport()) {
</span><del>- // We should either have an import or we should have thrown an exception.
</del><ins>+ // We should either have a Memory import or we should have thrown an exception.
</ins><span class="cx"> RELEASE_ASSERT(hasMemoryImport);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -200,6 +222,25 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ {
+ if (!!moduleInformation.tableInformation && moduleInformation.tableInformation.isImport()) {
+ // We should either have a Table import or we should have thrown an exception.
+ RELEASE_ASSERT(hasTableImport);
+ }
+
+ if (!!moduleInformation.tableInformation && !hasTableImport) {
+ RELEASE_ASSERT(!moduleInformation.tableInformation.isImport());
+ // We create a Table when it's a Table definition.
+ JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(),
+ moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum());
+ // We should always be able to allocate a JSWebAssemblyTable we've defined.
+ // If it's defined to be too large, we should have thrown a validation error.
+ ASSERT(!throwScope.exception());
+ ASSERT(table);
+ instance->setTable(vm, table);
+ }
+ }
+
</ins><span class="cx"> moduleRecord->link(exec, instance);
</span><span class="cx"> RETURN_IF_EXCEPTION(throwScope, { });
</span><span class="cx"> if (verbose)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyMemoryConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryConstructor.cpp (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryConstructor.cpp        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryConstructor.cpp        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx">
</span><span class="cx"> #include "FunctionPrototype.h"
</span><span class="cx"> #include "JSCInlines.h"
</span><ins>+#include "JSWebAssemblyHelpers.h"
</ins><span class="cx"> #include "JSWebAssemblyMemory.h"
</span><span class="cx"> #include "WasmMemory.h"
</span><span class="cx"> #include "WasmPageCount.h"
</span><span class="lines">@@ -54,17 +55,6 @@
</span><span class="cx"> if (exec->argumentCount() != 1)
</span><span class="cx"> return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("WebAssembly.Memory expects exactly one argument"))));
</span><span class="cx">
</span><del>- auto getUint32 = [&] (JSValue value) -> uint32_t {
- double doubleValue = value.toInteger(exec);
- RETURN_IF_EXCEPTION(throwScope, { });
- if (doubleValue < 0 || doubleValue > UINT_MAX) {
- throwException(exec, throwScope,
- createRangeError(exec, ASCIILiteral("WebAssembly.Memory expects the 'initial' and 'maximum' properties to be integers in the range: [0, 2^32 - 1]")));
- return 0;
- }
- return static_cast<uint32_t>(doubleValue);
- };
-
</del><span class="cx"> JSObject* memoryDescriptor;
</span><span class="cx"> {
</span><span class="cx"> JSValue argument = exec->argument(0);
</span><span class="lines">@@ -78,7 +68,7 @@
</span><span class="cx"> Identifier initial = Identifier::fromString(&vm, "initial");
</span><span class="cx"> JSValue minSizeValue = memoryDescriptor->get(exec, initial);
</span><span class="cx"> RETURN_IF_EXCEPTION(throwScope, { });
</span><del>- uint32_t size = getUint32(minSizeValue);
</del><ins>+ uint32_t size = toNonWrappingUint32(exec, minSizeValue);
</ins><span class="cx"> RETURN_IF_EXCEPTION(throwScope, { });
</span><span class="cx"> if (!Wasm::PageCount::isValid(size))
</span><span class="cx"> return JSValue::encode(throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory 'initial' page count is too large"))));
</span><span class="lines">@@ -93,10 +83,10 @@
</span><span class="cx"> if (hasProperty) {
</span><span class="cx"> JSValue maxSizeValue = memoryDescriptor->get(exec, maximum);
</span><span class="cx"> RETURN_IF_EXCEPTION(throwScope, { });
</span><del>- uint32_t size = getUint32(maxSizeValue);
</del><ins>+ uint32_t size = toNonWrappingUint32(exec, maxSizeValue);
+ RETURN_IF_EXCEPTION(throwScope, { });
</ins><span class="cx"> if (!Wasm::PageCount::isValid(size))
</span><span class="cx"> return JSValue::encode(throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory 'maximum' page count is too large"))));
</span><del>- RETURN_IF_EXCEPTION(throwScope, { });
</del><span class="cx"> maximumPageCount = Wasm::PageCount(size);
</span><span class="cx">
</span><span class="cx"> if (initialPageCount > maximumPageCount) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyModuleRecordcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -77,7 +77,7 @@
</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=164135
</del><ins>+ // FIXME https://bugs.webkit.org/show_bug.cgi?id=165782
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case Wasm::External::Memory: {
</span><span class="lines">@@ -136,9 +136,10 @@
</span><span class="cx"> // a. Let func be an Exported Function Exotic Object created from c.
</span><span class="cx"> // b. Append func to funcs.
</span><span class="cx"> // c. Return func.
</span><del>- JSWebAssemblyCallee* wasmCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(exp.functionIndex);
</del><ins>+ JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(exp.functionIndex);
+ JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(exp.functionIndex);
</ins><span class="cx"> Wasm::Signature* signature = module->signatureForFunctionIndexSpace(exp.functionIndex);
</span><del>- WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), exp.field.string(), instance, wasmCallee, signature);
</del><ins>+ WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), exp.field.string(), instance, jsEntrypointCallee, wasmEntrypointCallee, signature);
</ins><span class="cx"> exportedValue = function;
</span><span class="cx"> if (hasStart && startFunctionIndexSpace == exp.functionIndex)
</span><span class="cx"> m_startFunction.set(vm, this, function);
</span><span class="lines">@@ -145,7 +146,7 @@
</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=164135
</del><ins>+ // FIXME https://bugs.webkit.org/show_bug.cgi?id=165782
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case Wasm::External::Memory: {
</span><span class="lines">@@ -174,8 +175,9 @@
</span><span class="cx"> // FIXME can start call imports / tables? This assumes not. https://github.com/WebAssembly/design/issues/896
</span><span class="cx"> if (!m_startFunction.get()) {
</span><span class="cx"> // The start function wasn't added above. It must be a purely internal function.
</span><del>- JSWebAssemblyCallee* wasmCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
- WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), "start", instance, wasmCallee, signature);
</del><ins>+ JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
+ JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
+ WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), "start", instance, jsEntrypointCallee, wasmEntrypointCallee, signature);
</ins><span class="cx"> m_startFunction.set(vm, this, function);
</span><span class="cx"> }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyTableConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyTableConstructor.cpp (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyTableConstructor.cpp        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyTableConstructor.cpp        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -30,6 +30,8 @@
</span><span class="cx">
</span><span class="cx"> #include "FunctionPrototype.h"
</span><span class="cx"> #include "JSCInlines.h"
</span><ins>+#include "JSWebAssemblyHelpers.h"
+#include "JSWebAssemblyTable.h"
</ins><span class="cx"> #include "WebAssemblyTablePrototype.h"
</span><span class="cx">
</span><span class="cx"> #include "WebAssemblyTableConstructor.lut.h"
</span><span class="lines">@@ -43,12 +45,53 @@
</span><span class="cx"> @end
</span><span class="cx"> */
</span><span class="cx">
</span><del>-static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyTable(ExecState* state)
</del><ins>+static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyTable(ExecState* exec)
</ins><span class="cx"> {
</span><del>- VM& vm = state->vm();
- auto scope = DECLARE_THROW_SCOPE(vm);
- // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
- return JSValue::encode(throwException(state, scope, createError(state, ASCIILiteral("WebAssembly doesn't yet implement the Table constructor property"))));
</del><ins>+ VM& vm = exec->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSObject* memoryDescriptor;
+ {
+ JSValue argument = exec->argument(0);
+ if (!argument.isObject())
+ return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("WebAssembly.Table expects its first argument to be an object"))));
+ memoryDescriptor = jsCast<JSObject*>(argument);
+ }
+
+ {
+ Identifier elementIdent = Identifier::fromString(&vm, "element");
+ JSValue elementValue = memoryDescriptor->get(exec, elementIdent);
+ RETURN_IF_EXCEPTION(throwScope, { });
+ String elementString = elementValue.toWTFString(exec);
+ RETURN_IF_EXCEPTION(throwScope, { });
+ if (elementString != "anyfunc")
+ return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("WebAssembly.Table expects its 'element' field to be the string 'anyfunc'"))));
+ }
+
+ Identifier initialIdent = Identifier::fromString(&vm, "initial");
+ JSValue initialSizeValue = memoryDescriptor->get(exec, initialIdent);
+ RETURN_IF_EXCEPTION(throwScope, { });
+ uint32_t initial = toNonWrappingUint32(exec, initialSizeValue);
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ std::optional<uint32_t> maximum;
+ Identifier maximumIdent = Identifier::fromString(&vm, "maximum");
+ bool hasProperty = memoryDescriptor->hasProperty(exec, maximumIdent);
+ RETURN_IF_EXCEPTION(throwScope, { });
+ if (hasProperty) {
+ JSValue maxSizeValue = memoryDescriptor->get(exec, maximumIdent);
+ RETURN_IF_EXCEPTION(throwScope, { });
+ maximum = toNonWrappingUint32(exec, maxSizeValue);
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ if (initial > *maximum) {
+ return JSValue::encode(throwException(exec, throwScope,
+ createRangeError(exec, ASCIILiteral("'maximum' property must be greater than or equal to the 'initial' property"))));
+ }
+ }
+
+ throwScope.release();
+ return JSValue::encode(JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyTableStructure(), initial, maximum));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL callJSWebAssemblyTable(ExecState* state)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyTablePrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyTablePrototype.cpp (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyTablePrototype.cpp        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyTablePrototype.cpp        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -30,6 +30,8 @@
</span><span class="cx">
</span><span class="cx"> #include "FunctionPrototype.h"
</span><span class="cx"> #include "JSCInlines.h"
</span><ins>+#include "JSWebAssemblyHelpers.h"
+#include "JSWebAssemblyTable.h"
</ins><span class="cx">
</span><span class="cx"> #include "WebAssemblyTablePrototype.lut.h"
</span><span class="cx">
</span><span class="lines">@@ -42,10 +44,112 @@
</span><span class="cx"> @end
</span><span class="cx"> */
</span><span class="cx">
</span><del>-WebAssemblyTablePrototype* WebAssemblyTablePrototype::create(VM& vm, JSGlobalObject*, Structure* structure)
</del><ins>+static ALWAYS_INLINE JSWebAssemblyTable* getTable(ExecState* exec, VM& vm, JSValue v)
</ins><span class="cx"> {
</span><ins>+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSWebAssemblyTable* result = jsDynamicCast<JSWebAssemblyTable*>(v);
+ if (!result) {
+ throwException(exec, throwScope,
+ createTypeError(exec, ASCIILiteral("expected |this| value to be an instance of WebAssembly.Table")));
+ return nullptr;
+ }
+ return result;
+}
+
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncLength(ExecState*);
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncGrow(ExecState*);
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncGet(ExecState*);
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncSet(ExecState*);
+
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncLength(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue());
+ RETURN_IF_EXCEPTION(throwScope, { });
+ return JSValue::encode(jsNumber(table->size()));
+}
+
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncGrow(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue());
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ uint32_t index = toNonWrappingUint32(exec, exec->argument(0));
+ RETURN_IF_EXCEPTION(throwScope, { });
+ if (!table->grow(index)) {
+ throwException(exec, throwScope,
+ createTypeError(exec, ASCIILiteral("WebAssembly.Table.prototype.grow could not grow the table")));
+ return { };
+ }
+
+ return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncGet(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue());
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ uint32_t index = toNonWrappingUint32(exec, exec->argument(0));
+ RETURN_IF_EXCEPTION(throwScope, { });
+ if (index >= table->size()) {
+ throwException(exec, throwScope,
+ createRangeError(exec, ASCIILiteral("WebAssembly.Table.prototype.get expects an integer less than the size of the table")));
+ return { };
+ }
+
+ if (WebAssemblyFunction* result = table->getFunction(index))
+ return JSValue::encode(result);
+ return JSValue::encode(jsNull());
+}
+
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncSet(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue());
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ JSValue value = exec->argument(1);
+ WebAssemblyFunction* function = jsDynamicCast<WebAssemblyFunction*>(value);
+ if (!value.isNull() && !function) {
+ throwException(exec, throwScope,
+ createTypeError(exec, ASCIILiteral("WebAssembly.Table.prototype.set expects the second argument to be null or an instance of WebAssembly.Function")));
+ return { };
+ }
+
+ uint32_t index = toNonWrappingUint32(exec, exec->argument(0));
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ if (index >= table->size()) {
+ throwException(exec, throwScope,
+ createRangeError(exec, ASCIILiteral("WebAssembly.Table.prototype.set expects an integer less than the size of the table")));
+ return { };
+ }
+
+ if (value.isNull())
+ table->clearFunction(index);
+ else {
+ ASSERT(!!function);
+ table->setFunction(vm, index, function);
+ }
+
+ return JSValue::encode(jsUndefined());
+}
+
+WebAssemblyTablePrototype* WebAssemblyTablePrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+{
</ins><span class="cx"> auto* object = new (NotNull, allocateCell<WebAssemblyTablePrototype>(vm.heap)) WebAssemblyTablePrototype(vm, structure);
</span><del>- object->finishCreation(vm);
</del><ins>+ object->finishCreation(vm, globalObject);
</ins><span class="cx"> return object;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -54,9 +158,14 @@
</span><span class="cx"> return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void WebAssemblyTablePrototype::finishCreation(VM& vm)
</del><ins>+void WebAssemblyTablePrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
</ins><span class="cx"> {
</span><span class="cx"> Base::finishCreation(vm);
</span><ins>+
+ JSC_NATIVE_GETTER("length", webAssemblyTableProtoFuncLength, DontEnum | Accessor);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("grow", webAssemblyTableProtoFuncGrow, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("get", webAssemblyTableProtoFuncGet, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("set", webAssemblyTableProtoFuncSet, DontEnum, 2);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> WebAssemblyTablePrototype::WebAssemblyTablePrototype(VM& vm, Structure* structure)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyTablePrototypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyTablePrototype.h (209770 => 209771)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyTablePrototype.h        2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyTablePrototype.h        2016-12-13 20:32:40 UTC (rev 209771)
</span><span class="lines">@@ -43,7 +43,7 @@
</span><span class="cx"> DECLARE_INFO;
</span><span class="cx">
</span><span class="cx"> protected:
</span><del>- void finishCreation(VM&);
</del><ins>+ void finishCreation(VM&, JSGlobalObject*);
</ins><span class="cx">
</span><span class="cx"> private:
</span><span class="cx"> WebAssemblyTablePrototype(VM&, Structure*);
</span></span></pre>
</div>
</div>
</body>
</html>