<!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>[209880] 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/209880">209880</a></dd>
<dt>Author</dt> <dd>jfbastien@apple.com</dd>
<dt>Date</dt> <dd>2016-12-15 15:42:19 -0800 (Thu, 15 Dec 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>WebAssembly: improve compilation error messages
https://bugs.webkit.org/show_bug.cgi?id=163919
Reviewed by Saam Barati.
JSTests:
Update error messages in these tests.
Use the assert.throws facility in many of them which weren't already.
* wasm/js-api/element.js:
(assert.throws.new.WebAssembly.Module.builder.WebAssembly):
(assert.throws):
* wasm/js-api/global-error.js:
(assert.throws.new.WebAssembly.Module.bin):
(assert.throws):
(new.Number):
* wasm/js-api/table.js:
(assert.throws.new.WebAssembly.Module.builder.WebAssembly):
(assert.throws):
(assertBadTableImport):
* wasm/js-api/test_Data.js:
(DataSectionWithoutMemory):
* wasm/js-api/test_Start.js:
(InvalidStartFunctionIndex):
* wasm/js-api/test_basic_api.js:
(const.c.in.constructorProperties.switch):
Source/JavaScriptCore:
The error handling messages were underwhelming because most
locations merely returned `false` on failure. This patch uses
std::expected to denote that failure isn't expected. Doing this
makes it almost impossible to mess up the code: either a function
returns a result (or a partial result for internal helpers) or an
error. We're not synchronizing the error string with the m_failed
bool anymore, and the caller will abort if they try to get a
result but the outcome was an error.
This also shortens the code significantly using macros, while also
judiciously preventing inlining of error handling code and biasing
towards success using UNLIKELY. This means that the generated code
should be more efficient (no string formatting on success, and
regalloc can avoid these unlikely paths).
The patch adds a few missing checks as well, especially related to
count limits and memory allocation failure.
As a follow-up I'd like to improve WTF::makeString further, so it
does coercions to string and understands ADL as I did in this
patch.
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::fail):
(JSC::Wasm::parseAndCompile):
* wasm/WasmB3IRGenerator.h:
* wasm/WasmFormat.h:
(JSC::Wasm::isValidExternalKind):
(JSC::Wasm::makeString):
* wasm/WasmFunctionParser.h:
* wasm/WasmModuleParser.cpp:
* wasm/WasmModuleParser.h:
* wasm/WasmParser.h:
(JSC::Wasm::FailureHelper::makeString):
(JSC::Wasm::Parser::fail):
(JSC::Wasm::Parser<SuccessType>::Parser):
(JSC::Wasm::Parser<SuccessType>::consumeCharacter):
(JSC::Wasm::Parser<SuccessType>::consumeString):
(JSC::Wasm::Parser<SuccessType>::consumeUTF8String):
(JSC::Wasm::Parser<SuccessType>::parseVarUInt32):
(JSC::Wasm::Parser<SuccessType>::parseVarUInt64):
(JSC::Wasm::Parser<SuccessType>::parseVarInt32):
(JSC::Wasm::Parser<SuccessType>::parseVarInt64):
(JSC::Wasm::Parser<SuccessType>::parseUInt32):
(JSC::Wasm::Parser<SuccessType>::parseUInt64):
(JSC::Wasm::Parser<SuccessType>::parseUInt8):
(JSC::Wasm::Parser<SuccessType>::parseInt7):
(JSC::Wasm::Parser<SuccessType>::parseUInt7):
(JSC::Wasm::Parser<SuccessType>::parseVarUInt1):
(JSC::Wasm::Parser<SuccessType>::parseResultType):
(JSC::Wasm::Parser<SuccessType>::parseValueType):
(JSC::Wasm::Parser<SuccessType>::parseExternalKind):
* wasm/WasmPlan.cpp:
(JSC::Wasm::Plan::run):
* wasm/WasmSections.h:
(JSC::Wasm::isValidSection):
(JSC::Wasm::validateOrder):
(JSC::Wasm::makeString):
* wasm/WasmValidate.cpp:
(JSC::Wasm::Validate::fail):
(JSC::Wasm::Validate::addUnreachable):
(JSC::Wasm::validateFunction):
* wasm/WasmValidate.h:
* wasm/generateWasmB3IRGeneratorInlinesHeader.py:
* wasm/generateWasmOpsHeader.py:
* wasm/generateWasmValidateInlinesHeader.py:
(loadMacro):
(storeMacro):
* wasm/js/WebAssemblyInstanceConstructor.cpp:
(JSC::constructJSWebAssemblyInstance):
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::link):</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkJSTestswasmjsapielementjs">trunk/JSTests/wasm/js-api/element.js</a></li>
<li><a href="#trunkJSTestswasmjsapiglobalerrorjs">trunk/JSTests/wasm/js-api/global-error.js</a></li>
<li><a href="#trunkJSTestswasmjsapitablejs">trunk/JSTests/wasm/js-api/table.js</a></li>
<li><a href="#trunkJSTestswasmjsapitest_Datajs">trunk/JSTests/wasm/js-api/test_Data.js</a></li>
<li><a href="#trunkJSTestswasmjsapitest_Startjs">trunk/JSTests/wasm/js-api/test_Start.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="#trunkSourceJavaScriptCorewasmWasmB3IRGeneratorcpp">trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmB3IRGeneratorh">trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h</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="#trunkSourceJavaScriptCorewasmWasmParserh">trunk/Source/JavaScriptCore/wasm/WasmParser.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmPlancpp">trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmSectionsh">trunk/Source/JavaScriptCore/wasm/WasmSections.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmValidatecpp">trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmValidateh">trunk/Source/JavaScriptCore/wasm/WasmValidate.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmgenerateWasmB3IRGeneratorInlinesHeaderpy">trunk/Source/JavaScriptCore/wasm/generateWasmB3IRGeneratorInlinesHeader.py</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmgenerateWasmOpsHeaderpy">trunk/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmgenerateWasmValidateInlinesHeaderpy">trunk/Source/JavaScriptCore/wasm/generateWasmValidateInlinesHeader.py</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyInstanceConstructorcpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyModuleRecordcpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/JSTests/ChangeLog        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -1,5 +1,33 @@
</span><span class="cx"> 2016-12-15 JF Bastien <jfbastien@apple.com>
</span><span class="cx">
</span><ins>+ WebAssembly: improve compilation error messages
+ https://bugs.webkit.org/show_bug.cgi?id=163919
+
+ Reviewed by Saam Barati.
+
+ Update error messages in these tests.
+ Use the assert.throws facility in many of them which weren't already.
+
+ * wasm/js-api/element.js:
+ (assert.throws.new.WebAssembly.Module.builder.WebAssembly):
+ (assert.throws):
+ * wasm/js-api/global-error.js:
+ (assert.throws.new.WebAssembly.Module.bin):
+ (assert.throws):
+ (new.Number):
+ * wasm/js-api/table.js:
+ (assert.throws.new.WebAssembly.Module.builder.WebAssembly):
+ (assert.throws):
+ (assertBadTableImport):
+ * wasm/js-api/test_Data.js:
+ (DataSectionWithoutMemory):
+ * wasm/js-api/test_Start.js:
+ (InvalidStartFunctionIndex):
+ * wasm/js-api/test_basic_api.js:
+ (const.c.in.constructorProperties.switch):
+
+2016-12-15 JF Bastien <jfbastien@apple.com>
+
</ins><span class="cx"> WebAssembly API: improve data section errors
</span><span class="cx"> https://bugs.webkit.org/show_bug.cgi?id=165733
</span><span class="cx">
</span></span></pre></div>
<a id="trunkJSTestswasmjsapielementjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/js-api/element.js (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/element.js        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/JSTests/wasm/js-api/element.js        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -1,21 +1,6 @@
</span><span class="cx"> import Builder from '../Builder.js';
</span><span class="cx"> import * as assert from '../assert.js';
</span><span class="cx">
</span><del>-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 badElementSectionString = "couldn't parse section Element";
-
</del><span class="cx"> {
</span><span class="cx"> // Bad element section b/c no Table section/import.
</span><span class="cx"> const builder = new Builder()
</span><span class="lines">@@ -33,7 +18,7 @@
</span><span class="cx"> .End()
</span><span class="cx"> .End();
</span><span class="cx">
</span><del>- assertBadBinary(builder, badElementSectionString);
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 22 / 41: Element section expects a Table to be present (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -56,7 +41,7 @@
</span><span class="cx"> .End()
</span><span class="cx"> .End();
</span><span class="cx">
</span><del>- assertBadBinary(builder, badElementSectionString);
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 30 / 47: Element section can only have one Table for now (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -79,7 +64,7 @@
</span><span class="cx"> .End()
</span><span class="cx"> .End();
</span><span class="cx">
</span><del>- assertBadBinary(builder, badElementSectionString);
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 35 / 49: Element section's 0th element writes to index 20 which exceeds the maximum 20 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -102,7 +87,7 @@
</span><span class="cx"> .End()
</span><span class="cx"> .End();
</span><span class="cx">
</span><del>- assertBadBinary(builder, badElementSectionString);
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 35 / 48: Element section's 0th element writes to index 20 which exceeds the maximum 20 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -125,7 +110,7 @@
</span><span class="cx"> .End()
</span><span class="cx"> .End();
</span><span class="cx">
</span><del>- assertBadBinary(builder, badElementSectionString);
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 38 / 50: Element section's 0th element's 2th index is 1 which exceeds the function index space size of 1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkJSTestswasmjsapiglobalerrorjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/js-api/global-error.js (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/global-error.js        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/JSTests/wasm/js-api/global-error.js        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -23,14 +23,7 @@
</span><span class="cx"> const bin = builder.WebAssembly();
</span><span class="cx"> bin.trim();
</span><span class="cx">
</span><del>- let passed = false;
- try {
- const module = new WebAssembly.Module(bin.get());
- } catch (e) {
- if (e.message === "couldn't parse section Global: Global declarations (evaluating 'new WebAssembly.Module(bin.get())')")
- passed = true;
- }
- assert.truthy(passed);
</del><ins>+ assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 26 / 59: get_global's index 0 exceeds the number of imports 0 (evaluating 'new WebAssembly.Module(bin.get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -59,14 +52,7 @@
</span><span class="cx"> const bin = builder.WebAssembly();
</span><span class="cx"> bin.trim();
</span><span class="cx">
</span><del>- let passed = false;
- try {
- const module = new WebAssembly.Module(bin.get());
- } catch (e) {
- if (e.message === "couldn't parse section Import: Import declarations (evaluating 'new WebAssembly.Module(bin.get())')")
- passed = true;
- }
- assert.truthy(passed);
</del><ins>+ assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 32 / 76: Mutable Globals aren't supported (evaluating 'new WebAssembly.Module(bin.get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -91,14 +77,7 @@
</span><span class="cx"> const bin = builder.WebAssembly();
</span><span class="cx"> bin.trim();
</span><span class="cx">
</span><del>- let passed = false;
- try {
- const module = new WebAssembly.Module(bin.get());
- } catch (e) {
- if (e.message === "couldn't parse section Export: Exports (evaluating 'new WebAssembly.Module(bin.get())')")
- passed = true;
- }
- assert.truthy(passed);
</del><ins>+ assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 51 / 59: 1th Export isn't immutable, named 'global' (evaluating 'new WebAssembly.Module(bin.get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -124,14 +103,7 @@
</span><span class="cx"> const bin = builder.WebAssembly();
</span><span class="cx"> bin.trim();
</span><span class="cx">
</span><del>- let passed = false;
- try {
- const module = new WebAssembly.Module(bin.get());
- } catch (e) {
- if (e.message === "Attempt to store to immutable global. (evaluating 'new WebAssembly.Module(bin.get())')")
- passed = true;
- }
- assert.truthy(passed);
</del><ins>+ assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: set_global 0 is immutable (evaluating 'new WebAssembly.Module(bin.get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -158,14 +130,7 @@
</span><span class="cx"> const bin = builder.WebAssembly();
</span><span class="cx"> bin.trim();
</span><span class="cx">
</span><del>- let passed = false;
- try {
- const module = new WebAssembly.Module(bin.get());
- } catch (e) {
- if (e.message === "Attempt to use unknown global. (evaluating 'new WebAssembly.Module(bin.get())')")
- passed = true;
- }
- assert.truthy(passed);
</del><ins>+ assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: set_global 1 of unknown global, limit is 1 (evaluating 'new WebAssembly.Module(bin.get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -191,14 +156,7 @@
</span><span class="cx"> const bin = builder.WebAssembly();
</span><span class="cx"> bin.trim();
</span><span class="cx">
</span><del>- let passed = false;
- try {
- const module = new WebAssembly.Module(bin.get());
- } catch (e) {
- if (e.message === "Attempt to set global with type: F32 with a variable of type: I32 (evaluating 'new WebAssembly.Module(bin.get())')")
- passed = true;
- }
- assert.truthy(passed);
</del><ins>+ assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: set_global 0 with type F32 with a variable of type I32 (evaluating 'new WebAssembly.Module(bin.get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> for ( let imp of [undefined, null, {}, () => {}, "number", new Number(4)]) {
</span><span class="lines">@@ -226,13 +184,6 @@
</span><span class="cx"> const bin = builder.WebAssembly();
</span><span class="cx"> bin.trim();
</span><span class="cx">
</span><del>- let passed = false;
</del><span class="cx"> const module = new WebAssembly.Module(bin.get());
</span><del>- try {
- new WebAssembly.Instance(module, { imp: { global: imp } });
- } catch (e) {
- if (e.message === "imported global must be a number (evaluating 'new WebAssembly.Instance(module, { imp: { global: imp } })')")
- passed = true;
- }
- assert.truthy(passed);
</del><ins>+ assert.throws(() => new WebAssembly.Instance(module, { imp: { global: imp } }), TypeError, "imported global must be a number (evaluating 'new WebAssembly.Instance(module, { imp: { global: imp } })')");
</ins><span class="cx"> }
</span></span></pre></div>
<a id="trunkJSTestswasmjsapitablejs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/js-api/table.js (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/table.js        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/JSTests/wasm/js-api/table.js        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -1,15 +1,6 @@
</span><span class="cx"> import Builder from '../Builder.js';
</span><span class="cx"> import * as assert from '../assert.js';
</span><span class="cx">
</span><del>-const badTableString = "couldn't parse section Table: Indirect function table and other tables (evaluating 'new WebAssembly.Module(bin)')";
-const badImportString = "couldn't parse section Import: Import declarations (evaluating 'new WebAssembly.Module(bin)')";
-const badExportString = "couldn't parse section Export: Exports (evaluating 'new WebAssembly.Module(bin)')";
-
-function assertBadBinary(builder, str) {
- const bin = builder.WebAssembly().get();
- assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, str);
-}
-
</del><span class="cx"> {
</span><span class="cx"> const builder = new Builder()
</span><span class="cx"> .Type().End()
</span><span class="lines">@@ -22,7 +13,7 @@
</span><span class="cx"> .End()
</span><span class="cx"> .Code()
</span><span class="cx"> .End();
</span><del>- assertBadBinary(builder, badTableString);
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 34 / 41: Table section cannot exist if an Import has a table (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -35,7 +26,7 @@
</span><span class="cx"> .End()
</span><span class="cx"> .Code()
</span><span class="cx"> .End();
</span><del>- assertBadBinary(builder, badTableString);
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 17 / 28: Table count of 2 is invalid, only 1 is allowed for now (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -51,7 +42,7 @@
</span><span class="cx"> .CallIndirect(0, 0)
</span><span class="cx"> .End()
</span><span class="cx"> .End();
</span><del>- assertBadBinary(builder, "call_indirect is only valid when a table is defined or imported (evaluating 'new WebAssembly.Module(bin)')");
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 4 / 7: call_indirect is only valid when a table is defined or imported (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -70,7 +61,7 @@
</span><span class="cx"> .CallIndirect(0, 1)
</span><span class="cx"> .End()
</span><span class="cx"> .End();
</span><del>- assertBadBinary(builder, "call_indirect 'reserved' varuint1 must be 0x0 (evaluating 'new WebAssembly.Module(bin)')");
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 6 / 7: call_indirect's 'reserved' varuint1 must be 0x0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -83,7 +74,7 @@
</span><span class="cx"> .End()
</span><span class="cx"> .Code()
</span><span class="cx"> .End();
</span><del>- assertBadBinary(builder, badExportString);
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 23 / 26: can't export a non-existent Table (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="lines">@@ -99,10 +90,10 @@
</span><span class="cx"> .End()
</span><span class="cx"> .Code()
</span><span class="cx"> .End();
</span><del>- assertBadBinary(builder, badExportString);
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 30 / 33: can't export Table 1 only zero-index Table is currently supported (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-function assertBadTable(tableDescription) {
</del><ins>+function assertBadTable(tableDescription, message) {
</ins><span class="cx"> const builder = new Builder()
</span><span class="cx"> .Type().End()
</span><span class="cx"> .Function().End()
</span><span class="lines">@@ -111,10 +102,10 @@
</span><span class="cx"> .End()
</span><span class="cx"> .Code()
</span><span class="cx"> .End();
</span><del>- assertBadBinary(builder, badTableString);
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, message);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-function assertBadTableImport(tableDescription) {
</del><ins>+function assertBadTableImport(tableDescription, message) {
</ins><span class="cx"> const builder = new Builder()
</span><span class="cx"> .Type().End()
</span><span class="cx"> .Import()
</span><span class="lines">@@ -123,29 +114,53 @@
</span><span class="cx"> .Function().End()
</span><span class="cx"> .Code()
</span><span class="cx"> .End();
</span><del>- assertBadBinary(builder, badImportString);
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, message);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> {
</span><span class="cx"> let badDescriptions = [
</span><del>- {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"},
</del><ins>+ [{initial: 10, element: "i32"},
+ "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+ "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+ [{initial: 10, element: "f32"},
+ "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+ "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+ [{initial: 10, element: "f64"},
+ "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+ "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+ [{initial: 10, element: "i64"},
+ "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+ "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+ [{initial: 10, maximum: 20, element: "i32"},
+ "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+ "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+ [{initial: 10, maximum: 20, element: "f32"},
+ "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+ "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+ [{initial: 10, maximum: 20, element: "f64"},
+ "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+ "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+ [{initial: 10, maximum: 20, element: "i64"},
+ "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+ "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
</ins><span class="cx">
</span><del>- {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"},
</del><ins>+ [{initial: 10, maximum: 9, element: "anyfunc"},
+ "WebAssembly.Module doesn't parse at byte 21 / 24: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+ "WebAssembly.Module doesn't parse at byte 29 / 35: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+ [{initial: 1, maximum: 0, element: "anyfunc"},
+ "WebAssembly.Module doesn't parse at byte 21 / 24: resizable limits has a initial page count of 1 which is greater than its maximum 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+ "WebAssembly.Module doesn't parse at byte 29 / 35: resizable limits has a initial page count of 1 which is greater than its maximum 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+ [{initial: 2**32 - 1, maximum: 2**32 - 2, element: "anyfunc"},
+ "WebAssembly.Module doesn't parse at byte 29 / 32: resizable limits has a initial page count of 4294967295 which is greater than its maximum 4294967294 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+ "WebAssembly.Module doesn't parse at byte 37 / 43: resizable limits has a initial page count of 4294967295 which is greater than its maximum 4294967294 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+ [{initial: 2**31, element: "anyfunc"},
+ "WebAssembly.Module doesn't parse at byte 24 / 27: Table's initial page count of 2147483648 is invalid (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+ "WebAssembly.Module doesn't parse at byte 32 / 38: Table's initial page count of 2147483648 is invalid (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
</ins><span class="cx"> ];
</span><span class="cx">
</span><span class="cx"> for (const d of badDescriptions) {
</span><del>- assertBadTable(d);
- assertBadTableImport(d);
</del><ins>+ assertBadTable(d[0], d[1]);
+ assertBadTableImport(d[0], d[2]);
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -159,7 +174,7 @@
</span><span class="cx"> .Function().End()
</span><span class="cx"> .Code()
</span><span class="cx"> .End();
</span><del>- assertBadBinary(builder, badImportString);
</del><ins>+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 39 / 48: Table section cannot exist if an Import has a table (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -173,23 +188,15 @@
</span><span class="cx"> .Function().End()
</span><span class="cx"> .Code()
</span><span class="cx"> .End();
</span><del>-
- let threw = false;
</del><span class="cx"> const module = new WebAssembly.Module(builder.WebAssembly().get());
</span><del>- try {
- new WebAssembly.Instance(module, {imp: {table}});
- } catch (e) {
- assert.eq(e.toString(), message);
- threw = true;
- }
- assert.truthy(threw);
</del><ins>+ assert.throws(() => new WebAssembly.Instance(module, {imp: {table}}), TypeError, message);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> const badTables = [
</span><del>- [{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"],
</del><ins>+ [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, element: "anyfunc"}), "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"}), "Imported Table's 'maximum' is larger than the module's expected 'maximum'"],
+ [{initial: 100, element:"anyfunc"}, new WebAssembly.Table({initial:10, element: "anyfunc"}), "Table import provided an 'initial' that is too small"],
+ [{initial: 10, element:"anyfunc"}, new WebAssembly.Table({initial:9, element: "anyfunc"}), "Table import provided an 'initial' that is too small"],
</ins><span class="cx"> ];
</span><span class="cx"> for (const [d, t, m] of badTables) {
</span><span class="cx"> assertBadTableInstance(d, t, m);
</span></span></pre></div>
<a id="trunkJSTestswasmjsapitest_Datajs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/js-api/test_Data.js (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/test_Data.js        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/JSTests/wasm/js-api/test_Data.js        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -52,7 +52,7 @@
</span><span class="cx"> .Segment([0xff]).Offset(0).End()
</span><span class="cx"> .End();
</span><span class="cx"> const bin = builder.WebAssembly().get();
</span><del>- assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `couldn't parse section Data: Data segments (evaluating 'new WebAssembly.Module(bin)')`);
</del><ins>+ assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 13 / 20: Data section cannot exist without a Memory section or Import (evaluating 'new WebAssembly.Module(bin)')`);
</ins><span class="cx"> })();
</span><span class="cx">
</span><span class="cx"> (function EmptyDataSectionWithoutMemory() {
</span><span class="lines">@@ -62,7 +62,7 @@
</span><span class="cx"> .Segment([]).Offset(0).End()
</span><span class="cx"> .End();
</span><span class="cx"> const bin = builder.WebAssembly().get();
</span><del>- assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `couldn't parse section Data: Data segments (evaluating 'new WebAssembly.Module(bin)')`);
</del><ins>+ assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 13 / 19: Data section cannot exist without a Memory section or Import (evaluating 'new WebAssembly.Module(bin)')`);
</ins><span class="cx"> })();
</span><span class="cx">
</span><span class="cx"> (function DataSectionBiggerThanMemory() {
</span></span></pre></div>
<a id="trunkJSTestswasmjsapitest_Startjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/js-api/test_Start.js (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/test_Start.js        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/JSTests/wasm/js-api/test_Start.js        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -31,5 +31,5 @@
</span><span class="cx"> .Start(0).End() // Invalid index.
</span><span class="cx"> .Code().End();
</span><span class="cx"> const bin = b.WebAssembly().get();
</span><del>- assert.throws(() => new WebAssembly.Module(bin), Error, `couldn't parse section Start: Start function declaration (evaluating 'new WebAssembly.Module(bin)')`);
</del><ins>+ assert.throws(() => new WebAssembly.Module(bin), Error, `WebAssembly.Module doesn't parse at byte 17 / 20: Start index 0 exceeds function index space 0 (evaluating 'new WebAssembly.Module(bin)')`);
</ins><span class="cx"> })();
</span></span></pre></div>
<a id="trunkJSTestswasmjsapitest_basic_apijs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/js-api/test_basic_api.js (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/wasm/js-api/test_basic_api.js        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/JSTests/wasm/js-api/test_basic_api.js        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -55,7 +55,7 @@
</span><span class="cx"> assert.throws(() => new WebAssembly[c](invalid), TypeError, `first argument to WebAssembly.Module must be an ArrayBufferView or an ArrayBuffer (evaluating 'new WebAssembly[c](invalid)')`);
</span><span class="cx"> for (const buffer of [new ArrayBuffer(), new DataView(new ArrayBuffer()), new Int8Array(), new Uint8Array(), new Uint8ClampedArray(), new Int16Array(), new Uint16Array(), new Int32Array(), new Uint32Array(), new Float32Array(), new Float64Array()])
</span><span class="cx"> // FIXME the following should be WebAssembly.CompileError. https://bugs.webkit.org/show_bug.cgi?id=163768
</span><del>- assert.throws(() => new WebAssembly[c](buffer), Error, `Module is 0 bytes, expected at least 8 bytes (evaluating 'new WebAssembly[c](buffer)')`);
</del><ins>+ assert.throws(() => new WebAssembly[c](buffer), Error, `WebAssembly.Module doesn't parse at byte 0 / 0: expected a module of at least 8 bytes (evaluating 'new WebAssembly[c](buffer)')`);
</ins><span class="cx"> assert.instanceof(new WebAssembly[c](emptyModuleArray), WebAssembly.Module);
</span><span class="cx"> // FIXME test neutered TypedArray and TypedArrayView. https://bugs.webkit.org/show_bug.cgi?id=163899
</span><span class="cx"> break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -1,5 +1,85 @@
</span><span class="cx"> 2016-12-15 JF Bastien <jfbastien@apple.com>
</span><span class="cx">
</span><ins>+ WebAssembly: improve compilation error messages
+ https://bugs.webkit.org/show_bug.cgi?id=163919
+
+ Reviewed by Saam Barati.
+
+ The error handling messages were underwhelming because most
+ locations merely returned `false` on failure. This patch uses
+ std::expected to denote that failure isn't expected. Doing this
+ makes it almost impossible to mess up the code: either a function
+ returns a result (or a partial result for internal helpers) or an
+ error. We're not synchronizing the error string with the m_failed
+ bool anymore, and the caller will abort if they try to get a
+ result but the outcome was an error.
+
+ This also shortens the code significantly using macros, while also
+ judiciously preventing inlining of error handling code and biasing
+ towards success using UNLIKELY. This means that the generated code
+ should be more efficient (no string formatting on success, and
+ regalloc can avoid these unlikely paths).
+
+ The patch adds a few missing checks as well, especially related to
+ count limits and memory allocation failure.
+
+ As a follow-up I'd like to improve WTF::makeString further, so it
+ does coercions to string and understands ADL as I did in this
+ patch.
+
+ * wasm/WasmB3IRGenerator.cpp:
+ (JSC::Wasm::B3IRGenerator::fail):
+ (JSC::Wasm::parseAndCompile):
+ * wasm/WasmB3IRGenerator.h:
+ * wasm/WasmFormat.h:
+ (JSC::Wasm::isValidExternalKind):
+ (JSC::Wasm::makeString):
+ * wasm/WasmFunctionParser.h:
+ * wasm/WasmModuleParser.cpp:
+ * wasm/WasmModuleParser.h:
+ * wasm/WasmParser.h:
+ (JSC::Wasm::FailureHelper::makeString):
+ (JSC::Wasm::Parser::fail):
+ (JSC::Wasm::Parser<SuccessType>::Parser):
+ (JSC::Wasm::Parser<SuccessType>::consumeCharacter):
+ (JSC::Wasm::Parser<SuccessType>::consumeString):
+ (JSC::Wasm::Parser<SuccessType>::consumeUTF8String):
+ (JSC::Wasm::Parser<SuccessType>::parseVarUInt32):
+ (JSC::Wasm::Parser<SuccessType>::parseVarUInt64):
+ (JSC::Wasm::Parser<SuccessType>::parseVarInt32):
+ (JSC::Wasm::Parser<SuccessType>::parseVarInt64):
+ (JSC::Wasm::Parser<SuccessType>::parseUInt32):
+ (JSC::Wasm::Parser<SuccessType>::parseUInt64):
+ (JSC::Wasm::Parser<SuccessType>::parseUInt8):
+ (JSC::Wasm::Parser<SuccessType>::parseInt7):
+ (JSC::Wasm::Parser<SuccessType>::parseUInt7):
+ (JSC::Wasm::Parser<SuccessType>::parseVarUInt1):
+ (JSC::Wasm::Parser<SuccessType>::parseResultType):
+ (JSC::Wasm::Parser<SuccessType>::parseValueType):
+ (JSC::Wasm::Parser<SuccessType>::parseExternalKind):
+ * wasm/WasmPlan.cpp:
+ (JSC::Wasm::Plan::run):
+ * wasm/WasmSections.h:
+ (JSC::Wasm::isValidSection):
+ (JSC::Wasm::validateOrder):
+ (JSC::Wasm::makeString):
+ * wasm/WasmValidate.cpp:
+ (JSC::Wasm::Validate::fail):
+ (JSC::Wasm::Validate::addUnreachable):
+ (JSC::Wasm::validateFunction):
+ * wasm/WasmValidate.h:
+ * wasm/generateWasmB3IRGeneratorInlinesHeader.py:
+ * wasm/generateWasmOpsHeader.py:
+ * wasm/generateWasmValidateInlinesHeader.py:
+ (loadMacro):
+ (storeMacro):
+ * wasm/js/WebAssemblyInstanceConstructor.cpp:
+ (JSC::constructJSWebAssemblyInstance):
+ * wasm/js/WebAssemblyModuleRecord.cpp:
+ (JSC::WebAssemblyModuleRecord::link):
+
+2016-12-15 JF Bastien <jfbastien@apple.com>
+
</ins><span class="cx"> WebAssembly API: improve data section errors, initialize after Element
</span><span class="cx"> https://bugs.webkit.org/show_bug.cgi?id=165733
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmB3IRGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -137,53 +137,66 @@
</span><span class="cx">
</span><span class="cx"> static constexpr ExpressionType emptyExpression = nullptr;
</span><span class="cx">
</span><ins>+ typedef String ErrorType;
+ typedef UnexpectedType<ErrorType> UnexpectedResult;
+ typedef Expected<std::unique_ptr<WasmInternalFunction>, ErrorType> Result;
+ typedef Expected<void, ErrorType> PartialResult;
+ template <typename ...Args>
+ NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const
+ {
+ using namespace FailureHelper; // See ADL comment in WasmParser.h.
+ return UnexpectedResult(makeString(ASCIILiteral("WebAssembly.Module failed compiling: "), makeString(args)...));
+ }
+#define WASM_COMPILE_FAIL_IF(condition, ...) do { \
+ if (UNLIKELY(condition)) \
+ return fail(__VA_ARGS__); \
+ } while (0)
+
</ins><span class="cx"> B3IRGenerator(VM&, const ModuleInformation&, Procedure&, WasmInternalFunction*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&);
</span><span class="cx">
</span><del>- bool WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
- bool WARN_UNUSED_RETURN addLocal(Type, uint32_t);
</del><ins>+ PartialResult WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
+ PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t);
</ins><span class="cx"> ExpressionType addConstant(Type, uint64_t);
</span><span class="cx">
</span><span class="cx"> // Locals
</span><del>- bool WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
- bool WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
</del><ins>+ PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
+ PartialResult WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
</ins><span class="cx">
</span><span class="cx"> // Globals
</span><del>- bool WARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result);
- bool WARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value);
</del><ins>+ PartialResult WARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result);
+ PartialResult WARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value);
</ins><span class="cx">
</span><span class="cx"> // Memory
</span><del>- bool WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
- bool WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
</del><ins>+ PartialResult WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
+ PartialResult WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
</ins><span class="cx">
</span><span class="cx"> // Basic operators
</span><span class="cx"> template<OpType>
</span><del>- bool WARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result);
</del><ins>+ PartialResult WARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result);
</ins><span class="cx"> template<OpType>
</span><del>- bool WARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result);
- bool WARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result);
</del><ins>+ PartialResult WARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result);
+ PartialResult WARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result);
</ins><span class="cx">
</span><span class="cx"> // Control flow
</span><span class="cx"> ControlData WARN_UNUSED_RETURN addBlock(Type signature);
</span><span class="cx"> ControlData WARN_UNUSED_RETURN addLoop(Type signature);
</span><del>- bool WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);
- bool WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);
- bool WARN_UNUSED_RETURN addElseToUnreachable(ControlData&);
</del><ins>+ PartialResult WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);
+ PartialResult WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);
+ PartialResult WARN_UNUSED_RETURN addElseToUnreachable(ControlData&);
</ins><span class="cx">
</span><del>- bool WARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues);
- bool WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& returnValues);
- bool WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTargets, const ExpressionList& expressionStack);
- bool WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);
- bool WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);
</del><ins>+ PartialResult WARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues);
+ PartialResult WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& returnValues);
+ PartialResult WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTargets, const ExpressionList& expressionStack);
+ PartialResult WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);
+ PartialResult WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);
</ins><span class="cx">
</span><span class="cx"> // Calls
</span><del>- bool WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature*, Vector<ExpressionType>& args, ExpressionType& result);
- bool WARN_UNUSED_RETURN addCallIndirect(const Signature*, Vector<ExpressionType>& args, ExpressionType& result);
- void addUnreachable();
</del><ins>+ PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature*, Vector<ExpressionType>& args, ExpressionType& result);
+ PartialResult WARN_UNUSED_RETURN addCallIndirect(const Signature*, Vector<ExpressionType>& args, ExpressionType& result);
+ PartialResult WARN_UNUSED_RETURN addUnreachable();
</ins><span class="cx">
</span><span class="cx"> void dump(const Vector<ControlEntry>& controlStack, const ExpressionList& expressionStack);
</span><span class="cx">
</span><del>- void setErrorMessage(String&&) { UNREACHABLE_FOR_PLATFORM(); }
-
</del><span class="cx"> private:
</span><span class="cx"> ExpressionType emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOp);
</span><span class="cx"> ExpressionType emitLoadOp(LoadOpType, Origin, ExpressionType pointer, uint32_t offset);
</span><span class="lines">@@ -291,10 +304,9 @@
</span><span class="cx"> return zeroValue;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::addLocal(Type type, uint32_t count)
</del><ins>+auto B3IRGenerator::addLocal(Type type, uint32_t count) -> PartialResult
</ins><span class="cx"> {
</span><del>- if (!m_locals.tryReserveCapacity(m_locals.size() + count))
- return false;
</del><ins>+ WASM_COMPILE_FAIL_IF(!m_locals.tryReserveCapacity(m_locals.size() + count), "can't allocate memory for ", m_locals.size() + count, " locals");
</ins><span class="cx">
</span><span class="cx"> for (uint32_t i = 0; i < count; ++i) {
</span><span class="cx"> Variable* local = m_proc.addVariable(toB3Type(type));
</span><span class="lines">@@ -301,14 +313,13 @@
</span><span class="cx"> m_locals.uncheckedAppend(local);
</span><span class="cx"> m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), local, zeroForType(type));
</span><span class="cx"> }
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::addArguments(const Vector<Type>& types)
</del><ins>+auto B3IRGenerator::addArguments(const Vector<Type>& types) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(!m_locals.size());
</span><del>- if (!m_locals.tryReserveCapacity(types.size()))
- return false;
</del><ins>+ WASM_COMPILE_FAIL_IF(!m_locals.tryReserveCapacity(types.size()), "can't allocate memory for ", types.size(), " arguments");
</ins><span class="cx">
</span><span class="cx"> m_locals.grow(types.size());
</span><span class="cx"> wasmCallingConvention().loadArguments(types, m_proc, m_currentBlock, Origin(),
</span><span class="lines">@@ -317,17 +328,17 @@
</span><span class="cx"> m_locals[i] = argumentVariable;
</span><span class="cx"> m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), argumentVariable, argument);
</span><span class="cx"> });
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::getLocal(uint32_t index, ExpressionType& result)
</del><ins>+auto B3IRGenerator::getLocal(uint32_t index, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(m_locals[index]);
</span><span class="cx"> result = m_currentBlock->appendNew<VariableValue>(m_proc, B3::Get, Origin(), m_locals[index]);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-void B3IRGenerator::addUnreachable()
</del><ins>+auto B3IRGenerator::addUnreachable() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> B3::PatchpointValue* unreachable = m_currentBlock->appendNew<B3::PatchpointValue>(m_proc, B3::Void, Origin());
</span><span class="cx"> unreachable->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
</span><span class="lines">@@ -334,28 +345,29 @@
</span><span class="cx"> jit.breakpoint();
</span><span class="cx"> });
</span><span class="cx"> unreachable->effects.terminal = true;
</span><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::setLocal(uint32_t index, ExpressionType value)
</del><ins>+auto B3IRGenerator::setLocal(uint32_t index, ExpressionType value) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(m_locals[index]);
</span><span class="cx"> m_currentBlock->appendNew<VariableValue>(m_proc, B3::Set, Origin(), m_locals[index], value);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::getGlobal(uint32_t index, ExpressionType& result)
</del><ins>+auto B3IRGenerator::getGlobal(uint32_t index, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfGlobals());
</span><span class="cx"> result = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, toB3Type(m_info.globals[index].type), Origin(), globalsArray, index * sizeof(Register));
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::setGlobal(uint32_t index, ExpressionType value)
</del><ins>+auto B3IRGenerator::setGlobal(uint32_t index, ExpressionType value) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(toB3Type(m_info.globals[index].type) == value->type());
</span><span class="cx"> Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfGlobals());
</span><span class="cx"> m_currentBlock->appendNew<MemoryValue>(m_proc, Store, Origin(), value, globalsArray, index * sizeof(Register));
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> inline Value* B3IRGenerator::emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOperation)
</span><span class="lines">@@ -465,12 +477,12 @@
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t offset)
</del><ins>+auto B3IRGenerator::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t offset) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(pointer->type() == Int32);
</span><span class="cx">
</span><span class="cx"> result = emitLoadOp(op, Origin(), emitCheckAndPreparePointer(pointer, offset, sizeOfLoadOp(op)), offset);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> inline uint32_t sizeOfStoreOp(StoreOpType op)
</span><span class="lines">@@ -527,18 +539,18 @@
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t offset)
</del><ins>+auto B3IRGenerator::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t offset) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(pointer->type() == Int32);
</span><span class="cx">
</span><span class="cx"> emitStoreOp(op, Origin(), emitCheckAndPreparePointer(pointer, offset, sizeOfStoreOp(op)), value, offset);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> result = m_currentBlock->appendNew<Value>(m_proc, B3::Select, Origin(), condition, nonZero, zero);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> B3IRGenerator::ExpressionType B3IRGenerator::addConstant(Type type, uint64_t value)
</span><span class="lines">@@ -576,7 +588,7 @@
</span><span class="cx"> return ControlData(m_proc, signature, BlockType::Loop, continuation, body);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::addIf(ExpressionType condition, Type signature, ControlType& result)
</del><ins>+auto B3IRGenerator::addIf(ExpressionType condition, Type signature, ControlType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> // FIXME: This needs to do some kind of stack passing.
</span><span class="cx">
</span><span class="lines">@@ -591,10 +603,10 @@
</span><span class="cx">
</span><span class="cx"> m_currentBlock = taken;
</span><span class="cx"> result = ControlData(m_proc, signature, BlockType::If, continuation, notTaken);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::addElse(ControlData& data, const ExpressionList& currentStack)
</del><ins>+auto B3IRGenerator::addElse(ControlData& data, const ExpressionList& currentStack) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> unifyValuesWithBlock(currentStack, data.result);
</span><span class="cx"> m_currentBlock->appendNewControlValue(m_proc, Jump, Origin(), data.continuation);
</span><span class="lines">@@ -601,15 +613,15 @@
</span><span class="cx"> return addElseToUnreachable(data);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::addElseToUnreachable(ControlData& data)
</del><ins>+auto B3IRGenerator::addElseToUnreachable(ControlData& data) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(data.type() == BlockType::If);
</span><span class="cx"> m_currentBlock = data.special;
</span><span class="cx"> data.convertIfToBlock();
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::addReturn(const ExpressionList& returnValues)
</del><ins>+auto B3IRGenerator::addReturn(const ExpressionList& returnValues) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(returnValues.size() <= 1);
</span><span class="cx"> if (returnValues.size())
</span><span class="lines">@@ -616,10 +628,10 @@
</span><span class="cx"> m_currentBlock->appendNewControlValue(m_proc, B3::Return, Origin(), returnValues[0]);
</span><span class="cx"> else
</span><span class="cx"> m_currentBlock->appendNewControlValue(m_proc, B3::Return, Origin());
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::addBranch(ControlData& data, ExpressionType condition, const ExpressionList& returnValues)
</del><ins>+auto B3IRGenerator::addBranch(ControlData& data, ExpressionType condition, const ExpressionList& returnValues) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> if (data.type() != BlockType::Loop)
</span><span class="cx"> unifyValuesWithBlock(returnValues, data.result);
</span><span class="lines">@@ -637,10 +649,10 @@
</span><span class="cx"> target->addPredecessor(m_currentBlock);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack)
</del><ins>+auto B3IRGenerator::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> for (size_t i = 0; i < targets.size(); ++i)
</span><span class="cx"> unifyValuesWithBlock(expressionStack, targets[i]->result);
</span><span class="lines">@@ -651,10 +663,10 @@
</span><span class="cx"> for (size_t i = 0; i < targets.size(); ++i)
</span><span class="cx"> switchValue->appendCase(SwitchCase(i, FrequentedBlock(targets[i]->targetBlockForBranch())));
</span><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::endBlock(ControlEntry& entry, ExpressionList& expressionStack)
</del><ins>+auto B3IRGenerator::endBlock(ControlEntry& entry, ExpressionList& expressionStack) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ControlData& data = entry.controlData;
</span><span class="cx">
</span><span class="lines">@@ -666,7 +678,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span><del>-bool B3IRGenerator::addEndToUnreachable(ControlEntry& entry)
</del><ins>+auto B3IRGenerator::addEndToUnreachable(ControlEntry& entry) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ControlData& data = entry.controlData;
</span><span class="cx"> m_currentBlock = data.continuation;
</span><span class="lines">@@ -679,10 +691,10 @@
</span><span class="cx"> for (Variable* result : data.result)
</span><span class="cx"> entry.enclosedExpressionStack.append(m_currentBlock->appendNew<VariableValue>(m_proc, B3::Get, Origin(), result));
</span><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(signature->arguments.size() == args.size());
</span><span class="cx">
</span><span class="lines">@@ -705,10 +717,10 @@
</span><span class="cx"> });
</span><span class="cx"> });
</span><span class="cx"> });
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool B3IRGenerator::addCallIndirect(const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addCallIndirect(const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ExpressionType calleeIndex = args.takeLast();
</span><span class="cx"> ASSERT(signature->arguments.size() == args.size());
</span><span class="lines">@@ -779,7 +791,7 @@
</span><span class="cx"> });
</span><span class="cx"> });
</span><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void B3IRGenerator::unify(Variable* variable, ExpressionType source)
</span><span class="lines">@@ -907,7 +919,7 @@
</span><span class="cx"> return jsEntrypoint;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-std::unique_ptr<WasmInternalFunction> parseAndCompile(VM& vm, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& info, unsigned optLevel)
</del><ins>+Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& info, unsigned optLevel)
</ins><span class="cx"> {
</span><span class="cx"> auto result = std::make_unique<WasmInternalFunction>();
</span><span class="cx">
</span><span class="lines">@@ -914,8 +926,7 @@
</span><span class="cx"> Procedure procedure;
</span><span class="cx"> B3IRGenerator context(vm, info, procedure, result.get(), unlinkedWasmToWasmCalls, functionIndexSpace);
</span><span class="cx"> FunctionParser<B3IRGenerator> parser(context, functionStart, functionLength, signature, functionIndexSpace, info);
</span><del>- if (!parser.parse())
- RELEASE_ASSERT_NOT_REACHED();
</del><ins>+ WASM_FAIL_IF_HELPER_FAILS(parser.parse());
</ins><span class="cx">
</span><span class="cx"> procedure.resetReachability();
</span><span class="cx"> validate(procedure, "After parsing:\n");
</span><span class="lines">@@ -929,13 +940,13 @@
</span><span class="cx"> result->wasmEntrypoint.compilation = std::make_unique<Compilation>(vm, procedure, optLevel);
</span><span class="cx"> result->wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters();
</span><span class="cx"> result->jsToWasmEntrypoint.compilation = createJSToWasmWrapper(vm, *result, signature, result->wasmEntrypoint.compilation->code(), info.memory);
</span><del>- return result;
</del><ins>+ return WTFMove(result);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Custom wasm ops. These are the ones too messy to do in wasm.json.
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::I32Ctz>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::I32Ctz>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int32, Origin());
</span><span class="cx"> patchpoint->append(arg, ValueRep::SomeRegister);
</span><span class="lines">@@ -944,11 +955,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::I64Ctz>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::I64Ctz>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int64, Origin());
</span><span class="cx"> patchpoint->append(arg, ValueRep::SomeRegister);
</span><span class="lines">@@ -957,11 +968,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::I32Popcnt>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::I32Popcnt>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> // FIXME: This should use the popcnt instruction if SSE4 is available but we don't have code to detect SSE4 yet.
</span><span class="cx"> // see: https://bugs.webkit.org/show_bug.cgi?id=165363
</span><span class="lines">@@ -968,11 +979,11 @@
</span><span class="cx"> uint32_t (*popcount)(int32_t) = [] (int32_t value) -> uint32_t { return __builtin_popcount(value); };
</span><span class="cx"> Value* funcAddress = m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), bitwise_cast<void*>(popcount));
</span><span class="cx"> result = m_currentBlock->appendNew<CCallValue>(m_proc, Int32, Origin(), Effects::none(), funcAddress, arg);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::I64Popcnt>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::I64Popcnt>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> // FIXME: This should use the popcnt instruction if SSE4 is available but we don't have code to detect SSE4 yet.
</span><span class="cx"> // see: https://bugs.webkit.org/show_bug.cgi?id=165363
</span><span class="lines">@@ -979,11 +990,11 @@
</span><span class="cx"> uint64_t (*popcount)(int64_t) = [] (int64_t value) -> uint64_t { return __builtin_popcountll(value); };
</span><span class="cx"> Value* funcAddress = m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), bitwise_cast<void*>(popcount));
</span><span class="cx"> result = m_currentBlock->appendNew<CCallValue>(m_proc, Int64, Origin(), Effects::none(), funcAddress, arg);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<F64ConvertUI64>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<F64ConvertUI64>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Double, Origin());
</span><span class="cx"> if (isX86())
</span><span class="lines">@@ -999,11 +1010,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::F32ConvertUI64>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::F32ConvertUI64>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Float, Origin());
</span><span class="cx"> if (isX86())
</span><span class="lines">@@ -1019,11 +1030,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::F64Nearest>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::F64Nearest>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Double, Origin());
</span><span class="cx"> patchpoint->append(arg, ValueRep::SomeRegister);
</span><span class="lines">@@ -1032,11 +1043,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::F32Nearest>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::F32Nearest>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Float, Origin());
</span><span class="cx"> patchpoint->append(arg, ValueRep::SomeRegister);
</span><span class="lines">@@ -1045,11 +1056,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::F64Trunc>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::F64Trunc>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Double, Origin());
</span><span class="cx"> patchpoint->append(arg, ValueRep::SomeRegister);
</span><span class="lines">@@ -1058,11 +1069,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::F32Trunc>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::F32Trunc>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Float, Origin());
</span><span class="cx"> patchpoint->append(arg, ValueRep::SomeRegister);
</span><span class="lines">@@ -1071,11 +1082,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::I32TruncSF64>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::I32TruncSF64>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), -static_cast<double>(std::numeric_limits<int32_t>::min()));
</span><span class="cx"> Value* min = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<int32_t>::min()));
</span><span class="lines">@@ -1094,11 +1105,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::I32TruncSF32>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::I32TruncSF32>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), -static_cast<float>(std::numeric_limits<int32_t>::min()));
</span><span class="cx"> Value* min = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<int32_t>::min()));
</span><span class="lines">@@ -1117,12 +1128,12 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::I32TruncUF64>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::I32TruncUF64>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<int32_t>::min()) * -2.0);
</span><span class="cx"> Value* min = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), -1.0);
</span><span class="lines">@@ -1141,11 +1152,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::I32TruncUF32>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::I32TruncUF32>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<int32_t>::min()) * -2.0);
</span><span class="cx"> Value* min = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), -1.0);
</span><span class="lines">@@ -1164,11 +1175,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::I64TruncSF64>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::I64TruncSF64>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), -static_cast<double>(std::numeric_limits<int64_t>::min()));
</span><span class="cx"> Value* min = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<int64_t>::min()));
</span><span class="lines">@@ -1187,11 +1198,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::I64TruncUF64>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::I64TruncUF64>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<int64_t>::min()) * -2.0);
</span><span class="cx"> Value* min = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), -1.0);
</span><span class="lines">@@ -1229,11 +1240,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::I64TruncSF32>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::I64TruncSF32>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), -static_cast<float>(std::numeric_limits<int64_t>::min()));
</span><span class="cx"> Value* min = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<int64_t>::min()));
</span><span class="lines">@@ -1252,11 +1263,11 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<>
</span><del>-bool B3IRGenerator::addOp<OpType::I64TruncUF32>(ExpressionType arg, ExpressionType& result)
</del><ins>+auto B3IRGenerator::addOp<OpType::I64TruncUF32>(ExpressionType arg, ExpressionType& result) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<int64_t>::min()) * -2.0);
</span><span class="cx"> Value* min = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), -1.0);
</span><span class="lines">@@ -1294,7 +1305,7 @@
</span><span class="cx"> });
</span><span class="cx"> patchpoint->effects = Effects::none();
</span><span class="cx"> result = patchpoint;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> } } // namespace JSC::Wasm
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmB3IRGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> #include "B3Compilation.h"
</span><span class="cx"> #include "VM.h"
</span><span class="cx"> #include "WasmFormat.h"
</span><ins>+#include <wtf/Expected.h>
</ins><span class="cx">
</span><span class="cx"> extern "C" void dumpProcedure(void*);
</span><span class="cx">
</span><span class="lines">@@ -37,7 +38,7 @@
</span><span class="cx">
</span><span class="cx"> class MemoryInformation;
</span><span class="cx">
</span><del>-std::unique_ptr<WasmInternalFunction> parseAndCompile(VM&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&, const ModuleInformation&, unsigned optLevel = 1);
</del><ins>+Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&, const ModuleInformation&, unsigned optLevel = 1);
</ins><span class="cx">
</span><span class="cx"> } } // namespace JSC::Wasm
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmFormath"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmFormat.h (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmFormat.h        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/WasmFormat.h        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -61,34 +61,45 @@
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-struct External {
- enum Kind : uint8_t {
- // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
- Function = 0,
- Table = 1,
- Memory = 2,
- Global = 3,
- };
- template<typename Int>
- static bool isValid(Int val)
- {
- switch (val) {
- case Function:
- case Table:
- case Memory:
- case Global:
- return true;
- default:
- return false;
- }
- }
-
- static_assert(Function == 0, "Wasm needs Function to have the value 0");
- static_assert(Table == 1, "Wasm needs Table to have the value 1");
- static_assert(Memory == 2, "Wasm needs Memory to have the value 2");
- static_assert(Global == 3, "Wasm needs Global to have the value 3");
</del><ins>+enum class ExternalKind : uint8_t {
+ // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
+ Function = 0,
+ Table = 1,
+ Memory = 2,
+ Global = 3,
</ins><span class="cx"> };
</span><span class="cx">
</span><ins>+template<typename Int>
+static bool isValidExternalKind(Int val)
+{
+ switch (val) {
+ case static_cast<Int>(ExternalKind::Function):
+ case static_cast<Int>(ExternalKind::Table):
+ case static_cast<Int>(ExternalKind::Memory):
+ case static_cast<Int>(ExternalKind::Global):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static_assert(static_cast<int>(ExternalKind::Function) == 0, "Wasm needs Function to have the value 0");
+static_assert(static_cast<int>(ExternalKind::Table) == 1, "Wasm needs Table to have the value 1");
+static_assert(static_cast<int>(ExternalKind::Memory) == 2, "Wasm needs Memory to have the value 2");
+static_assert(static_cast<int>(ExternalKind::Global) == 3, "Wasm needs Global to have the value 3");
+
+static inline const char* makeString(ExternalKind kind)
+{
+ switch (kind) {
+ case ExternalKind::Function: return "Function";
+ case ExternalKind::Table: return "Table";
+ case ExternalKind::Memory: return "Memory";
+ case ExternalKind::Global: return "Global";
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return "?";
+}
+
</ins><span class="cx"> struct Signature {
</span><span class="cx"> Type returnType;
</span><span class="cx"> Vector<Type> arguments;
</span><span class="lines">@@ -97,13 +108,13 @@
</span><span class="cx"> struct Import {
</span><span class="cx"> Identifier module;
</span><span class="cx"> Identifier field;
</span><del>- External::Kind kind;
</del><ins>+ ExternalKind kind;
</ins><span class="cx"> unsigned kindIndex; // Index in the vector of the corresponding kind.
</span><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> struct Export {
</span><span class="cx"> Identifier field;
</span><del>- External::Kind kind;
</del><ins>+ ExternalKind kind;
</ins><span class="cx"> unsigned kindIndex; // Index in the vector of the corresponding kind.
</span><span class="cx"> };
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmFunctionParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -39,7 +39,7 @@
</span><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> template<typename Context>
</span><del>-class FunctionParser : public Parser {
</del><ins>+class FunctionParser : public Parser<void> {
</ins><span class="cx"> public:
</span><span class="cx"> typedef typename Context::ExpressionType ExpressionType;
</span><span class="cx"> typedef typename Context::ControlType ControlType;
</span><span class="lines">@@ -47,7 +47,7 @@
</span><span class="cx">
</span><span class="cx"> FunctionParser(Context&, const uint8_t* functionStart, size_t functionLength, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);
</span><span class="cx">
</span><del>- bool WARN_UNUSED_RETURN parse();
</del><ins>+ Result WARN_UNUSED_RETURN parse();
</ins><span class="cx">
</span><span class="cx"> struct ControlEntry {
</span><span class="cx"> ExpressionList enclosedExpressionStack;
</span><span class="lines">@@ -57,26 +57,27 @@
</span><span class="cx"> private:
</span><span class="cx"> static const bool verbose = false;
</span><span class="cx">
</span><del>- bool WARN_UNUSED_RETURN parseBody();
- bool WARN_UNUSED_RETURN parseExpression(OpType);
- bool WARN_UNUSED_RETURN parseUnreachableExpression(OpType);
- bool WARN_UNUSED_RETURN addReturn();
- bool WARN_UNUSED_RETURN unifyControl(Vector<ExpressionType>&, unsigned level);
</del><ins>+ PartialResult WARN_UNUSED_RETURN parseBody();
+ PartialResult WARN_UNUSED_RETURN parseExpression(OpType);
+ PartialResult WARN_UNUSED_RETURN parseUnreachableExpression(OpType);
+ PartialResult WARN_UNUSED_RETURN addReturn();
+ PartialResult WARN_UNUSED_RETURN unifyControl(Vector<ExpressionType>&, unsigned level);
</ins><span class="cx">
</span><del>- bool WARN_UNUSED_RETURN popExpressionStack(ExpressionType& result);
</del><ins>+#define WASM_TRY_POP_EXPRESSION_STACK_INTO(result, what) do { \
+ WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't pop empty stack in " what); \
+ result = m_expressionStack.takeLast(); \
+ } while (0)
</ins><span class="cx">
</span><span class="cx"> template<OpType>
</span><del>- bool WARN_UNUSED_RETURN unaryCase();
</del><ins>+ PartialResult WARN_UNUSED_RETURN unaryCase();
</ins><span class="cx">
</span><span class="cx"> template<OpType>
</span><del>- bool WARN_UNUSED_RETURN binaryCase();
</del><ins>+ PartialResult WARN_UNUSED_RETURN binaryCase();
</ins><span class="cx">
</span><del>- bool setErrorMessage(String&& message)
- {
- m_context.setErrorMessage(WTFMove(message));
- return false;
- }
</del><ins>+#define WASM_TRY_ADD_TO_CONTEXT(add_expression) WASM_FAIL_IF_HELPER_FAILS(m_context.add_expression)
</ins><span class="cx">
</span><ins>+ // FIXME add a macro as above for WASM_TRY_APPEND_TO_CONTROL_STACK https://bugs.webkit.org/show_bug.cgi?id=165862
+
</ins><span class="cx"> Context& m_context;
</span><span class="cx"> ExpressionList m_expressionStack;
</span><span class="cx"> Vector<ControlEntry> m_controlStack;
</span><span class="lines">@@ -99,41 +100,36 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<typename Context>
</span><del>-bool FunctionParser<Context>::parse()
</del><ins>+auto FunctionParser<Context>::parse() -> Result
</ins><span class="cx"> {
</span><del>- if (!m_context.addArguments(m_signature->arguments))
- return false;
-
</del><span class="cx"> uint32_t localCount;
</span><del>- if (!parseVarUInt32(localCount))
- return false;
</del><span class="cx">
</span><ins>+ WASM_PARSER_FAIL_IF(!m_context.addArguments(m_signature->arguments), "can't add ", m_signature->arguments.size(), " arguments to Function");
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(localCount), "can't get local count");
+ WASM_PARSER_FAIL_IF(localCount == std::numeric_limits<uint32_t>::max(), "Function section's local count is too big ", localCount);
+
</ins><span class="cx"> for (uint32_t i = 0; i < localCount; ++i) {
</span><span class="cx"> uint32_t numberOfLocals;
</span><del>- if (!parseVarUInt32(numberOfLocals))
- return false;
-
</del><span class="cx"> Type typeOfLocal;
</span><del>- if (!parseValueType(typeOfLocal))
- return false;
</del><span class="cx">
</span><del>- if (!m_context.addLocal(typeOfLocal, numberOfLocals))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfLocals), "can't get Function's number of locals in group ", i);
+ WASM_PARSER_FAIL_IF(numberOfLocals == std::numeric_limits<uint32_t>::max(), "Function section's ", i, "th local group count is too big ", numberOfLocals);
+ WASM_PARSER_FAIL_IF(!parseValueType(typeOfLocal), "can't get Function local's type in group ", i);
+ WASM_PARSER_FAIL_IF(!m_context.addLocal(typeOfLocal, numberOfLocals), "can't add ", numberOfLocals, " Function locals from group ", i);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return parseBody();
</del><ins>+ WASM_FAIL_IF_HELPER_FAILS(parseBody());
+
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<typename Context>
</span><del>-bool FunctionParser<Context>::parseBody()
</del><ins>+auto FunctionParser<Context>::parseBody() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> while (true) {
</span><span class="cx"> uint8_t op;
</span><del>- if (!parseUInt8(op) || !isValidOpType(op)) {
- if (verbose)
- WTF::dataLogLn("attempted to decode invalid op: ", RawPointer(reinterpret_cast<void*>(op)), " at offset: ", RawPointer(reinterpret_cast<void*>(m_offset)));
- return false;
- }
</del><ins>+ WASM_PARSER_FAIL_IF(!parseUInt8(op), "can't decode opcode");
+ WASM_PARSER_FAIL_IF(!isValidOpType(op), "invalid opcode ", op);
</ins><span class="cx">
</span><span class="cx"> if (verbose) {
</span><span class="cx"> dataLogLn("processing op (", m_unreachableBlocks, "): ", RawPointer(reinterpret_cast<void*>(op)), " at offset: ", RawPointer(reinterpret_cast<void*>(m_offset)));
</span><span class="lines">@@ -140,21 +136,16 @@
</span><span class="cx"> m_context.dump(m_controlStack, m_expressionStack);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (op == OpType::End && !m_controlStack.size())
- return m_unreachableBlocks ? true : addReturn();
-
- if (m_unreachableBlocks) {
- if (!parseUnreachableExpression(static_cast<OpType>(op))) {
- if (verbose)
- dataLogLn("failed to process unreachable op:", op);
- return false;
- }
- } else if (!parseExpression(static_cast<OpType>(op))) {
- if (verbose)
- dataLogLn("failed to process op:", op);
- return false;
</del><ins>+ if (op == OpType::End && !m_controlStack.size()) {
+ if (m_unreachableBlocks)
+ return { };
+ return addReturn();
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ if (m_unreachableBlocks)
+ WASM_FAIL_IF_HELPER_FAILS(parseUnreachableExpression(static_cast<OpType>(op)));
+ else
+ WASM_FAIL_IF_HELPER_FAILS(parseExpression(static_cast<OpType>(op)));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="lines">@@ -161,56 +152,52 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<typename Context>
</span><del>-bool FunctionParser<Context>::addReturn()
</del><ins>+auto FunctionParser<Context>::addReturn() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ExpressionList returnValues;
</span><span class="cx"> if (m_signature->returnType != Void) {
</span><span class="cx"> ExpressionType returnValue;
</span><del>- if (!popExpressionStack(returnValue))
- return false;
</del><ins>+ WASM_TRY_POP_EXPRESSION_STACK_INTO(returnValue, "return");
</ins><span class="cx"> returnValues.append(returnValue);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> m_unreachableBlocks = 1;
</span><del>- return m_context.addReturn(returnValues);
</del><ins>+ WASM_TRY_ADD_TO_CONTEXT(addReturn(returnValues));
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<typename Context>
</span><span class="cx"> template<OpType op>
</span><del>-bool FunctionParser<Context>::binaryCase()
</del><ins>+auto FunctionParser<Context>::binaryCase() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ExpressionType right;
</span><del>- if (!popExpressionStack(right))
- return false;
-
</del><span class="cx"> ExpressionType left;
</span><del>- if (!popExpressionStack(left))
- return false;
</del><ins>+ ExpressionType result;
</ins><span class="cx">
</span><del>- ExpressionType result;
- if (!m_context.template addOp<op>(left, right, result))
- return false;
</del><ins>+ WASM_TRY_POP_EXPRESSION_STACK_INTO(right, "binary right");
+ WASM_TRY_POP_EXPRESSION_STACK_INTO(left, "binary left");
+ WASM_TRY_ADD_TO_CONTEXT(template addOp<op>(left, right, result));
+
</ins><span class="cx"> m_expressionStack.append(result);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<typename Context>
</span><span class="cx"> template<OpType op>
</span><del>-bool FunctionParser<Context>::unaryCase()
</del><ins>+auto FunctionParser<Context>::unaryCase() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ExpressionType value;
</span><del>- if (!popExpressionStack(value))
- return false;
</del><ins>+ ExpressionType result;
</ins><span class="cx">
</span><del>- ExpressionType result;
- if (!m_context.template addOp<op>(value, result))
- return false;
</del><ins>+ WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "unary");
+ WASM_TRY_ADD_TO_CONTEXT(template addOp<op>(value, result));
+
</ins><span class="cx"> m_expressionStack.append(result);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<typename Context>
</span><del>-bool FunctionParser<Context>::parseExpression(OpType op)
</del><ins>+auto FunctionParser<Context>::parseExpression(OpType op) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> switch (op) {
</span><span class="cx"> #define CREATE_CASE(name, id, b3op, inc) case OpType::name: return binaryCase<OpType::name>();
</span><span class="lines">@@ -241,327 +228,248 @@
</span><span class="cx">
</span><span class="cx"> case OpType::Select: {
</span><span class="cx"> ExpressionType condition;
</span><del>- if (!popExpressionStack(condition))
- return false;
-
</del><span class="cx"> ExpressionType zero;
</span><del>- if (!popExpressionStack(zero))
- return false;
-
</del><span class="cx"> ExpressionType nonZero;
</span><del>- if (!popExpressionStack(nonZero))
- return false;
</del><span class="cx">
</span><ins>+ WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "select condition");
+ WASM_TRY_POP_EXPRESSION_STACK_INTO(zero, "select zero");
+ WASM_TRY_POP_EXPRESSION_STACK_INTO(nonZero, "select non-zero");
+
</ins><span class="cx"> ExpressionType result;
</span><del>- if (!m_context.addSelect(condition, nonZero, zero, result))
- return false;
</del><ins>+ WASM_TRY_ADD_TO_CONTEXT(addSelect(condition, nonZero, zero, result));
</ins><span class="cx">
</span><span class="cx"> m_expressionStack.append(result);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> #define CREATE_CASE(name, id, b3op, inc) case OpType::name:
</span><span class="cx"> FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE) {
</span><span class="cx"> uint32_t alignment;
</span><del>- if (!parseVarUInt32(alignment))
- return false;
-
</del><span class="cx"> uint32_t offset;
</span><del>- if (!parseVarUInt32(offset))
- return false;
-
</del><span class="cx"> ExpressionType pointer;
</span><del>- if (!popExpressionStack(pointer))
- return false;
-
</del><span class="cx"> ExpressionType result;
</span><del>- if (!m_context.load(static_cast<LoadOpType>(op), pointer, result, offset))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get load alignment");
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get load offset");
+ WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "load pointer");
+ WASM_TRY_ADD_TO_CONTEXT(load(static_cast<LoadOpType>(op), pointer, result, offset));
</ins><span class="cx"> m_expressionStack.append(result);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) {
</span><span class="cx"> uint32_t alignment;
</span><del>- if (!parseVarUInt32(alignment))
- return false;
-
</del><span class="cx"> uint32_t offset;
</span><del>- if (!parseVarUInt32(offset))
- return false;
-
</del><span class="cx"> ExpressionType value;
</span><del>- if (!popExpressionStack(value))
- return false;
-
</del><span class="cx"> ExpressionType pointer;
</span><del>- if (!popExpressionStack(pointer))
- return false;
-
- return m_context.store(static_cast<StoreOpType>(op), pointer, value, offset);
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get store alignment");
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get store offset");
+ WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "store value");
+ WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "store pointer");
+ WASM_TRY_ADD_TO_CONTEXT(store(static_cast<StoreOpType>(op), pointer, value, offset));
+ return { };
</ins><span class="cx"> }
</span><span class="cx"> #undef CREATE_CASE
</span><span class="cx">
</span><span class="cx"> case OpType::F32Const: {
</span><span class="cx"> uint32_t constant;
</span><del>- if (!parseUInt32(constant))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't parse 32-bit floating-point constant");
</ins><span class="cx"> m_expressionStack.append(m_context.addConstant(F32, constant));
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::I32Const: {
</span><span class="cx"> int32_t constant;
</span><del>- if (!parseVarInt32(constant))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't parse 32-bit constant");
</ins><span class="cx"> m_expressionStack.append(m_context.addConstant(I32, constant));
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::F64Const: {
</span><span class="cx"> uint64_t constant;
</span><del>- if (!parseUInt64(constant))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't parse 64-bit floating-point constant");
</ins><span class="cx"> m_expressionStack.append(m_context.addConstant(F64, constant));
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::I64Const: {
</span><span class="cx"> int64_t constant;
</span><del>- if (!parseVarInt64(constant))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't parse 64-bit constant");
</ins><span class="cx"> m_expressionStack.append(m_context.addConstant(I64, constant));
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::GetLocal: {
</span><span class="cx"> uint32_t index;
</span><del>- if (!parseVarUInt32(index))
- return false;
</del><span class="cx"> ExpressionType result;
</span><del>- if (!m_context.getLocal(index, result))
- return false;
-
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for get_local");
+ WASM_PARSER_FAIL_IF(!m_context.getLocal(index, result), "can't get_local at index", index);
</ins><span class="cx"> m_expressionStack.append(result);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::SetLocal: {
</span><span class="cx"> uint32_t index;
</span><del>- if (!parseVarUInt32(index))
- return false;
</del><span class="cx"> ExpressionType value;
</span><del>- if (!popExpressionStack(value))
- return false;
- return m_context.setLocal(index, value);
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for set_local");
+ WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_local");
+ WASM_TRY_ADD_TO_CONTEXT(setLocal(index, value));
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::TeeLocal: {
</span><span class="cx"> uint32_t index;
</span><del>- if (!parseVarUInt32(index))
- return false;
- if (!m_expressionStack.size())
- return false;
- return m_context.setLocal(index, m_expressionStack.last());
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for tee_local");
+ WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't tee_local on empty expression stack");
+ WASM_TRY_ADD_TO_CONTEXT(setLocal(index, m_expressionStack.last()));
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::GetGlobal: {
</span><span class="cx"> uint32_t index;
</span><del>- if (!parseVarUInt32(index))
- return false;
</del><span class="cx"> ExpressionType result;
</span><del>- if (!m_context.getGlobal(index, result))
- return false;
-
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index");
+ WASM_TRY_ADD_TO_CONTEXT(getGlobal(index, result));
</ins><span class="cx"> m_expressionStack.append(result);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::SetGlobal: {
</span><span class="cx"> uint32_t index;
</span><del>- if (!parseVarUInt32(index))
- return false;
</del><span class="cx"> ExpressionType value;
</span><del>- if (!popExpressionStack(value))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get set_global's index");
+ WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_global value");
+ WASM_TRY_ADD_TO_CONTEXT(setGlobal(index, value));
</ins><span class="cx"> return m_context.setGlobal(index, value);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::Call: {
</span><span class="cx"> uint32_t functionIndex;
</span><del>- if (!parseVarUInt32(functionIndex))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't parse call's function index");
+ WASM_PARSER_FAIL_IF(functionIndex >= m_functionIndexSpace.size, "call function index ", functionIndex, " exceeds function index space ", m_functionIndexSpace.size);
</ins><span class="cx">
</span><del>- if (functionIndex >= m_functionIndexSpace.size)
- return false;
-
</del><span class="cx"> const Signature* calleeSignature = m_functionIndexSpace.buffer.get()[functionIndex].signature;
</span><ins>+ WASM_PARSER_FAIL_IF(calleeSignature->arguments.size() > m_expressionStack.size(), "call function index ", functionIndex, " has ", calleeSignature->arguments.size(), " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");
</ins><span class="cx">
</span><del>- if (calleeSignature->arguments.size() > m_expressionStack.size())
- return false;
-
</del><span class="cx"> size_t firstArgumentIndex = m_expressionStack.size() - calleeSignature->arguments.size();
</span><span class="cx"> Vector<ExpressionType> args;
</span><del>- args.reserveInitialCapacity(calleeSignature->arguments.size());
- for (unsigned i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
- args.append(m_expressionStack[i]);
</del><ins>+ WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(calleeSignature->arguments.size()), "can't allocate enough memory for call's ", calleeSignature->arguments.size(), " arguments");
+ for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
+ args.uncheckedAppend(m_expressionStack[i]);
</ins><span class="cx"> m_expressionStack.shrink(firstArgumentIndex);
</span><span class="cx">
</span><span class="cx"> ExpressionType result = Context::emptyExpression;
</span><del>- if (!m_context.addCall(functionIndex, calleeSignature, args, result))
- return false;
</del><ins>+ WASM_TRY_ADD_TO_CONTEXT(addCall(functionIndex, calleeSignature, args, result));
</ins><span class="cx">
</span><span class="cx"> if (result != Context::emptyExpression)
</span><span class="cx"> m_expressionStack.append(result);
</span><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::CallIndirect: {
</span><del>- if (!m_info.tableInformation)
- return setErrorMessage("call_indirect is only valid when a table is defined or imported");
</del><span class="cx"> uint32_t signatureIndex;
</span><del>- if (!parseVarUInt32(signatureIndex))
- return false;
-
</del><span class="cx"> uint8_t reserved;
</span><del>- if (!parseVarUInt1(reserved))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!m_info.tableInformation, "call_indirect is only valid when a table is defined or imported");
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(signatureIndex), "can't get call_indirect's signature index");
+ WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't get call_indirect's reserved byte");
+ WASM_PARSER_FAIL_IF(reserved, "call_indirect's 'reserved' varuint1 must be 0x0");
+ WASM_PARSER_FAIL_IF(m_info.signatures.size() <= signatureIndex, "call_indirect's signature index ", signatureIndex, " exceeds known signatures ", m_info.signatures.size());
</ins><span class="cx">
</span><del>- if (reserved != 0)
- return setErrorMessage("call_indirect 'reserved' varuint1 must be 0x0");
-
- if (m_info.signatures.size() <= signatureIndex)
- return setErrorMessage("Tried to use a signature outside the range of valid signatures");
-
</del><span class="cx"> const Signature* calleeSignature = &m_info.signatures[signatureIndex];
</span><span class="cx"> size_t argumentCount = calleeSignature->arguments.size() + 1; // Add the callee's index.
</span><del>- if (argumentCount > m_expressionStack.size())
- return setErrorMessage("Not enough values on the stack for call_indirect");
</del><ins>+ WASM_PARSER_FAIL_IF(argumentCount > m_expressionStack.size(), "call_indirect expects ", argumentCount, " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");
</ins><span class="cx">
</span><span class="cx"> Vector<ExpressionType> args;
</span><del>- if (!args.tryReserveCapacity(argumentCount))
- return setErrorMessage("Out of memory");
-
</del><ins>+ WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(argumentCount), "can't allocate enough memory for ", argumentCount, " call_indirect arguments");
</ins><span class="cx"> size_t firstArgumentIndex = m_expressionStack.size() - argumentCount;
</span><del>- for (unsigned i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
</del><ins>+ for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
</ins><span class="cx"> args.uncheckedAppend(m_expressionStack[i]);
</span><span class="cx"> m_expressionStack.shrink(firstArgumentIndex);
</span><span class="cx">
</span><span class="cx"> ExpressionType result = Context::emptyExpression;
</span><del>- if (!m_context.addCallIndirect(calleeSignature, args, result))
- return false;
</del><ins>+ WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(calleeSignature, args, result));
</ins><span class="cx">
</span><span class="cx"> if (result != Context::emptyExpression)
</span><span class="cx"> m_expressionStack.append(result);
</span><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::Block: {
</span><span class="cx"> Type inlineSignature;
</span><del>- if (!parseResultType(inlineSignature))
- return false;
-
</del><ins>+ WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get block's inline signature");
</ins><span class="cx"> m_controlStack.append({ WTFMove(m_expressionStack), m_context.addBlock(inlineSignature) });
</span><span class="cx"> m_expressionStack = ExpressionList();
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::Loop: {
</span><span class="cx"> Type inlineSignature;
</span><del>- if (!parseResultType(inlineSignature))
- return false;
-
</del><ins>+ WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get loop's inline signature");
</ins><span class="cx"> m_controlStack.append({ WTFMove(m_expressionStack), m_context.addLoop(inlineSignature) });
</span><span class="cx"> m_expressionStack = ExpressionList();
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::If: {
</span><span class="cx"> Type inlineSignature;
</span><del>- if (!parseResultType(inlineSignature))
- return false;
-
</del><span class="cx"> ExpressionType condition;
</span><del>- if (!popExpressionStack(condition))
- return false;
-
</del><span class="cx"> ControlType control;
</span><del>- if (!m_context.addIf(condition, inlineSignature, control))
- return false;
-
</del><ins>+ WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get if's inline signature");
+ WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "if condition");
+ WASM_TRY_ADD_TO_CONTEXT(addIf(condition, inlineSignature, control));
</ins><span class="cx"> m_controlStack.append({ WTFMove(m_expressionStack), control });
</span><span class="cx"> m_expressionStack = ExpressionList();
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::Else: {
</span><del>- if (!m_controlStack.size()) {
- setErrorMessage("Attempted to use else block at the top-level of a function");
- return false;
- }
-
- if (!m_context.addElse(m_controlStack.last().controlData, m_expressionStack))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(m_controlStack.isEmpty(), "can't use else block at the top-level of a function");
+ WASM_TRY_ADD_TO_CONTEXT(addElse(m_controlStack.last().controlData, m_expressionStack));
</ins><span class="cx"> m_expressionStack.shrink(0);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::Br:
</span><span class="cx"> case OpType::BrIf: {
</span><span class="cx"> uint32_t target;
</span><del>- if (!parseVarUInt32(target) || target >= m_controlStack.size())
- return false;
-
</del><span class="cx"> ExpressionType condition = Context::emptyExpression;
</span><del>- if (op == OpType::BrIf) {
- if (!popExpressionStack(condition))
- return false;
- } else
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get br / br_if's target");
+ WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br / br_if's target ", target, " exceeds control stack size ", m_controlStack.size());
+ if (op == OpType::BrIf)
+ WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br / br_if condition");
+ else
</ins><span class="cx"> m_unreachableBlocks = 1;
</span><span class="cx">
</span><span class="cx"> ControlType& data = m_controlStack[m_controlStack.size() - 1 - target].controlData;
</span><span class="cx">
</span><del>- return m_context.addBranch(data, condition, m_expressionStack);
</del><ins>+ WASM_TRY_ADD_TO_CONTEXT(addBranch(data, condition, m_expressionStack));
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::BrTable: {
</span><span class="cx"> uint32_t numberOfTargets;
</span><del>- if (!parseVarUInt32(numberOfTargets))
- return false;
</del><ins>+ ExpressionType condition;
+ uint32_t defaultTarget;
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfTargets), "can't get the number of targets for br_table");
+ WASM_PARSER_FAIL_IF(numberOfTargets == std::numeric_limits<uint32_t>::max(), "br_table's number of targets is too big ", numberOfTargets);
</ins><span class="cx">
</span><span class="cx"> Vector<ControlType*> targets;
</span><del>- if (!targets.tryReserveCapacity(numberOfTargets))
- return false;
-
</del><ins>+ WASM_PARSER_FAIL_IF(!targets.tryReserveCapacity(numberOfTargets), "can't allocate memory for ", numberOfTargets, " br_table targets");
</ins><span class="cx"> for (uint32_t i = 0; i < numberOfTargets; ++i) {
</span><span class="cx"> uint32_t target;
</span><del>- if (!parseVarUInt32(target))
- return false;
-
- if (target >= m_controlStack.size())
- return false;
-
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get ", i, "th target for br_table");
+ WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br_table's ", i, "th target ", target, " exceeds control stack size ", m_controlStack.size());
</ins><span class="cx"> targets.uncheckedAppend(&m_controlStack[m_controlStack.size() - 1 - target].controlData);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- uint32_t defaultTarget;
- if (!parseVarUInt32(defaultTarget))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(defaultTarget), "can't get default target for br_table");
+ WASM_PARSER_FAIL_IF(defaultTarget >= m_controlStack.size(), "br_table's default target ", defaultTarget, " exceeds control stack size ", m_controlStack.size());
+ WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br_table condition");
+ WASM_TRY_ADD_TO_CONTEXT(addSwitch(condition, targets, m_controlStack[m_controlStack.size() - 1 - defaultTarget].controlData, m_expressionStack));
</ins><span class="cx">
</span><del>- if (defaultTarget >= m_controlStack.size())
- return false;
-
- ExpressionType condition;
- if (!popExpressionStack(condition))
- return false;
-
- if (!m_context.addSwitch(condition, targets, m_controlStack[m_controlStack.size() - 1 - defaultTarget].controlData, m_expressionStack))
- return false;
-
</del><span class="cx"> m_unreachableBlocks = 1;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::Return: {
</span><span class="lines">@@ -573,35 +481,33 @@
</span><span class="cx"> // FIXME: This is a little weird in that it will modify the expressionStack for the result of the block.
</span><span class="cx"> // That's a little too effectful for me but I don't have a better API right now.
</span><span class="cx"> // see: https://bugs.webkit.org/show_bug.cgi?id=164353
</span><del>- if (!m_context.endBlock(data, m_expressionStack))
- return false;
</del><ins>+ WASM_TRY_ADD_TO_CONTEXT(endBlock(data, m_expressionStack));
</ins><span class="cx"> m_expressionStack.swap(data.enclosedExpressionStack);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::Unreachable: {
</span><del>- m_context.addUnreachable();
</del><ins>+ WASM_TRY_ADD_TO_CONTEXT(addUnreachable());
</ins><span class="cx"> m_unreachableBlocks = 1;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::Drop: {
</span><del>- if (!m_expressionStack.size()) {
- setErrorMessage("Attempted to drop an expression from an empty stack.");
- return false;
- }
</del><ins>+ WASM_PARSER_FAIL_IF(!m_expressionStack.size(), "can't drop on empty stack");
</ins><span class="cx"> m_expressionStack.takeLast();
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::Nop: {
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::GrowMemory:
</span><ins>+ return fail("not yet implemented: grow_memory"); // FIXME: Not yet implemented.
+
</ins><span class="cx"> case OpType::CurrentMemory:
</span><del>- // FIXME: Not yet implemented.
- return false;
</del><ins>+ return fail("not yet implemented: current_memory"); // FIXME: Not yet implemented.
+
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> ASSERT_NOT_REACHED();
</span><span class="lines">@@ -608,31 +514,29 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<typename Context>
</span><del>-bool FunctionParser<Context>::parseUnreachableExpression(OpType op)
</del><ins>+auto FunctionParser<Context>::parseUnreachableExpression(OpType op) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(m_unreachableBlocks);
</span><span class="cx"> switch (op) {
</span><span class="cx"> case OpType::Else: {
</span><span class="cx"> if (m_unreachableBlocks > 1)
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx">
</span><span class="cx"> ControlEntry& data = m_controlStack.last();
</span><span class="cx"> m_unreachableBlocks = 0;
</span><del>- if (!m_context.addElseToUnreachable(data.controlData))
- return false;
</del><ins>+ WASM_TRY_ADD_TO_CONTEXT(addElseToUnreachable(data.controlData));
</ins><span class="cx"> m_expressionStack.shrink(0);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::End: {
</span><span class="cx"> if (m_unreachableBlocks == 1) {
</span><span class="cx"> ControlEntry data = m_controlStack.takeLast();
</span><del>- if (!m_context.addEndToUnreachable(data))
- return false;
</del><ins>+ WASM_TRY_ADD_TO_CONTEXT(addEndToUnreachable(data));
</ins><span class="cx"> m_expressionStack.swap(data.enclosedExpressionStack);
</span><span class="cx"> }
</span><span class="cx"> m_unreachableBlocks--;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case OpType::Loop:
</span><span class="lines">@@ -639,7 +543,7 @@
</span><span class="cx"> case OpType::If:
</span><span class="cx"> case OpType::Block: {
</span><span class="cx"> m_unreachableBlocks++;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // two immediate cases
</span><span class="lines">@@ -646,9 +550,9 @@
</span><span class="cx"> case OpType::Br:
</span><span class="cx"> case OpType::BrIf: {
</span><span class="cx"> uint32_t unused;
</span><del>- if (!parseVarUInt32(unused))
- return false;
- return parseVarUInt32(unused);
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get br / br_if in unreachable context");
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get br / br_if in unreachable context");
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // one immediate cases
</span><span class="lines">@@ -659,27 +563,16 @@
</span><span class="cx"> case OpType::SetLocal:
</span><span class="cx"> case OpType::GetLocal: {
</span><span class="cx"> uint32_t unused;
</span><del>- return parseVarUInt32(unused);
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get const / local in unreachable context");
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> default:
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-template<typename Context>
-bool FunctionParser<Context>::popExpressionStack(ExpressionType& result)
-{
- if (m_expressionStack.size()) {
- result = m_expressionStack.takeLast();
- return true;
- }
-
- setErrorMessage("Attempted to use a stack value when none existed");
- return false;
-}
-
</del><span class="cx"> } } // namespace JSC::Wasm
</span><span class="cx">
</span><span class="cx"> #endif // ENABLE(WEBASSEMBLY)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmModuleParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -39,99 +39,46 @@
</span><span class="cx">
</span><span class="cx"> namespace JSC { namespace Wasm {
</span><span class="cx">
</span><del>-static const bool verbose = false;
-
-bool ModuleParser::parse()
</del><ins>+auto ModuleParser::parse() -> Result
</ins><span class="cx"> {
</span><del>- m_module = std::make_unique<ModuleInformation>();
-
</del><ins>+ m_result.module = std::make_unique<ModuleInformation>();
</ins><span class="cx"> const size_t minSize = 8;
</span><del>- if (length() < minSize) {
- m_errorMessage = "Module is " + String::number(length()) + " bytes, expected at least " + String::number(minSize) + " bytes";
- return false;
- }
- if (!consumeCharacter(0) || !consumeString("asm")) {
- m_errorMessage = "Modules doesn't start with '\\0asm'";
- return false;
- }
-
</del><span class="cx"> uint32_t versionNumber;
</span><del>- if (!parseUInt32(versionNumber)) {
- // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
- m_errorMessage = "couldn't parse version number";
- return false;
- }
</del><span class="cx">
</span><del>- if (versionNumber != expectedVersionNumber) {
- // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
- m_errorMessage = "unexpected version number";
- return false;
- }
</del><ins>+ WASM_PARSER_FAIL_IF(length() < minSize, "expected a module of at least ", minSize, " bytes");
+ WASM_PARSER_FAIL_IF(!consumeCharacter(0) || !consumeString("asm"), "modules doesn't start with '\\0asm'");
+ WASM_PARSER_FAIL_IF(!parseUInt32(versionNumber), "can't parse version number");
+ WASM_PARSER_FAIL_IF(versionNumber != expectedVersionNumber, "unexpected version number ", versionNumber, " expected ", expectedVersionNumber);
</ins><span class="cx">
</span><del>-
- if (verbose)
- dataLogLn("Passed processing header.");
-
- Sections::Section previousSection = Sections::Unknown;
</del><ins>+ Section previousSection = Section::Unknown;
</ins><span class="cx"> while (m_offset < length()) {
</span><del>- if (verbose)
- dataLogLn("Starting to parse next section at offset: ", m_offset);
-
</del><span class="cx"> uint8_t sectionByte;
</span><del>- if (!parseUInt7(sectionByte)) {
- // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
- m_errorMessage = "couldn't get section byte";
- return false;
- }
</del><span class="cx">
</span><del>- if (verbose)
- dataLogLn("Section byte: ", sectionByte);
</del><ins>+ WASM_PARSER_FAIL_IF(!parseUInt7(sectionByte), "can't get section byte");
</ins><span class="cx">
</span><del>- Sections::Section section = Sections::Unknown;
</del><ins>+ Section section = Section::Unknown;
</ins><span class="cx"> if (sectionByte) {
</span><del>- if (sectionByte < Sections::Unknown)
- section = static_cast<Sections::Section>(sectionByte);
</del><ins>+ if (isValidSection(sectionByte))
+ section = static_cast<Section>(sectionByte);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- if (!Sections::validateOrder(previousSection, section)) {
- // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
- m_errorMessage = "invalid section order";
- return false;
- }
-
</del><span class="cx"> uint32_t sectionLength;
</span><del>- if (!parseVarUInt32(sectionLength)) {
- // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
- m_errorMessage = "couldn't get section length";
- return false;
- }
</del><ins>+ WASM_PARSER_FAIL_IF(!validateOrder(previousSection, section), "invalid section order, ", previousSection, " followed by ", section);
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(sectionLength), "can't get ", section, " section's length");
+ WASM_PARSER_FAIL_IF(sectionLength > length() - m_offset, section, "section of size ", sectionLength, " would overflow Module's size");
</ins><span class="cx">
</span><del>- if (sectionLength > length() - m_offset) {
- // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
- m_errorMessage = "section content would overflow Module's size";
- return false;
- }
-
</del><span class="cx"> auto end = m_offset + sectionLength;
</span><span class="cx">
</span><span class="cx"> switch (section) {
</span><del>- // FIXME improve error message in macro below https://bugs.webkit.org/show_bug.cgi?id=163919
-#define WASM_SECTION_PARSE(NAME, ID, DESCRIPTION) \
- case Sections::NAME: { \
- if (verbose) \
- dataLogLn("Parsing " DESCRIPTION); \
- if (!parse ## NAME()) { \
- m_errorMessage = "couldn't parse section " #NAME ": " DESCRIPTION; \
- return false; \
- } \
- break; \
</del><ins>+#define WASM_SECTION_PARSE(NAME, ID, DESCRIPTION) \
+ case Section::NAME: { \
+ WASM_FAIL_IF_HELPER_FAILS(parse ## NAME()); \
+ break; \
</ins><span class="cx"> }
</span><span class="cx"> FOR_EACH_WASM_SECTION(WASM_SECTION_PARSE)
</span><span class="cx"> #undef WASM_SECTION_PARSE
</span><span class="cx">
</span><del>- case Sections::Unknown: {
- if (verbose)
- dataLogLn("Unknown section, skipping.");
</del><ins>+ case Section::Unknown: {
</ins><span class="cx"> // Ignore section's name LEB and bytes: they're already included in sectionLength.
</span><span class="cx"> m_offset += sectionLength;
</span><span class="cx"> break;
</span><span class="lines">@@ -138,90 +85,64 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (verbose)
- dataLogLn("Finished parsing section.");
</del><ins>+ WASM_PARSER_FAIL_IF(end != m_offset, "parsing ended before the end of ", section, " section");
</ins><span class="cx">
</span><del>- if (end != m_offset) {
- // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
- m_errorMessage = "parsing ended before the end of the section";
- return false;
- }
-
</del><span class="cx"> previousSection = section;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- // TODO
- m_failed = false;
- return true;
</del><ins>+ return WTFMove(m_result);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseType()
</del><ins>+auto ModuleParser::parseType() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> uint32_t count;
</span><del>- if (!parseVarUInt32(count)
- || count == std::numeric_limits<uint32_t>::max()
- || !m_module->signatures.tryReserveCapacity(count))
- return false;
- if (verbose)
- dataLogLn(" count: ", count);
</del><span class="cx">
</span><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Type section's count");
+ WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Type section's count is too big ", count);
+ WASM_PARSER_FAIL_IF(!m_result.module->signatures.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries");
+
</ins><span class="cx"> for (uint32_t i = 0; i < count; ++i) {
</span><span class="cx"> int8_t type;
</span><del>- if (!parseInt7(type))
- return false;
- if (type != Func)
- return false;
-
- if (verbose)
- dataLogLn("Got function type.");
-
</del><span class="cx"> uint32_t argumentCount;
</span><span class="cx"> Vector<Type> argumentTypes;
</span><del>- if (!parseVarUInt32(argumentCount)
- || argumentCount == std::numeric_limits<uint32_t>::max()
- || !argumentTypes.tryReserveCapacity(argumentCount))
- return false;
- if (verbose)
- dataLogLn(" argument count: ", argumentCount);
</del><span class="cx">
</span><ins>+ WASM_PARSER_FAIL_IF(!parseInt7(type), "can't get ", i, "th Type's type");
+ WASM_PARSER_FAIL_IF(type != Func, i, "th Type is non-Func ", type);
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(argumentCount), "can't get ", i, "th Type's argument count");
+ WASM_PARSER_FAIL_IF(argumentCount == std::numeric_limits<uint32_t>::max(), i, "th argument count is too big ", argumentCount);
+ WASM_PARSER_FAIL_IF(!argumentTypes.tryReserveCapacity(argumentCount), "can't allocate enough memory for Type section's ", i, "th ", argumentCount, " arguments");
+
</ins><span class="cx"> for (unsigned i = 0; i < argumentCount; ++i) {
</span><span class="cx"> Type argumentType;
</span><del>- if (!parseResultType(argumentType))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseResultType(argumentType), "can't get ", i, "th argument Type");
</ins><span class="cx"> argumentTypes.uncheckedAppend(argumentType);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> uint8_t returnCount;
</span><del>- if (!parseVarUInt1(returnCount))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt1(returnCount), "can't get ", i, "th Type's return count");
</ins><span class="cx"> Type returnType;
</span><span class="cx">
</span><del>- if (verbose)
- dataLogLn(returnCount);
-
</del><span class="cx"> if (returnCount) {
</span><span class="cx"> Type value;
</span><del>- if (!parseValueType(value))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseValueType(value), "can't get ", i, "th Type's return value");
</ins><span class="cx"> returnType = static_cast<Type>(value);
</span><span class="cx"> } else
</span><span class="cx"> returnType = Type::Void;
</span><span class="cx">
</span><del>- m_module->signatures.uncheckedAppend({ returnType, WTFMove(argumentTypes) });
</del><ins>+ m_result.module->signatures.uncheckedAppend({ returnType, WTFMove(argumentTypes) });
</ins><span class="cx"> }
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseImport()
</del><ins>+auto ModuleParser::parseImport() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> uint32_t importCount;
</span><del>- if (!parseVarUInt32(importCount)
- || importCount == std::numeric_limits<uint32_t>::max()
- || !m_module->globals.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
- || !m_module->imports.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
- || !m_module->importFunctions.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
- || !m_functionIndexSpace.tryReserveCapacity(importCount)) // FIXME this over-allocates when we fix the FIXMEs below. We'll allocate some more here when we know how many functions to expect.
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(importCount), "can't get Import section's count");
+ WASM_PARSER_FAIL_IF(importCount == std::numeric_limits<uint32_t>::max(), "Import section's count is too big ", importCount);
+ WASM_PARSER_FAIL_IF(!m_result.module->globals.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " globals"); // FIXME this over-allocates when we fix the FIXMEs below.
+ WASM_PARSER_FAIL_IF(!m_result.module->imports.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " imports"); // FIXME this over-allocates when we fix the FIXMEs below.
+ WASM_PARSER_FAIL_IF(!m_result.module->importFunctions.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " import functions"); // FIXME this over-allocates when we fix the FIXMEs below.
+ WASM_PARSER_FAIL_IF(!m_result.functionIndexSpace.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " functions in the index space"); // FIXME this over-allocates when we fix the FIXMEs below. We'll allocate some more here when we know how many functions to expect.
</ins><span class="cx">
</span><span class="cx"> for (uint32_t importNumber = 0; importNumber < importCount; ++importNumber) {
</span><span class="cx"> Import imp;
</span><span class="lines">@@ -229,162 +150,144 @@
</span><span class="cx"> uint32_t fieldLen;
</span><span class="cx"> String moduleString;
</span><span class="cx"> String fieldString;
</span><del>- if (!parseVarUInt32(moduleLen)
- || !consumeUTF8String(moduleString, moduleLen))
- return false;
</del><ins>+
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(moduleLen), "can't get ", importNumber, "th Import's module name length");
+ WASM_PARSER_FAIL_IF(!consumeUTF8String(moduleString, moduleLen), "can't get ", importNumber, "th Import's module name of length ", moduleLen);
</ins><span class="cx"> imp.module = Identifier::fromString(m_vm, moduleString);
</span><del>- if (!parseVarUInt32(fieldLen)
- || !consumeUTF8String(fieldString, fieldLen))
- return false;
</del><ins>+
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", importNumber, "th Import's field name length in module '", moduleString, "'");
+ WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", importNumber, "th Import's field name of length ", moduleLen, " in module '", moduleString, "'");
</ins><span class="cx"> imp.field = Identifier::fromString(m_vm, fieldString);
</span><del>- if (!parseExternalKind(imp.kind))
- return false;
</del><ins>+
+ WASM_PARSER_FAIL_IF(!parseExternalKind(imp.kind), "can't get ", importNumber, "th Import's kind in module '", moduleString, "' field '", fieldString, "'");
</ins><span class="cx"> switch (imp.kind) {
</span><del>- case External::Function: {
</del><ins>+ case ExternalKind::Function: {
</ins><span class="cx"> uint32_t functionSignatureIndex;
</span><del>- if (!parseVarUInt32(functionSignatureIndex)
- || functionSignatureIndex >= m_module->signatures.size())
- return false;
- imp.kindIndex = m_module->importFunctions.size();
- Signature* signature = &m_module->signatures[functionSignatureIndex];
- m_module->importFunctions.uncheckedAppend(signature);
- m_functionIndexSpace.uncheckedAppend(signature);
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSignatureIndex), "can't get ", importNumber, "th Import's function signature in module '", moduleString, "' field '", fieldString, "'");
+ WASM_PARSER_FAIL_IF(functionSignatureIndex >= m_result.module->signatures.size(), "invalid function signature for ", importNumber, "th Import, ", functionSignatureIndex, " is out of range of ", m_result.module->signatures.size(), " in module '", moduleString, "' field '", fieldString, "'");
+ imp.kindIndex = m_result.module->importFunctions.size();
+ Signature* signature = &m_result.module->signatures[functionSignatureIndex];
+ m_result.module->importFunctions.uncheckedAppend(signature);
+ m_result.functionIndexSpace.uncheckedAppend(signature);
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case External::Table: {
</del><ins>+ case ExternalKind::Table: {
</ins><span class="cx"> bool isImport = true;
</span><del>- if (!parseTableHelper(isImport))
- return false;
</del><ins>+ PartialResult result = parseTableHelper(isImport);
+ if (UNLIKELY(!result))
+ return result.getUnexpected();
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case External::Memory: {
</del><ins>+ case ExternalKind::Memory: {
</ins><span class="cx"> bool isImport = true;
</span><del>- if (!parseMemoryHelper(isImport))
- return false;
</del><ins>+ PartialResult result = parseMemoryHelper(isImport);
+ if (UNLIKELY(!result))
+ return result.getUnexpected();
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case External::Global: {
</del><ins>+ case ExternalKind::Global: {
</ins><span class="cx"> Global global;
</span><del>- if (!parseGlobalType(global))
- return false;
</del><ins>+ WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global));
+ WASM_PARSER_FAIL_IF(global.mutability == Global::Mutable, "Mutable Globals aren't supported");
</ins><span class="cx">
</span><del>- if (global.mutability == Global::Mutable)
- return false;
-
- imp.kindIndex = m_module->globals.size();
- m_module->globals.uncheckedAppend(WTFMove(global));
</del><ins>+ imp.kindIndex = m_result.module->globals.size();
+ m_result.module->globals.uncheckedAppend(WTFMove(global));
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- m_module->imports.uncheckedAppend(imp);
</del><ins>+ m_result.module->imports.uncheckedAppend(imp);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- m_module->firstInternalGlobal = m_module->globals.size();
- return true;
</del><ins>+ m_result.module->firstInternalGlobal = m_result.module->globals.size();
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseFunction()
</del><ins>+auto ModuleParser::parseFunction() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> uint32_t count;
</span><del>- if (!parseVarUInt32(count)
- || count == std::numeric_limits<uint32_t>::max()
- || !m_module->internalFunctionSignatures.tryReserveCapacity(count)
- || !m_functionLocationInBinary.tryReserveCapacity(count)
- || !m_functionIndexSpace.tryReserveCapacity(m_functionIndexSpace.size() + count))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Function section's count");
+ WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Function section's count is too big ", count);
+ WASM_PARSER_FAIL_IF(!m_result.module->internalFunctionSignatures.tryReserveCapacity(count), "can't allocate enough memory for ", count, " Function signatures");
+ WASM_PARSER_FAIL_IF(!m_result.functionLocationInBinary.tryReserveCapacity(count), "can't allocate enough memory for ", count, "Function locations");
+ WASM_PARSER_FAIL_IF(!m_result.functionIndexSpace.tryReserveCapacity(m_result.functionIndexSpace.size() + count), "can't allocate enough memory for ", count, " more functions in the function index space");
</ins><span class="cx">
</span><span class="cx"> for (uint32_t i = 0; i < count; ++i) {
</span><span class="cx"> uint32_t typeNumber;
</span><del>- if (!parseVarUInt32(typeNumber)
- || typeNumber >= m_module->signatures.size())
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(typeNumber), "can't get ", i, "th Function's type number");
+ WASM_PARSER_FAIL_IF(typeNumber >= m_result.module->signatures.size(), i, "th Function type number is invalid ", typeNumber);
</ins><span class="cx">
</span><del>- Signature* signature = &m_module->signatures[typeNumber];
</del><ins>+ Signature* signature = &m_result.module->signatures[typeNumber];
</ins><span class="cx"> // The Code section fixes up start and end.
</span><span class="cx"> size_t start = 0;
</span><span class="cx"> size_t end = 0;
</span><del>- m_module->internalFunctionSignatures.uncheckedAppend(signature);
- m_functionLocationInBinary.uncheckedAppend({ start, end });
- m_functionIndexSpace.uncheckedAppend(signature);
</del><ins>+ m_result.module->internalFunctionSignatures.uncheckedAppend(signature);
+ m_result.functionLocationInBinary.uncheckedAppend({ start, end });
+ m_result.functionIndexSpace.uncheckedAppend(signature);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum)
</del><ins>+auto ModuleParser::parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(!maximum);
</span><span class="cx">
</span><span class="cx"> uint8_t flags;
</span><del>- if (!parseVarUInt1(flags))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt1(flags), "can't parse resizable limits flags");
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(initial), "can't parse resizable limits initial page count");
</ins><span class="cx">
</span><del>- if (!parseVarUInt32(initial))
- return false;
-
</del><span class="cx"> if (flags) {
</span><span class="cx"> uint32_t maximumInt;
</span><del>- if (!parseVarUInt32(maximumInt))
- return false;
-
- if (initial > maximumInt)
- return false;
-
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(maximumInt), "can't parse resizable limits maximum page count");
+ WASM_PARSER_FAIL_IF(initial > maximumInt, "resizable limits has a initial page count of ", initial, " which is greater than its maximum ", maximumInt);
</ins><span class="cx"> maximum = maximumInt;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseTableHelper(bool isImport)
</del><ins>+auto ModuleParser::parseTableHelper(bool isImport) -> PartialResult
</ins><span class="cx"> {
</span><del>- // We're only allowed a total of one Table import or definition.
- if (m_hasTable)
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(m_hasTable, "Table section cannot exist if an Import has a table");
</ins><span class="cx">
</span><span class="cx"> m_hasTable = true;
</span><span class="cx">
</span><span class="cx"> int8_t type;
</span><del>- if (!parseInt7(type))
- return false;
- if (type != Wasm::Anyfunc)
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseInt7(type), "can't parse Table type");
+ WASM_PARSER_FAIL_IF(type != Wasm::Anyfunc, "Table type should be anyfunc, got ", type);
</ins><span class="cx">
</span><span class="cx"> uint32_t initial;
</span><span class="cx"> std::optional<uint32_t> maximum;
</span><del>- if (!parseResizableLimits(initial, maximum))
- return false;
</del><ins>+ PartialResult limits = parseResizableLimits(initial, maximum);
+ if (UNLIKELY(!limits))
+ return limits.getUnexpected();
+ WASM_PARSER_FAIL_IF(!JSWebAssemblyTable::isValidSize(initial), "Table's initial page count of ", initial, " is invalid");
</ins><span class="cx">
</span><del>- if (!JSWebAssemblyTable::isValidSize(initial))
- return false;
-
</del><span class="cx"> ASSERT(!maximum || *maximum >= initial);
</span><span class="cx">
</span><del>- m_module->tableInformation = TableInformation(initial, maximum, isImport);
</del><ins>+ m_result.module->tableInformation = TableInformation(initial, maximum, isImport);
</ins><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseTable()
</del><ins>+auto ModuleParser::parseTable() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> uint32_t count;
</span><del>- if (!parseVarUInt32(count))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Table's count");
+ WASM_PARSER_FAIL_IF(count != 1, "Table count of ", count, " is invalid, only 1 is allowed for now");
</ins><span class="cx">
</span><del>- // We only allow one table for now.
- if (count != 1)
- return false;
</del><ins>+ bool isImport = false;
+ PartialResult result = parseTableHelper(isImport);
+ if (UNLIKELY(!result))
+ return result.getUnexpected();
</ins><span class="cx">
</span><del>- bool isImport = false;
- return parseTableHelper(isImport);
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseMemoryHelper(bool isImport)
</del><ins>+auto ModuleParser::parseMemoryHelper(bool isImport) -> PartialResult
</ins><span class="cx"> {
</span><del>- // We don't allow redeclaring memory. Either via import or definition.
- if (m_module->memory)
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(m_result.module->memory, "Memory section cannot exist if an Import has a memory");
</ins><span class="cx">
</span><span class="cx"> PageCount initialPageCount;
</span><span class="cx"> PageCount maximumPageCount;
</span><span class="lines">@@ -391,17 +294,16 @@
</span><span class="cx"> {
</span><span class="cx"> uint32_t initial;
</span><span class="cx"> std::optional<uint32_t> maximum;
</span><del>- if (!parseResizableLimits(initial, maximum))
- return false;
</del><ins>+ PartialResult limits = parseResizableLimits(initial, maximum);
+ if (UNLIKELY(!limits))
+ return limits.getUnexpected();
</ins><span class="cx"> ASSERT(!maximum || *maximum >= initial);
</span><del>- if (!PageCount::isValid(initial))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!PageCount::isValid(initial), "Memory's initial page count of ", initial, " is invalid");
</ins><span class="cx">
</span><span class="cx"> initialPageCount = PageCount(initial);
</span><span class="cx">
</span><span class="cx"> if (maximum) {
</span><del>- if (!PageCount::isValid(*maximum))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!PageCount::isValid(*maximum), "Memory's maximum page count of ", *maximum, " is invalid");
</ins><span class="cx"> maximumPageCount = PageCount(*maximum);
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -409,44 +311,37 @@
</span><span class="cx"> ASSERT(!maximumPageCount || maximumPageCount >= initialPageCount);
</span><span class="cx">
</span><span class="cx"> Vector<unsigned> pinnedSizes = { 0 };
</span><del>- m_module->memory = MemoryInformation(initialPageCount, maximumPageCount, pinnedSizes, isImport);
- return true;
</del><ins>+ m_result.module->memory = MemoryInformation(initialPageCount, maximumPageCount, pinnedSizes, isImport);
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseMemory()
</del><ins>+auto ModuleParser::parseMemory() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> uint8_t count;
</span><del>- if (!parseVarUInt1(count))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt1(count), "can't parse Memory section's count");
</ins><span class="cx">
</span><span class="cx"> if (!count)
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx">
</span><del>- // We only allow one memory for now.
- if (count != 1)
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(count != 1, "Memory section has more than one memory, WebAssembly currently only allows zero or one");
</ins><span class="cx">
</span><span class="cx"> bool isImport = false;
</span><span class="cx"> return parseMemoryHelper(isImport);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseGlobal()
</del><ins>+auto ModuleParser::parseGlobal() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> uint32_t globalCount;
</span><del>- if (!parseVarUInt32(globalCount))
- return false;
- if (!m_module->globals.tryReserveCapacity(globalCount + m_module->firstInternalGlobal))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(globalCount), "can't get Global section's count");
+ WASM_PARSER_FAIL_IF(!m_result.module->globals.tryReserveCapacity(globalCount + m_result.module->firstInternalGlobal), "can't allocate memory for ", globalCount + m_result.module->firstInternalGlobal, " globals");
</ins><span class="cx">
</span><span class="cx"> for (uint32_t globalIndex = 0; globalIndex < globalCount; ++globalIndex) {
</span><span class="cx"> Global global;
</span><del>- if (!parseGlobalType(global))
- return false;
-
</del><span class="cx"> uint8_t initOpcode;
</span><del>- if (!parseInitExpr(initOpcode, global.initialBitsOrImportNumber))
- return false;
</del><span class="cx">
</span><ins>+ WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global));
+ WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, global.initialBitsOrImportNumber));
+
</ins><span class="cx"> global.initializationType = Global::FromExpression;
</span><span class="cx"> Type typeForInitOpcode;
</span><span class="cx"> switch (initOpcode) {
</span><span class="lines">@@ -463,9 +358,8 @@
</span><span class="cx"> typeForInitOpcode = F64;
</span><span class="cx"> break;
</span><span class="cx"> case GetGlobal:
</span><del>- if (global.initialBitsOrImportNumber >= m_module->firstInternalGlobal)
- return false;
- typeForInitOpcode = m_module->globals[global.initialBitsOrImportNumber].type;
</del><ins>+ WASM_PARSER_FAIL_IF(global.initialBitsOrImportNumber >= m_result.module->firstInternalGlobal, globalIndex, "th Global uses get_global ", global.initialBitsOrImportNumber, " which exceeds the first internal global ", m_result.module->firstInternalGlobal);
+ typeForInitOpcode = m_result.module->globals[global.initialBitsOrImportNumber].type;
</ins><span class="cx"> global.initializationType = Global::FromGlobalImport;
</span><span class="cx"> break;
</span><span class="cx"> default:
</span><span class="lines">@@ -472,121 +366,95 @@
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (typeForInitOpcode != global.type)
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(typeForInitOpcode != global.type, "Global init_expr opcode of type ", typeForInitOpcode, " doesn't match global's type ", global.type);
</ins><span class="cx">
</span><del>- m_module->globals.uncheckedAppend(WTFMove(global));
</del><ins>+ m_result.module->globals.uncheckedAppend(WTFMove(global));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseExport()
</del><ins>+auto ModuleParser::parseExport() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> uint32_t exportCount;
</span><del>- if (!parseVarUInt32(exportCount)
- || exportCount == std::numeric_limits<uint32_t>::max()
- || !m_module->exports.tryReserveCapacity(exportCount))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(exportCount), "can't get Export section's count");
+ WASM_PARSER_FAIL_IF(exportCount == std::numeric_limits<uint32_t>::max(), "Export section's count is too big ", exportCount);
+ WASM_PARSER_FAIL_IF(!m_result.module->exports.tryReserveCapacity(exportCount), "can't allocate enough memory for ", exportCount, " exports");
</ins><span class="cx">
</span><span class="cx"> for (uint32_t exportNumber = 0; exportNumber < exportCount; ++exportNumber) {
</span><span class="cx"> Export exp;
</span><span class="cx"> uint32_t fieldLen;
</span><span class="cx"> String fieldString;
</span><del>- if (!parseVarUInt32(fieldLen)
- || !consumeUTF8String(fieldString, fieldLen))
- return false;
</del><ins>+
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", exportNumber, "th Export's field name length");
+ WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", exportNumber, "th Export's field name of length ", fieldLen);
</ins><span class="cx"> exp.field = Identifier::fromString(m_vm, fieldString);
</span><span class="cx">
</span><del>- if (!parseExternalKind(exp.kind))
- return false;
-
- if (!parseVarUInt32(exp.kindIndex))
- return false;
-
</del><ins>+ WASM_PARSER_FAIL_IF(!parseExternalKind(exp.kind), "can't get ", exportNumber, "th Export's kind, named '", fieldString, "'");
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(exp.kindIndex), "can't get ", exportNumber, "th Export's kind index, named '", fieldString, "'");
</ins><span class="cx"> switch (exp.kind) {
</span><del>- case External::Function: {
- if (exp.kindIndex >= m_functionIndexSpace.size())
- return false;
</del><ins>+ case ExternalKind::Function: {
+ WASM_PARSER_FAIL_IF(exp.kindIndex >= m_result.functionIndexSpace.size(), exportNumber, "th Export has invalid function number ", exp.kindIndex, " it exceeds the function index space ", m_result.functionIndexSpace.size(), ", named '", fieldString, "'");
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case External::Table: {
- if (!m_hasTable)
- return false;
- if (exp.kindIndex != 0)
- return false;
</del><ins>+ case ExternalKind::Table: {
+ WASM_PARSER_FAIL_IF(!m_hasTable, "can't export a non-existent Table");
+ WASM_PARSER_FAIL_IF(exp.kindIndex, "can't export Table ", exp.kindIndex, " only zero-index Table is currently supported");
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case External::Memory: {
- if (!m_module->memory)
- return false;
- if (exp.kindIndex != 0)
- return false;
</del><ins>+ case ExternalKind::Memory: {
+ WASM_PARSER_FAIL_IF(!m_result.module->memory, "can't export a non-existent Memory");
+ WASM_PARSER_FAIL_IF(exp.kindIndex, "can't export Memory ", exp.kindIndex, " only one Table is currently supported");
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case External::Global: {
- if (exp.kindIndex >= m_module->globals.size())
- return false;
-
- if (m_module->globals[exp.kindIndex].mutability != Global::Immutable)
- return false;
</del><ins>+ case ExternalKind::Global: {
+ WASM_PARSER_FAIL_IF(exp.kindIndex >= m_result.module->globals.size(), exportNumber, "th Export has invalid global number ", exp.kindIndex, " it exceeds the globals count ", m_result.module->globals.size(), ", named '", fieldString, "'");
+ WASM_PARSER_FAIL_IF(m_result.module->globals[exp.kindIndex].mutability != Global::Immutable, exportNumber, "th Export isn't immutable, named '", fieldString, "'");
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- m_module->exports.uncheckedAppend(exp);
</del><ins>+ m_result.module->exports.uncheckedAppend(exp);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseStart()
</del><ins>+auto ModuleParser::parseStart() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> uint32_t startFunctionIndex;
</span><del>- if (!parseVarUInt32(startFunctionIndex)
- || startFunctionIndex >= m_functionIndexSpace.size())
- return false;
- Signature* signature = m_functionIndexSpace[startFunctionIndex].signature;
- if (signature->arguments.size() != 0
- || signature->returnType != Void)
- return false;
- m_module->startFunctionIndexSpace = startFunctionIndex;
- return true;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(startFunctionIndex), "can't get Start index");
+ WASM_PARSER_FAIL_IF(startFunctionIndex >= m_result.functionIndexSpace.size(), "Start index ", startFunctionIndex, " exceeds function index space ", m_result.functionIndexSpace.size());
+ Signature* signature = m_result.functionIndexSpace[startFunctionIndex].signature;
+ WASM_PARSER_FAIL_IF(!signature->arguments.isEmpty(), "Start function can't have arguments");
+ WASM_PARSER_FAIL_IF(signature->returnType != Void, "Start function can't return a value");
+ m_result.module->startFunctionIndexSpace = startFunctionIndex;
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseElement()
</del><ins>+auto ModuleParser::parseElement() -> PartialResult
</ins><span class="cx"> {
</span><del>- if (!m_hasTable)
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!m_hasTable, "Element section expects a Table to be present");
</ins><span class="cx">
</span><span class="cx"> uint32_t elementCount;
</span><del>- if (!parseVarUInt32(elementCount))
- return false;
- if (!m_module->elements.tryReserveCapacity(elementCount))
- return false;
-
- for (unsigned i = 0; i < elementCount; ++i) {
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(elementCount), "can't get Element section's count");
+ WASM_PARSER_FAIL_IF(elementCount == std::numeric_limits<uint32_t>::max(), "Element section's count is too big ", elementCount);
+ WASM_PARSER_FAIL_IF(!m_result.module->elements.tryReserveCapacity(elementCount), "can't allocate memory for ", elementCount, " Elements");
+ for (unsigned elementNum = 0; elementNum < elementCount; ++elementNum) {
</ins><span class="cx"> uint32_t tableIndex;
</span><del>- if (!parseVarUInt32(tableIndex))
- return false;
- // We only support one table for now.
- if (tableIndex != 0)
- return false;
-
</del><span class="cx"> uint64_t offset;
</span><span class="cx"> uint8_t initOpcode;
</span><del>- if (!parseInitExpr(initOpcode, offset))
- return false;
</del><ins>+ uint32_t indexCount;
</ins><span class="cx">
</span><del>- if (initOpcode != OpType::I32Const)
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index");
+ WASM_PARSER_FAIL_IF(tableIndex, "Element section can only have one Table for now");
+ WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, offset));
+ WASM_PARSER_FAIL_IF(initOpcode != OpType::I32Const, "Element section doesn't support non-i32 init_expr opcode for now, got ", initOpcode);
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(indexCount), "can't get ", elementNum, "th index count for Element section");
+ WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount);
</ins><span class="cx">
</span><del>- uint32_t indexCount;
- if (!parseVarUInt32(indexCount))
- return false;
-
- ASSERT(!!m_module->tableInformation);
- if (std::optional<uint32_t> maximum = m_module->tableInformation.maximum()) {
</del><ins>+ ASSERT(!!m_result.module->tableInformation);
+ if (std::optional<uint32_t> maximum = m_result.module->tableInformation.maximum()) {
</ins><span class="cx"> // FIXME: should indexCount being zero be a validation error?
</span><span class="cx"> // https://bugs.webkit.org/show_bug.cgi?id=165826
</span><span class="cx"> if (indexCount) {
</span><span class="lines">@@ -594,67 +462,58 @@
</span><span class="cx"> // Should they be though?
</span><span class="cx"> // https://bugs.webkit.org/show_bug.cgi?id=165827
</span><span class="cx"> uint64_t lastWrittenIndex = static_cast<uint64_t>(indexCount) + static_cast<uint64_t>(offset) - 1;
</span><del>- if (lastWrittenIndex >= static_cast<uint64_t>(*maximum))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(lastWrittenIndex >= static_cast<uint64_t>(*maximum), "Element section's ", elementNum, "th element writes to index ", lastWrittenIndex, " which exceeds the maximum ", *maximum);
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> Element element;
</span><del>- if (!element.functionIndices.tryReserveCapacity(indexCount))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
</ins><span class="cx">
</span><span class="cx"> element.offset = offset;
</span><span class="cx">
</span><del>- for (unsigned i = 0; i < indexCount; ++i) {
</del><ins>+ for (unsigned index = 0; index < indexCount; ++index) {
</ins><span class="cx"> uint32_t functionIndex;
</span><del>- if (!parseVarUInt32(functionIndex))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index");
+ WASM_PARSER_FAIL_IF(functionIndex >= m_result.functionIndexSpace.size(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_result.functionIndexSpace.size());
</ins><span class="cx">
</span><del>- if (functionIndex >= m_functionIndexSpace.size())
- return false;
-
</del><span class="cx"> element.functionIndices.uncheckedAppend(functionIndex);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- m_module->elements.uncheckedAppend(WTFMove(element));
</del><ins>+ m_result.module->elements.uncheckedAppend(WTFMove(element));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseCode()
</del><ins>+auto ModuleParser::parseCode() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> uint32_t count;
</span><del>- if (!parseVarUInt32(count)
- || count == std::numeric_limits<uint32_t>::max()
- || count != m_functionLocationInBinary.size())
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Code section's count");
+ WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Code section's count is too big ", count);
+ WASM_PARSER_FAIL_IF(count != m_result.functionLocationInBinary.size(), "Code section count ", count, " exceeds the declared number of functions ", m_result.functionLocationInBinary.size());
</ins><span class="cx">
</span><span class="cx"> for (uint32_t i = 0; i < count; ++i) {
</span><span class="cx"> uint32_t functionSize;
</span><del>- if (!parseVarUInt32(functionSize)
- || functionSize > length()
- || functionSize > length() - m_offset)
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSize), "can't get ", i, "th Code function's size");
+ WASM_PARSER_FAIL_IF(functionSize > length(), "Code function's size ", functionSize, " exceeds the module's size ", length());
+ WASM_PARSER_FAIL_IF(functionSize > length() - m_offset, "Code function's size ", functionSize, " exceeds the module's remaining size", length() - m_offset);
</ins><span class="cx">
</span><del>- m_functionLocationInBinary[i].start = m_offset;
- m_functionLocationInBinary[i].end = m_offset + functionSize;
- m_offset = m_functionLocationInBinary[i].end;
</del><ins>+ m_result.functionLocationInBinary[i].start = m_offset;
+ m_result.functionLocationInBinary[i].end = m_offset + functionSize;
+ m_offset = m_result.functionLocationInBinary[i].end;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseInitExpr(uint8_t& opcode, uint64_t& bitsOrImportNumber)
</del><ins>+auto ModuleParser::parseInitExpr(uint8_t& opcode, uint64_t& bitsOrImportNumber) -> PartialResult
</ins><span class="cx"> {
</span><del>- if (!parseUInt8(opcode))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseUInt8(opcode), "can't get init_expr's opcode");
</ins><span class="cx">
</span><span class="cx"> switch (opcode) {
</span><span class="cx"> case I32Const: {
</span><span class="cx"> int32_t constant;
</span><del>- if (!parseVarInt32(constant))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't get constant value for init_expr's i32.const");
</ins><span class="cx"> bitsOrImportNumber = static_cast<uint64_t>(constant);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -661,8 +520,7 @@
</span><span class="cx">
</span><span class="cx"> case I64Const: {
</span><span class="cx"> int64_t constant;
</span><del>- if (!parseVarInt64(constant))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't get constant value for init_expr's i64.const");
</ins><span class="cx"> bitsOrImportNumber = constant;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -669,8 +527,7 @@
</span><span class="cx">
</span><span class="cx"> case F32Const: {
</span><span class="cx"> uint32_t constant;
</span><del>- if (!parseUInt32(constant))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't get constant value for init_expr's f32.const");
</ins><span class="cx"> bitsOrImportNumber = constant;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -677,8 +534,7 @@
</span><span class="cx">
</span><span class="cx"> case F64Const: {
</span><span class="cx"> uint64_t constant;
</span><del>- if (!parseUInt64(constant))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't get constant value for init_expr's f64.const");
</ins><span class="cx"> bitsOrImportNumber = constant;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -685,94 +541,69 @@
</span><span class="cx">
</span><span class="cx"> case GetGlobal: {
</span><span class="cx"> uint32_t index;
</span><del>- if (!parseVarUInt32(index))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index");
+ WASM_PARSER_FAIL_IF(index >= m_result.module->imports.size(), "get_global's index ", index, " exceeds the number of imports ", m_result.module->imports.size());
+ const Import& import = m_result.module->imports[index];
+ WASM_PARSER_FAIL_IF(m_result.module->imports[index].kind != ExternalKind::Global, "get_global's import kind is ", m_result.module->imports[index].kind, " should be global");
+ WASM_PARSER_FAIL_IF(import.kindIndex >= m_result.module->firstInternalGlobal, "get_global import kind index ", import.kindIndex, " exceeds the first internal global ", m_result.module->firstInternalGlobal);
</ins><span class="cx">
</span><del>- if (index >= m_module->imports.size())
- return false;
- const Import& import = m_module->imports[index];
- if (m_module->imports[index].kind != External::Global
- || import.kindIndex >= m_module->firstInternalGlobal)
- return false;
</del><ins>+ ASSERT(m_result.module->globals[import.kindIndex].mutability == Global::Immutable);
</ins><span class="cx">
</span><del>- ASSERT(m_module->globals[import.kindIndex].mutability == Global::Immutable);
-
</del><span class="cx"> bitsOrImportNumber = index;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> default:
</span><del>- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(false, "unknown init_expr opcode ", opcode);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> uint8_t endOpcode;
</span><del>- if (!parseUInt8(endOpcode) || endOpcode != OpType::End)
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseUInt8(endOpcode), "can't get init_expr's end opcode");
+ WASM_PARSER_FAIL_IF(endOpcode != OpType::End, "init_expr should end with end, ended with ", endOpcode);
</ins><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseGlobalType(Global& global)
</del><ins>+auto ModuleParser::parseGlobalType(Global& global) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> uint8_t mutability;
</span><del>- if (!parseValueType(global.type) || !parseVarUInt1(mutability))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseValueType(global.type), "can't get Global's value type");
+ WASM_PARSER_FAIL_IF(!parseVarUInt1(mutability), "can't get Global type's mutability");
</ins><span class="cx"> global.mutability = static_cast<Global::Mutability>(mutability);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool ModuleParser::parseData()
</del><ins>+auto ModuleParser::parseData() -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> uint32_t segmentCount;
</span><del>- if (!m_module->memory)
- return false;
- if (!parseVarUInt32(segmentCount)
- || segmentCount == std::numeric_limits<uint32_t>::max()
- || !m_module->data.tryReserveCapacity(segmentCount))
- return false;
- if (verbose)
- dataLogLn(" segments: ", segmentCount);
</del><ins>+ WASM_PARSER_FAIL_IF(!m_result.module->memory, "Data section cannot exist without a Memory section or Import");
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(segmentCount), "can't get Data section's count");
+ WASM_PARSER_FAIL_IF(segmentCount == std::numeric_limits<uint32_t>::max(), "Data section's count is too big ", segmentCount);
+ WASM_PARSER_FAIL_IF(!m_result.module->data.tryReserveCapacity(segmentCount), "can't allocate enough memory for Data section's ", segmentCount, " segments");
</ins><span class="cx">
</span><span class="cx"> for (uint32_t segmentNumber = 0; segmentNumber < segmentCount; ++segmentNumber) {
</span><del>- if (verbose)
- dataLogLn(" segment #", segmentNumber);
</del><span class="cx"> uint32_t index;
</span><span class="cx"> uint64_t offset;
</span><span class="cx"> uint8_t initOpcode;
</span><span class="cx"> uint32_t dataByteLength;
</span><del>- if (!parseVarUInt32(index)
- || index)
- return false;
</del><span class="cx">
</span><del>- if (!parseInitExpr(initOpcode, offset))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get ", segmentNumber, "th Data segment's index");
+ WASM_PARSER_FAIL_IF(index, segmentNumber, "th Data segment has non-zero index ", index);
+ WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, offset));
+ WASM_PARSER_FAIL_IF(initOpcode != OpType::I32Const, segmentNumber, "th Data segment has opcode ", initOpcode, " expected i32.const");
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(dataByteLength), "can't get ", segmentNumber, "th Data segment's data byte length");
+ WASM_PARSER_FAIL_IF(dataByteLength == std::numeric_limits<uint32_t>::max(), segmentNumber, "th Data segment's data byte length is too big ", dataByteLength);
</ins><span class="cx">
</span><del>- if (initOpcode != OpType::I32Const)
- return false;
-
- if (verbose)
- dataLogLn(" offset: ", offset);
-
- if (!parseVarUInt32(dataByteLength)
- || dataByteLength == std::numeric_limits<uint32_t>::max())
- return false;
- if (verbose)
- dataLogLn(" data bytes: ", dataByteLength);
-
</del><span class="cx"> Segment* segment = Segment::make(offset, dataByteLength);
</span><del>- if (!segment)
- return false;
- m_module->data.uncheckedAppend(Segment::makePtr(segment));
</del><ins>+ WASM_PARSER_FAIL_IF(!segment, "can't allocate enough memory for ", segmentNumber, "th Data segment of size ", dataByteLength);
+ m_result.module->data.uncheckedAppend(Segment::makePtr(segment));
</ins><span class="cx"> for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) {
</span><span class="cx"> uint8_t byte;
</span><del>- if (!parseUInt8(byte))
- return false;
</del><ins>+ WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", dataByte, "th data byte from ", segmentNumber, "th Data segment");
</ins><span class="cx"> segment->byte(dataByte) = byte;
</span><del>- if (verbose)
- dataLogLn(" [", dataByte, "] = ", segment->byte(dataByte));
</del><span class="cx"> }
</span><span class="cx"> }
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> } } // namespace JSC::Wasm
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmModuleParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmModuleParser.h (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmModuleParser.h        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/WasmModuleParser.h        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -34,7 +34,13 @@
</span><span class="cx">
</span><span class="cx"> namespace JSC { namespace Wasm {
</span><span class="cx">
</span><del>-class ModuleParser : public Parser {
</del><ins>+struct ModuleParserResult {
+ std::unique_ptr<ModuleInformation> module;
+ FunctionIndexSpace functionIndexSpace;
+ Vector<FunctionLocationInBinary> functionLocationInBinary;
+};
+
+class ModuleParser : public Parser<ModuleParserResult> {
</ins><span class="cx"> public:
</span><span class="cx">
</span><span class="cx"> ModuleParser(VM* vm, const uint8_t* sourceBuffer, size_t sourceLength)
</span><span class="lines">@@ -47,51 +53,23 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><del>- bool WARN_UNUSED_RETURN parse();
- bool WARN_UNUSED_RETURN failed() const { return m_failed; }
- const String& errorMessage() const
- {
- RELEASE_ASSERT(failed());
- return m_errorMessage;
- }
</del><ins>+ Result WARN_UNUSED_RETURN parse();
</ins><span class="cx">
</span><del>- std::unique_ptr<ModuleInformation>& moduleInformation()
- {
- RELEASE_ASSERT(!failed());
- return m_module;
- }
-
- FunctionIndexSpace& functionIndexSpace()
- {
- RELEASE_ASSERT(!failed());
- return m_functionIndexSpace;
- }
-
- Vector<FunctionLocationInBinary>& functionLocationInBinary()
- {
- RELEASE_ASSERT(!failed());
- return m_functionLocationInBinary;
- }
-
</del><span class="cx"> private:
</span><del>- bool parseGlobalType(Global&);
</del><span class="cx">
</span><del>-#define WASM_SECTION_DECLARE_PARSER(NAME, ID, DESCRIPTION) bool WARN_UNUSED_RETURN parse ## NAME();
</del><ins>+#define WASM_SECTION_DECLARE_PARSER(NAME, ID, DESCRIPTION) PartialResult WARN_UNUSED_RETURN parse ## NAME();
</ins><span class="cx"> FOR_EACH_WASM_SECTION(WASM_SECTION_DECLARE_PARSER)
</span><span class="cx"> #undef WASM_SECTION_DECLARE_PARSER
</span><span class="cx">
</span><del>- bool WARN_UNUSED_RETURN parseMemoryHelper(bool isImport);
- bool WARN_UNUSED_RETURN parseTableHelper(bool isImport);
- bool WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum);
- bool WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&);
</del><ins>+ PartialResult WARN_UNUSED_RETURN parseGlobalType(Global&);
+ PartialResult WARN_UNUSED_RETURN parseMemoryHelper(bool isImport);
+ PartialResult WARN_UNUSED_RETURN parseTableHelper(bool isImport);
+ PartialResult WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum);
+ PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&);
</ins><span class="cx">
</span><span class="cx"> VM* m_vm;
</span><del>- std::unique_ptr<ModuleInformation> m_module;
- FunctionIndexSpace m_functionIndexSpace;
- Vector<FunctionLocationInBinary> m_functionLocationInBinary;
- bool m_failed { true };
</del><ins>+ ModuleParserResult m_result;
</ins><span class="cx"> bool m_hasTable { false };
</span><del>- String m_errorMessage;
</del><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> } } // namespace JSC::Wasm
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmParser.h (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmParser.h        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/WasmParser.h        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -32,6 +32,8 @@
</span><span class="cx"> #include "WasmFormat.h"
</span><span class="cx"> #include "WasmOps.h"
</span><span class="cx"> #include "WasmSections.h"
</span><ins>+#include <type_traits>
+#include <wtf/Expected.h>
</ins><span class="cx"> #include <wtf/LEBDecoder.h>
</span><span class="cx"> #include <wtf/StdLibExtras.h>
</span><span class="cx"> #include <wtf/text/WTFString.h>
</span><span class="lines">@@ -38,7 +40,21 @@
</span><span class="cx">
</span><span class="cx"> namespace JSC { namespace Wasm {
</span><span class="cx">
</span><ins>+namespace FailureHelper {
+// FIXME We should move this to makeString. It's in its own namespace to enable C++ Argument Dependent Lookup à la std::swap: user code can deblare its own "boxFailure" and the fail() helper will find it.
+static inline auto makeString(const char *failure) { return ASCIILiteral(failure); }
+template <typename Int, typename = typename std::enable_if<std::is_integral<Int>::value>::type>
+static inline auto makeString(Int failure) { return String::number(failure); }
+}
+
+template<typename SuccessType>
</ins><span class="cx"> class Parser {
</span><ins>+public:
+ typedef String ErrorType;
+ typedef UnexpectedType<ErrorType> UnexpectedResult;
+ typedef Expected<void, ErrorType> PartialResult;
+ typedef Expected<SuccessType, ErrorType> Result;
+
</ins><span class="cx"> protected:
</span><span class="cx"> Parser(const uint8_t*, size_t);
</span><span class="cx">
</span><span class="lines">@@ -60,7 +76,7 @@
</span><span class="cx">
</span><span class="cx"> bool WARN_UNUSED_RETURN parseResultType(Type&);
</span><span class="cx"> bool WARN_UNUSED_RETURN parseValueType(Type&);
</span><del>- bool WARN_UNUSED_RETURN parseExternalKind(External::Kind&);
</del><ins>+ bool WARN_UNUSED_RETURN parseExternalKind(ExternalKind&);
</ins><span class="cx">
</span><span class="cx"> const uint8_t* source() const { return m_source; }
</span><span class="cx"> size_t length() const { return m_sourceLength; }
</span><span class="lines">@@ -67,18 +83,37 @@
</span><span class="cx">
</span><span class="cx"> size_t m_offset = 0;
</span><span class="cx">
</span><ins>+ template <typename ...Args>
+ NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const
+ {
+ using namespace FailureHelper; // See ADL comment in namespace above.
+ return UnexpectedResult(makeString(ASCIILiteral("WebAssembly.Module doesn't parse at byte "), String::number(m_offset), ASCIILiteral(" / "), String::number(m_sourceLength), ASCIILiteral(": "), makeString(args)...));
+ }
+#define WASM_PARSER_FAIL_IF(condition, ...) do { \
+ if (UNLIKELY(condition)) \
+ return fail(__VA_ARGS__); \
+ } while (0)
+
+#define WASM_FAIL_IF_HELPER_FAILS(helper) do { \
+ auto helperResult = helper; \
+ if (UNLIKELY(!helperResult)) \
+ return helperResult.getUnexpected(); \
+ } while (0)
+
</ins><span class="cx"> private:
</span><span class="cx"> const uint8_t* m_source;
</span><span class="cx"> size_t m_sourceLength;
</span><span class="cx"> };
</span><span class="cx">
</span><del>-ALWAYS_INLINE Parser::Parser(const uint8_t* sourceBuffer, size_t sourceLength)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE Parser<SuccessType>::Parser(const uint8_t* sourceBuffer, size_t sourceLength)
</ins><span class="cx"> : m_source(sourceBuffer)
</span><span class="cx"> , m_sourceLength(sourceLength)
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::consumeCharacter(char c)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::consumeCharacter(char c)
</ins><span class="cx"> {
</span><span class="cx"> if (m_offset >= length())
</span><span class="cx"> return false;
</span><span class="lines">@@ -89,7 +124,8 @@
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::consumeString(const char* str)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::consumeString(const char* str)
</ins><span class="cx"> {
</span><span class="cx"> unsigned start = m_offset;
</span><span class="cx"> if (m_offset >= length())
</span><span class="lines">@@ -103,7 +139,8 @@
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::consumeUTF8String(String& result, size_t stringLength)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::consumeUTF8String(String& result, size_t stringLength)
</ins><span class="cx"> {
</span><span class="cx"> if (stringLength == 0) {
</span><span class="cx"> result = emptyString();
</span><span class="lines">@@ -118,27 +155,32 @@
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::parseVarUInt32(uint32_t& result)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseVarUInt32(uint32_t& result)
</ins><span class="cx"> {
</span><span class="cx"> return WTF::LEBDecoder::decodeUInt32(m_source, m_sourceLength, m_offset, result);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::parseVarUInt64(uint64_t& result)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseVarUInt64(uint64_t& result)
</ins><span class="cx"> {
</span><span class="cx"> return WTF::LEBDecoder::decodeUInt64(m_source, m_sourceLength, m_offset, result);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::parseVarInt32(int32_t& result)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseVarInt32(int32_t& result)
</ins><span class="cx"> {
</span><span class="cx"> return WTF::LEBDecoder::decodeInt32(m_source, m_sourceLength, m_offset, result);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::parseVarInt64(int64_t& result)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseVarInt64(int64_t& result)
</ins><span class="cx"> {
</span><span class="cx"> return WTF::LEBDecoder::decodeInt64(m_source, m_sourceLength, m_offset, result);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::parseUInt32(uint32_t& result)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseUInt32(uint32_t& result)
</ins><span class="cx"> {
</span><span class="cx"> if (length() < 4 || m_offset > length() - 4)
</span><span class="cx"> return false;
</span><span class="lines">@@ -147,7 +189,8 @@
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::parseUInt64(uint64_t& result)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseUInt64(uint64_t& result)
</ins><span class="cx"> {
</span><span class="cx"> if (length() < 8 || m_offset > length() - 8)
</span><span class="cx"> return false;
</span><span class="lines">@@ -156,7 +199,8 @@
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::parseUInt8(uint8_t& result)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseUInt8(uint8_t& result)
</ins><span class="cx"> {
</span><span class="cx"> if (m_offset >= length())
</span><span class="cx"> return false;
</span><span class="lines">@@ -164,7 +208,8 @@
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::parseInt7(int8_t& result)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseInt7(int8_t& result)
</ins><span class="cx"> {
</span><span class="cx"> if (m_offset >= length())
</span><span class="cx"> return false;
</span><span class="lines">@@ -173,7 +218,8 @@
</span><span class="cx"> return (v & 0x80) == 0;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::parseUInt7(uint8_t& result)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseUInt7(uint8_t& result)
</ins><span class="cx"> {
</span><span class="cx"> if (m_offset >= length())
</span><span class="cx"> return false;
</span><span class="lines">@@ -181,7 +227,8 @@
</span><span class="cx"> return result < 0x80;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::parseVarUInt1(uint8_t& result)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseVarUInt1(uint8_t& result)
</ins><span class="cx"> {
</span><span class="cx"> uint32_t temp;
</span><span class="cx"> if (!parseVarUInt32(temp))
</span><span class="lines">@@ -190,7 +237,8 @@
</span><span class="cx"> return temp <= 1;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::parseResultType(Type& result)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseResultType(Type& result)
</ins><span class="cx"> {
</span><span class="cx"> int8_t value;
</span><span class="cx"> if (!parseInt7(value))
</span><span class="lines">@@ -201,19 +249,21 @@
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-ALWAYS_INLINE bool Parser::parseValueType(Type& result)
</del><ins>+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseValueType(Type& result)
</ins><span class="cx"> {
</span><span class="cx"> return parseResultType(result) && isValueType(result);
</span><span class="cx"> }
</span><del>-
-ALWAYS_INLINE bool Parser::parseExternalKind(External::Kind& result)
</del><ins>+
+template<typename SuccessType>
+ALWAYS_INLINE bool Parser<SuccessType>::parseExternalKind(ExternalKind& result)
</ins><span class="cx"> {
</span><span class="cx"> uint8_t value;
</span><span class="cx"> if (!parseUInt7(value))
</span><span class="cx"> return false;
</span><del>- if (!External::isValid(value))
</del><ins>+ if (!isValidExternalKind(value))
</ins><span class="cx"> return false;
</span><del>- result = static_cast<External::Kind>(value);
</del><ins>+ result = static_cast<ExternalKind>(value);
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmPlancpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -60,23 +60,18 @@
</span><span class="cx">
</span><span class="cx"> void Plan::run()
</span><span class="cx"> {
</span><del>- if (verbose)
- dataLogLn("Starting plan.");
</del><span class="cx"> {
</span><span class="cx"> ModuleParser moduleParser(m_vm, m_source, m_sourceLength);
</span><del>- if (!moduleParser.parse()) {
- if (verbose)
- dataLogLn("Parsing module failed: ", moduleParser.errorMessage());
- m_errorMessage = moduleParser.errorMessage();
- return;
</del><ins>+ auto parseResult = moduleParser.parse();
+ if (!parseResult) {
+ m_errorMessage = parseResult.error();
+ return; // FIXME return an Expected.
</ins><span class="cx"> }
</span><del>- m_moduleInformation = WTFMove(moduleParser.moduleInformation());
- m_functionLocationInBinary = WTFMove(moduleParser.functionLocationInBinary());
- m_functionIndexSpace.size = moduleParser.functionIndexSpace().size();
- m_functionIndexSpace.buffer = moduleParser.functionIndexSpace().releaseBuffer();
</del><ins>+ m_moduleInformation = WTFMove(parseResult->module);
+ m_functionLocationInBinary = WTFMove(parseResult->functionLocationInBinary);
+ m_functionIndexSpace.size = parseResult->functionIndexSpace.size();
+ m_functionIndexSpace.buffer = parseResult->functionIndexSpace.releaseBuffer();
</ins><span class="cx"> }
</span><del>- if (verbose)
- dataLogLn("Parsed module.");
</del><span class="cx">
</span><span class="cx"> auto tryReserveCapacity = [this] (auto& vector, size_t size, const char* what) {
</span><span class="cx"> if (UNLIKELY(!vector.tryReserveCapacity(size))) {
</span><span class="lines">@@ -97,7 +92,7 @@
</span><span class="cx">
</span><span class="cx"> for (unsigned importIndex = 0; importIndex < m_moduleInformation->imports.size(); ++importIndex) {
</span><span class="cx"> Import* import = &m_moduleInformation->imports[importIndex];
</span><del>- if (import->kind != External::Function)
</del><ins>+ if (import->kind != ExternalKind::Function)
</ins><span class="cx"> continue;
</span><span class="cx"> unsigned importFunctionIndex = m_wasmToJSStubs.size();
</span><span class="cx"> if (verbose)
</span><span class="lines">@@ -117,19 +112,24 @@
</span><span class="cx"> unsigned functionIndexSpace = m_wasmToJSStubs.size() + functionIndex;
</span><span class="cx"> ASSERT(m_functionIndexSpace.buffer.get()[functionIndexSpace].signature == signature);
</span><span class="cx">
</span><del>- String error = validateFunction(functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation);
- if (!error.isNull()) {
</del><ins>+ auto validateResult = validateFunction(functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation);
+ if (!validateResult) {
</ins><span class="cx"> if (verbose) {
</span><span class="cx"> for (unsigned i = 0; i < functionLength; ++i)
</span><span class="cx"> dataLog(RawPointer(reinterpret_cast<void*>(functionStart[i])), ", ");
</span><span class="cx"> dataLogLn();
</span><span class="cx"> }
</span><del>- m_errorMessage = error;
</del><ins>+ m_errorMessage = validateResult.error(); // FIXME make this an Expected.
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> unlinkedWasmToWasmCalls.uncheckedAppend(Vector<UnlinkedWasmToWasmCall>());
</span><del>- m_wasmInternalFunctions.uncheckedAppend(parseAndCompile(*m_vm, functionStart, functionLength, signature, unlinkedWasmToWasmCalls.at(functionIndex), m_functionIndexSpace, *m_moduleInformation));
</del><ins>+ auto parseAndCompileResult = parseAndCompile(*m_vm, functionStart, functionLength, signature, unlinkedWasmToWasmCalls.at(functionIndex), m_functionIndexSpace, *m_moduleInformation);
+ if (UNLIKELY(!parseAndCompileResult)) {
+ m_errorMessage = parseAndCompileResult.error();
+ return; // FIXME make this an Expected.
+ }
+ m_wasmInternalFunctions.uncheckedAppend(WTFMove(*parseAndCompileResult));
</ins><span class="cx"> m_functionIndexSpace.buffer.get()[functionIndexSpace].code = m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation->code().executableAddress();
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmSectionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmSections.h (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmSections.h        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/WasmSections.h        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -42,21 +42,44 @@
</span><span class="cx"> macro(Code, 10, "Function bodies (code)") \
</span><span class="cx"> macro(Data, 11, "Data segments")
</span><span class="cx">
</span><del>-struct Sections {
- enum Section : uint8_t {
</del><ins>+enum class Section : uint8_t {
</ins><span class="cx"> #define DEFINE_WASM_SECTION_ENUM(NAME, ID, DESCRIPTION) NAME = ID,
</span><del>- FOR_EACH_WASM_SECTION(DEFINE_WASM_SECTION_ENUM)
</del><ins>+ FOR_EACH_WASM_SECTION(DEFINE_WASM_SECTION_ENUM)
</ins><span class="cx"> #undef DEFINE_WASM_SECTION_ENUM
</span><del>- Unknown
- };
- static bool validateOrder(Section previous, Section next)
- {
- if (previous == Unknown)
- return true;
- return previous < next;
- }
</del><ins>+ Unknown
</ins><span class="cx"> };
</span><span class="cx">
</span><ins>+template<typename Int>
+static inline bool isValidSection(Int section)
+{
+ switch (section) {
+#define VALIDATE_SECTION(NAME, ID, DESCRIPTION) case static_cast<Int>(Section::NAME): return true;
+ FOR_EACH_WASM_SECTION(VALIDATE_SECTION)
+#undef VALIDATE_SECTION
+ default:
+ return false;
+ }
+}
+
+static inline bool validateOrder(Section previous, Section next)
+{
+ if (previous == Section::Unknown)
+ return true;
+ return static_cast<uint8_t>(previous) < static_cast<uint8_t>(next);
+}
+
+static inline const char* makeString(Section section)
+{
+ switch (section) {
+#define STRINGIFY_SECTION_NAME(NAME, ID, DESCRIPTION) case Section::NAME: return #NAME;
+ FOR_EACH_WASM_SECTION(STRINGIFY_SECTION_NAME)
+#undef STRINGIFY_SECTION_NAME
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return "?";
+ }
+}
+
</ins><span class="cx"> } } // namespace JSC::Wasm
</span><span class="cx">
</span><span class="cx"> #endif // ENABLE(WEBASSEMBLY)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmValidatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -71,6 +71,9 @@
</span><span class="cx"> BlockType m_blockType;
</span><span class="cx"> Type m_signature;
</span><span class="cx"> };
</span><ins>+ typedef String ErrorType;
+ typedef UnexpectedType<ErrorType> UnexpectedResult;
+ typedef Expected<void, ErrorType> Result;
</ins><span class="cx"> typedef Type ExpressionType;
</span><span class="cx"> typedef ControlData ControlType;
</span><span class="cx"> typedef Vector<ExpressionType, 1> ExpressionList;
</span><span class="lines">@@ -78,54 +81,61 @@
</span><span class="cx">
</span><span class="cx"> static const ExpressionType emptyExpression = Void;
</span><span class="cx">
</span><del>- bool WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
- bool WARN_UNUSED_RETURN addLocal(Type, uint32_t);
</del><ins>+ template <typename ...Args>
+ NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const
+ {
+ using namespace FailureHelper; // See ADL comment in WasmParser.h.
+ return UnexpectedResult(makeString(ASCIILiteral("WebAssembly.Module doesn't validate: "), makeString(args)...));
+ }
+#define WASM_VALIDATOR_FAIL_IF(condition, ...) do { \
+ if (UNLIKELY(condition)) \
+ return fail(__VA_ARGS__); \
+ } while (0)
+
+ Result WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
+ Result WARN_UNUSED_RETURN addLocal(Type, uint32_t);
</ins><span class="cx"> ExpressionType addConstant(Type type, uint64_t) { return type; }
</span><span class="cx">
</span><span class="cx"> // Locals
</span><del>- bool WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
- bool WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
</del><ins>+ Result WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
+ Result WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
</ins><span class="cx">
</span><span class="cx"> // Globals
</span><del>- bool WARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result);
- bool WARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value);
</del><ins>+ Result WARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result);
+ Result WARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value);
</ins><span class="cx">
</span><span class="cx"> // Memory
</span><del>- bool WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
- bool WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
</del><ins>+ Result WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
+ Result WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
</ins><span class="cx">
</span><span class="cx"> // Basic operators
</span><span class="cx"> template<OpType>
</span><del>- bool WARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result);
</del><ins>+ Result WARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result);
</ins><span class="cx"> template<OpType>
</span><del>- bool WARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result);
- bool WARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result);
</del><ins>+ Result WARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result);
+ Result WARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result);
</ins><span class="cx">
</span><span class="cx"> // Control flow
</span><span class="cx"> ControlData WARN_UNUSED_RETURN addBlock(Type signature);
</span><span class="cx"> ControlData WARN_UNUSED_RETURN addLoop(Type signature);
</span><del>- bool WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);
- bool WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);
- bool WARN_UNUSED_RETURN addElseToUnreachable(ControlData&);
</del><ins>+ Result WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);
+ Result WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);
+ Result WARN_UNUSED_RETURN addElseToUnreachable(ControlData&);
</ins><span class="cx">
</span><del>- bool WARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues);
- bool WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& expressionStack);
- bool WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack);
- bool WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);
- bool WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);
</del><ins>+ Result WARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues);
+ Result WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& expressionStack);
+ Result WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack);
+ Result WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);
+ Result WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);
</ins><span class="cx">
</span><del>- void addUnreachable() { }
</del><ins>+ Result WARN_UNUSED_RETURN addUnreachable() { return { }; }
</ins><span class="cx">
</span><span class="cx"> // Calls
</span><del>- bool WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature*, const Vector<ExpressionType>& args, ExpressionType& result);
- bool WARN_UNUSED_RETURN addCallIndirect(const Signature*, const Vector<ExpressionType>& args, ExpressionType& result);
</del><ins>+ Result WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature*, const Vector<ExpressionType>& args, ExpressionType& result);
+ Result WARN_UNUSED_RETURN addCallIndirect(const Signature*, const Vector<ExpressionType>& args, ExpressionType& result);
</ins><span class="cx">
</span><del>- void dump(const Vector<ControlEntry>& controlStack, const ExpressionList& expressionStack);
-
</del><span class="cx"> bool hasMemory() const { return !!m_module.memory; }
</span><span class="cx">
</span><del>- void setErrorMessage(String&& message) { ASSERT(m_errorMessage.isNull()); m_errorMessage = WTFMove(message); }
- String errorMessage() const { return m_errorMessage; }
</del><span class="cx"> Validate(ExpressionType returnType, const ModuleInformation& module)
</span><span class="cx"> : m_returnType(returnType)
</span><span class="cx"> , m_module(module)
</span><span class="lines">@@ -132,90 +142,68 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ void dump(const Vector<ControlEntry>&, const ExpressionList&);
+
</ins><span class="cx"> private:
</span><del>- bool unify(Type, Type);
- bool unify(const ExpressionList&, const ControlData&);
</del><ins>+ Result unify(Type, Type);
+ Result unify(const ExpressionList&, const ControlData&);
</ins><span class="cx">
</span><del>- bool checkBranchTarget(ControlData& target, const ExpressionList& expressionStack);
</del><ins>+ Result checkBranchTarget(ControlData& target, const ExpressionList& expressionStack);
</ins><span class="cx">
</span><span class="cx"> ExpressionType m_returnType;
</span><span class="cx"> Vector<Type> m_locals;
</span><del>- String m_errorMessage;
</del><span class="cx"> const ModuleInformation& m_module;
</span><span class="cx"> };
</span><span class="cx">
</span><del>-bool Validate::addArguments(const Vector<Type>& args)
</del><ins>+auto Validate::addArguments(const Vector<Type>& args) -> Result
</ins><span class="cx"> {
</span><del>- for (Type arg : args) {
- if (!addLocal(arg, 1))
- return false;
- }
- return true;
</del><ins>+ for (Type arg : args)
+ WASM_FAIL_IF_HELPER_FAILS(addLocal(arg, 1));
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::addLocal(Type type, uint32_t count)
</del><ins>+auto Validate::addLocal(Type type, uint32_t count) -> Result
</ins><span class="cx"> {
</span><del>- if (!m_locals.tryReserveCapacity(m_locals.size() + count))
- return false;
</del><ins>+ size_t size = m_locals.size() + count;
+ WASM_VALIDATOR_FAIL_IF(!m_locals.tryReserveCapacity(size), "can't allocate memory for ", size, " locals");
</ins><span class="cx">
</span><span class="cx"> for (uint32_t i = 0; i < count; ++i)
</span><span class="cx"> m_locals.uncheckedAppend(type);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::getLocal(uint32_t index, ExpressionType& result)
</del><ins>+auto Validate::getLocal(uint32_t index, ExpressionType& result) -> Result
</ins><span class="cx"> {
</span><del>- if (index < m_locals.size()) {
- result = m_locals[index];
- return true;
- }
- m_errorMessage = ASCIILiteral("Attempt to use unknown local.");
- return false;
</del><ins>+ WASM_VALIDATOR_FAIL_IF(index >= m_locals.size(), "attempt to use unknown local ", index, " last one is ", m_locals.size());
+ result = m_locals[index];
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::setLocal(uint32_t index, ExpressionType value)
</del><ins>+auto Validate::setLocal(uint32_t index, ExpressionType value) -> Result
</ins><span class="cx"> {
</span><span class="cx"> ExpressionType localType;
</span><del>- if (!getLocal(index, localType))
- return false;
-
- if (localType == value)
- return true;
-
- m_errorMessage = makeString("Attempt to set local with type: ", toString(localType), " with a variable of type: ", toString(value));
- return false;
</del><ins>+ WASM_FAIL_IF_HELPER_FAILS(getLocal(index, localType));
+ WASM_VALIDATOR_FAIL_IF(localType != value, "set_local to type ", value, " expected ", localType);
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::getGlobal(uint32_t index, ExpressionType& result)
</del><ins>+auto Validate::getGlobal(uint32_t index, ExpressionType& result) -> Result
</ins><span class="cx"> {
</span><del>- if (index < m_module.globals.size()) {
- result = m_module.globals[index].type;
- ASSERT(isValueType(result));
- return true;
- }
- m_errorMessage = ASCIILiteral("Attempt to use unknown global.");
- return false;
</del><ins>+ WASM_VALIDATOR_FAIL_IF(index >= m_module.globals.size(), "get_global ", index, " of unknown global, limit is ", m_module.globals.size());
+ result = m_module.globals[index].type;
+ ASSERT(isValueType(result));
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::setGlobal(uint32_t index, ExpressionType value)
</del><ins>+auto Validate::setGlobal(uint32_t index, ExpressionType value) -> Result
</ins><span class="cx"> {
</span><del>- if (index >= m_module.globals.size()) {
- m_errorMessage = ASCIILiteral("Attempt to use unknown global.");
- return false;
- }
</del><ins>+ WASM_VALIDATOR_FAIL_IF(index >= m_module.globals.size(), "set_global ", index, " of unknown global, limit is ", m_module.globals.size());
+ WASM_VALIDATOR_FAIL_IF(m_module.globals[index].mutability == Global::Immutable, "set_global ", index, " is immutable");
</ins><span class="cx">
</span><del>- if (m_module.globals[index].mutability == Global::Immutable) {
- m_errorMessage = ASCIILiteral("Attempt to store to immutable global.");
- return false;
- }
-
</del><span class="cx"> ExpressionType globalType = m_module.globals[index].type;
</span><span class="cx"> ASSERT(isValueType(globalType));
</span><del>- if (globalType == value)
- return true;
-
- m_errorMessage = makeString("Attempt to set global with type: ", toString(globalType), " with a variable of type: ", toString(value));
- return false;
</del><ins>+ WASM_VALIDATOR_FAIL_IF(globalType != value, "set_global ", index, " with type ", globalType, " with a variable of type ", value);
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> Validate::ControlType Validate::addBlock(Type signature)
</span><span class="lines">@@ -228,209 +216,129 @@
</span><span class="cx"> return ControlData(BlockType::Loop, signature);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result)
</del><ins>+auto Validate::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result) -> Result
</ins><span class="cx"> {
</span><del>- if (condition != I32) {
- m_errorMessage = makeString("Attempting to use ", toString(condition), " as the condition for select");
- return false;
- }
-
- if (nonZero != zero) {
- m_errorMessage = makeString("Result types of select don't match. Got: ", toString(nonZero), " and ", toString(zero));
- return false;
- }
-
</del><ins>+ WASM_VALIDATOR_FAIL_IF(condition != I32, "select condition must be i32, got ", condition);
+ WASM_VALIDATOR_FAIL_IF(nonZero != zero, "select result types must match, got ", nonZero, " and ", zero);
</ins><span class="cx"> result = zero;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::addIf(ExpressionType condition, Type signature, ControlType& result)
</del><ins>+auto Validate::addIf(ExpressionType condition, Type signature, ControlType& result) -> Result
</ins><span class="cx"> {
</span><del>- if (condition != I32) {
- m_errorMessage = makeString("Attempting to use ", toString(condition), " as the condition for an if block");
- return false;
- }
</del><ins>+ WASM_VALIDATOR_FAIL_IF(condition != I32, "if condition must be i32, got ", condition);
</ins><span class="cx"> result = ControlData(BlockType::If, signature);
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::addElse(ControlType& current, const ExpressionList& values)
</del><ins>+auto Validate::addElse(ControlType& current, const ExpressionList& values) -> Result
</ins><span class="cx"> {
</span><del>- if (!unify(values, current)) {
- ASSERT(errorMessage());
- return false;
- }
-
</del><ins>+ WASM_FAIL_IF_HELPER_FAILS(unify(values, current));
</ins><span class="cx"> return addElseToUnreachable(current);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::addElseToUnreachable(ControlType& current)
</del><ins>+auto Validate::addElseToUnreachable(ControlType& current) -> Result
</ins><span class="cx"> {
</span><del>- if (current.type() != BlockType::If) {
- m_errorMessage = makeString("Attempting to add else block to something other than an if");
- return false;
- }
-
</del><ins>+ WASM_VALIDATOR_FAIL_IF(current.type() != BlockType::If, "else block isn't associated to an if");
</ins><span class="cx"> current = ControlData(BlockType::Block, current.signature());
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::addReturn(const ExpressionList& returnValues)
</del><ins>+auto Validate::addReturn(const ExpressionList& returnValues) -> Result
</ins><span class="cx"> {
</span><span class="cx"> if (m_returnType == Void)
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> ASSERT(returnValues.size() == 1);
</span><del>-
- if (m_returnType == returnValues[0])
- return true;
-
- m_errorMessage = makeString("Attempting to add return with type: ", toString(returnValues[0]), " but function expects return with type: ", toString(m_returnType));
- return false;
</del><ins>+ WASM_VALIDATOR_FAIL_IF(m_returnType != returnValues[0], "return type ", returnValues[0], " doesn't match function's return type ", m_returnType);
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::checkBranchTarget(ControlType& target, const ExpressionList& expressionStack)
</del><ins>+auto Validate::checkBranchTarget(ControlType& target, const ExpressionList& expressionStack) -> Result
</ins><span class="cx"> {
</span><span class="cx"> if (target.type() == BlockType::Loop)
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx">
</span><span class="cx"> if (target.signature() == Void)
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx">
</span><del>- if (!expressionStack.size()) {
- m_errorMessage = makeString("Attempting to branch to block with expected type: ", toString(target.signature()), " but the stack was empty");
- return false;
- }
</del><ins>+ WASM_VALIDATOR_FAIL_IF(expressionStack.isEmpty(), "branch to block on empty expression stack");
+ WASM_VALIDATOR_FAIL_IF(target.signature() != expressionStack.last(), "branch's stack type doesn't match block's type");
</ins><span class="cx">
</span><del>- if (target.signature() == expressionStack.last())
- return true;
-
- m_errorMessage = makeString("Attempting to branch to block with expected type: ", toString(target.signature()), " but stack has type: ", toString(target.signature()));
- return false;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::addBranch(ControlType& target, ExpressionType condition, const ExpressionList& stack)
</del><ins>+auto Validate::addBranch(ControlType& target, ExpressionType condition, const ExpressionList& stack) -> Result
</ins><span class="cx"> {
</span><span class="cx"> // Void means this is an unconditional branch.
</span><del>- if (condition != Void && condition != I32) {
- m_errorMessage = makeString("Attempting to add a conditional branch with condition type: ", toString(condition), " but expected i32.");
- return false;
- }
-
</del><ins>+ WASM_VALIDATOR_FAIL_IF(condition != Void && condition != I32, "conditional branch with non-i32 condition ", condition);
</ins><span class="cx"> return checkBranchTarget(target, stack);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack)
</del><ins>+auto Validate::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack) -> Result
</ins><span class="cx"> {
</span><del>- if (condition != I32) {
- m_errorMessage = makeString("Attempting to add a br_table with condition type: ", toString(condition), " but expected i32.");
- return false;
- }
</del><ins>+ WASM_VALIDATOR_FAIL_IF(condition != I32, "br_table with non-i32 condition ", condition);
</ins><span class="cx">
</span><del>- for (auto target : targets) {
- if (defaultTarget.signature() != target->signature()) {
- m_errorMessage = makeString("Attempting to add a br_table with different expected types. Default target has type: ", toString(defaultTarget.signature()), " but case has type: ", toString(target->signature()));
- return false;
- }
- }
</del><ins>+ for (auto target : targets)
+ WASM_VALIDATOR_FAIL_IF(defaultTarget.signature() != target->signature(), "br_table target type mismatch");
</ins><span class="cx">
</span><span class="cx"> return checkBranchTarget(defaultTarget, expressionStack);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::endBlock(ControlEntry& entry, ExpressionList& stack)
</del><ins>+auto Validate::endBlock(ControlEntry& entry, ExpressionList& stack) -> Result
</ins><span class="cx"> {
</span><span class="cx"> ControlData& block = entry.controlData;
</span><span class="cx"> if (block.signature() == Void)
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx">
</span><del>- if (!stack.size()) {
- m_errorMessage = makeString("Block fallthough expected type: ", toString(block.signature()), " but the stack was empty");
- return false;
- }
</del><ins>+ WASM_VALIDATOR_FAIL_IF(stack.isEmpty(), "typed block falls through on empty stack");
+ WASM_VALIDATOR_FAIL_IF(block.signature() != stack.last(), "block fallthrough doesn't match its declared type");
</ins><span class="cx">
</span><del>- if (block.signature() == stack.last()) {
- entry.enclosedExpressionStack.append(block.signature());
- return true;
- }
-
- m_errorMessage = makeString("Block fallthrough has expected type: ", toString(block.signature()), " but produced type: ", toString(block.signature()));
- return false;
</del><ins>+ entry.enclosedExpressionStack.append(block.signature());
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::addEndToUnreachable(ControlEntry& entry)
</del><ins>+auto Validate::addEndToUnreachable(ControlEntry& entry) -> Result
</ins><span class="cx"> {
</span><span class="cx"> if (entry.controlData.signature() != Void)
</span><span class="cx"> entry.enclosedExpressionStack.append(entry.controlData.signature());
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::addCall(unsigned, const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result)
</del><ins>+auto Validate::addCall(unsigned, const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
</ins><span class="cx"> {
</span><del>- if (signature->arguments.size() != args.size()) {
- StringBuilder builder;
- builder.append("Arity mismatch in call, expected: ");
- builder.appendNumber(signature->arguments.size());
- builder.append(" but got: ");
- builder.appendNumber(args.size());
- m_errorMessage = builder.toString();
- return false;
- }
</del><ins>+ WASM_VALIDATOR_FAIL_IF(signature->arguments.size() != args.size(), "arity mismatch in call, got ", args.size(), " arguments, expected ", signature->arguments.size());
</ins><span class="cx">
</span><del>- for (unsigned i = 0; i < args.size(); ++i) {
- if (args[i] != signature->arguments[i]) {
- m_errorMessage = makeString("Expected argument type: ", toString(signature->arguments[i]), " does not match passed argument type: ", toString(args[i]));
- return false;
- }
- }
</del><ins>+ for (unsigned i = 0; i < args.size(); ++i)
+ WASM_VALIDATOR_FAIL_IF(args[i] != signature->arguments[i], "argument type mismatch in call, got ", args[i], ", expected ", signature->arguments[i]);
</ins><span class="cx">
</span><span class="cx"> result = signature->returnType;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::addCallIndirect(const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result)
</del><ins>+auto Validate::addCallIndirect(const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
</ins><span class="cx"> {
</span><span class="cx"> const auto argumentCount = signature->arguments.size();
</span><del>- if (argumentCount != args.size() - 1) {
- StringBuilder builder;
- builder.append("Arity mismatch in call_indirect, expected: ");
- builder.appendNumber(signature->arguments.size());
- builder.append(" but got: ");
- builder.appendNumber(args.size());
- m_errorMessage = builder.toString();
- return false;
- }
</del><ins>+ WASM_VALIDATOR_FAIL_IF(argumentCount != args.size() - 1, "arity mismatch in call_indirect, got ", args.size() - 1, " arguments, expected ", argumentCount);
</ins><span class="cx">
</span><del>- for (unsigned i = 0; i < argumentCount; ++i) {
- if (args[i] != signature->arguments[i]) {
- m_errorMessage = makeString("Expected argument type: ", toString(signature->arguments[i]), " does not match passed argument type: ", toString(args[i]));
- return false;
- }
- }
</del><ins>+ for (unsigned i = 0; i < argumentCount; ++i)
+ WASM_VALIDATOR_FAIL_IF(args[i] != signature->arguments[i], "argument type mismatch in call_indirect, got ", args[i], ", expected ", signature->arguments[i]);
</ins><span class="cx">
</span><del>- if (args.last() != I32) {
- m_errorMessage = makeString("Expected call_indirect target index to have type: i32 but got type: ", toString(args.last()));
- return false;
- }
-
</del><ins>+ WASM_VALIDATOR_FAIL_IF(args.last() != I32, "non-i32 call_indirect index ", args.last());
+
</ins><span class="cx"> result = signature->returnType;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::unify(const ExpressionList& values, const ControlType& block)
</del><ins>+auto Validate::unify(const ExpressionList& values, const ControlType& block) -> Result
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(values.size() <= 1);
</span><span class="cx"> if (block.signature() == Void)
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx">
</span><del>- if (!values.size()) {
- m_errorMessage = makeString("Block has non-void signature but has no stack entries on exit");
- return false;
- }
</del><ins>+ WASM_VALIDATOR_FAIL_IF(values.isEmpty(), "non-void block ends with an empty stack");
+ WASM_VALIDATOR_FAIL_IF(values[0] != block.signature(), "control flow returns with unexpected type");
</ins><span class="cx">
</span><del>- if (values[0] == block.signature())
- return true;
-
- m_errorMessage = makeString("Expected control flow to return value with type: ", toString(block.signature()), " but got value with type: ", toString(values[0]));
- return false;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void Validate::dump(const Vector<ControlEntry>&, const ExpressionList&)
</span><span class="lines">@@ -439,21 +347,12 @@
</span><span class="cx"> // Think of this as penance for the sin of bad error messages.
</span><span class="cx"> }
</span><span class="cx">
</span><del>-String validateFunction(const uint8_t* source, size_t length, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& module)
</del><ins>+Expected<void, String> validateFunction(const uint8_t* source, size_t length, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& module)
</ins><span class="cx"> {
</span><span class="cx"> Validate context(signature->returnType, module);
</span><span class="cx"> FunctionParser<Validate> validator(context, source, length, signature, functionIndexSpace, module);
</span><del>-
- if (!validator.parse()) {
- // FIXME: add better location information here. see: https://bugs.webkit.org/show_bug.cgi?id=164288
- // FIXME: We should never not have an error message if we return false.
- // see: https://bugs.webkit.org/show_bug.cgi?id=164354
- if (context.errorMessage().isNull())
- return "Unknown error";
- return context.errorMessage();
- }
-
- return String();
</del><ins>+ WASM_FAIL_IF_HELPER_FAILS(validator.parse());
+ return { };
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> } } // namespace JSC::Wasm
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmValidateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmValidate.h (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmValidate.h        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/WasmValidate.h        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -28,10 +28,11 @@
</span><span class="cx"> #if ENABLE(WEBASSEMBLY)
</span><span class="cx">
</span><span class="cx"> #include "WasmFormat.h"
</span><ins>+#include <wtf/Expected.h>
</ins><span class="cx">
</span><span class="cx"> namespace JSC { namespace Wasm {
</span><span class="cx">
</span><del>-String validateFunction(const uint8_t*, size_t, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);
</del><ins>+Expected<void, String> validateFunction(const uint8_t*, size_t, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);
</ins><span class="cx">
</span><span class="cx"> } } // namespace JSC::Wasm
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmgenerateWasmB3IRGeneratorInlinesHeaderpy"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/generateWasmB3IRGeneratorInlinesHeader.py (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/generateWasmB3IRGeneratorInlinesHeader.py        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/generateWasmB3IRGeneratorInlinesHeader.py        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -189,10 +189,10 @@
</span><span class="cx"> args = ["ExpressionType arg" + str(param) for param in range(len(opcode["parameter"]))]
</span><span class="cx"> args.append("ExpressionType& result")
</span><span class="cx"> return """
</span><del>-template<> bool B3IRGenerator::addOp<OpType::""" + wasm.toCpp(op["name"]) + ">(" + ", ".join(args) + """)
</del><ins>+template<> auto B3IRGenerator::addOp<OpType::""" + wasm.toCpp(op["name"]) + ">(" + ", ".join(args) + """) -> PartialResult
</ins><span class="cx"> {
</span><span class="cx"> """ + generateB3Code(opcode, b3op) + """;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx"> """
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmgenerateWasmOpsHeaderpy"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -151,7 +151,7 @@
</span><span class="cx"> #undef CREATE_CASE
</span><span class="cx">
</span><span class="cx"> #define CREATE_CASE(name, id, b3type, inc) case name: return #name;
</span><del>-inline const char* toString(Type type)
</del><ins>+inline const char* makeString(Type type)
</ins><span class="cx"> {
</span><span class="cx"> switch (type) {
</span><span class="cx"> FOR_EACH_WASM_TYPE(CREATE_CASE)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmgenerateWasmValidateInlinesHeaderpy"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/generateWasmValidateInlinesHeader.py (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/generateWasmValidateInlinesHeader.py        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/generateWasmValidateInlinesHeader.py        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -60,15 +60,13 @@
</span><span class="cx"> def unaryMacro(name):
</span><span class="cx"> op = opcodes[name]
</span><span class="cx"> return """
</span><del>-template<> bool Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType value, ExpressionType& result)
</del><ins>+template<> auto Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType value, ExpressionType& result) -> Result
</ins><span class="cx"> {
</span><del>- if (value != """ + cppType(op["parameter"][0]) + """) {
- m_errorMessage = makeString(\"""" + name + """ expects the value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(value));
- return false;
- }
</del><ins>+ if (UNLIKELY(value != """ + cppType(op["parameter"][0]) + """))
+ return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ value type mismatch");
</ins><span class="cx">
</span><span class="cx"> result = """ + cppType(op["return"][0]) + """;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx"> """
</span><span class="cx">
</span><span class="lines">@@ -76,20 +74,16 @@
</span><span class="cx"> def binaryMacro(name):
</span><span class="cx"> op = opcodes[name]
</span><span class="cx"> return """
</span><del>-template<> bool Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType left, ExpressionType right, ExpressionType& result)
</del><ins>+template<> auto Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType left, ExpressionType right, ExpressionType& result) -> Result
</ins><span class="cx"> {
</span><del>- if (left != """ + cppType(op["parameter"][0]) + """) {
- m_errorMessage = makeString(\"""" + name + """ expects the left value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(left));
- return false;
- }
</del><ins>+ if (UNLIKELY(left != """ + cppType(op["parameter"][0]) + """))
+ return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ left value type mismatch");
</ins><span class="cx">
</span><del>- if (right != """ + cppType(op["parameter"][1]) + """) {
- m_errorMessage = makeString(\"""" + name + """ expects the right value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(right));
- return false;
- }
</del><ins>+ if (UNLIKELY(right != """ + cppType(op["parameter"][1]) + """))
+ return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ right value type mismatch");
</ins><span class="cx">
</span><span class="cx"> result = """ + cppType(op["return"][0]) + """;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }
</span><span class="cx"> """
</span><span class="cx">
</span><span class="lines">@@ -97,13 +91,11 @@
</span><span class="cx"> op = opcodes[name]
</span><span class="cx"> return """
</span><span class="cx"> case LoadOpType::""" + toCpp(name) + """: {
</span><del>- if (pointer != """ + cppType(op["parameter"][0]) + """) {
- m_errorMessage = makeString(\"""" + name + """ expects the pointer to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(pointer));
- return false;
- }
</del><ins>+ if (UNLIKELY(pointer != """ + cppType(op["parameter"][0]) + """))
+ return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ pointer type mismatch");
</ins><span class="cx">
</span><span class="cx"> result = """ + cppType(op["return"][0]) + """;
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }"""
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -111,17 +103,13 @@
</span><span class="cx"> op = opcodes[name]
</span><span class="cx"> return """
</span><span class="cx"> case StoreOpType::""" + toCpp(name) + """: {
</span><del>- if (pointer != """ + cppType(op["parameter"][0]) + """) {
- m_errorMessage = makeString(\"""" + name + """ expects the pointer to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(pointer));
- return false;
- }
</del><ins>+ if (UNLIKELY(pointer != """ + cppType(op["parameter"][0]) + """))
+ return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ pointer type mismatch");
</ins><span class="cx">
</span><del>- if (value != """ + cppType(op["parameter"][1]) + """) {
- m_errorMessage = makeString(\"""" + name + """ expects the value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(value));
- return false;
- }
</del><ins>+ if (UNLIKELY(value != """ + cppType(op["parameter"][1]) + """))
+ return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ value type mismatch");
</ins><span class="cx">
</span><del>- return true;
</del><ins>+ return { };
</ins><span class="cx"> }"""
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -141,10 +129,10 @@
</span><span class="cx">
</span><span class="cx"> """ + unarySpecializations + binarySpecializations + """
</span><span class="cx">
</span><del>-bool Validate::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t)
</del><ins>+auto Validate::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t) -> Result
</ins><span class="cx"> {
</span><del>- if (!hasMemory())
- return false;
</del><ins>+ if (UNLIKELY(!hasMemory()))
+ return UnexpectedType<Result::ErrorType>("validation failed: load instruction without memory");
</ins><span class="cx">
</span><span class="cx"> switch (op) {
</span><span class="cx"> """ + loadCases + """
</span><span class="lines">@@ -151,10 +139,10 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool Validate::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t)
</del><ins>+auto Validate::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t) -> Result
</ins><span class="cx"> {
</span><del>- if (!hasMemory())
- return false;
</del><ins>+ if (UNLIKELY(!hasMemory()))
+ return UnexpectedType<Result::ErrorType>("validation failed: store instruction without memory");
</ins><span class="cx">
</span><span class="cx"> switch (op) {
</span><span class="cx"> """ + storeCases + """
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyInstanceConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -106,7 +106,7 @@
</span><span class="cx"> RETURN_IF_EXCEPTION(throwScope, { });
</span><span class="cx">
</span><span class="cx"> switch (import.kind) {
</span><del>- case Wasm::External::Function: {
</del><ins>+ case Wasm::ExternalKind::Function: {
</ins><span class="cx"> // 4. If i is a function import:
</span><span class="cx"> // i. If IsCallable(v) is false, throw a TypeError.
</span><span class="cx"> if (!value.isFunction())
</span><span class="lines">@@ -129,7 +129,7 @@
</span><span class="cx"> // v. Append closure to imports.
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case Wasm::External::Table: {
</del><ins>+ case Wasm::ExternalKind::Table: {
</ins><span class="cx"> RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure.
</span><span class="cx"> // 7. Otherwise (i is a table import):
</span><span class="cx"> hasTableImport = true;
</span><span class="lines">@@ -160,7 +160,7 @@
</span><span class="cx"> instance->setTable(vm, table);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case Wasm::External::Memory: {
</del><ins>+ case Wasm::ExternalKind::Memory: {
</ins><span class="cx"> // 6. If i is a memory import:
</span><span class="cx"> RELEASE_ASSERT(!hasMemoryImport); // This should be guaranteed by a validation failure.
</span><span class="cx"> RELEASE_ASSERT(moduleInformation.memory);
</span><span class="lines">@@ -192,7 +192,7 @@
</span><span class="cx"> instance->setMemory(vm, memory);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case Wasm::External::Global: {
</del><ins>+ case Wasm::ExternalKind::Global: {
</ins><span class="cx"> // 5. If i is a global import:
</span><span class="cx"> // i. If i is not an immutable global, throw a TypeError.
</span><span class="cx"> ASSERT(moduleInformation.globals[import.kindIndex].mutability == Wasm::Global::Immutable);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyModuleRecordcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp (209879 => 209880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp        2016-12-15 23:12:31 UTC (rev 209879)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp        2016-12-15 23:42:19 UTC (rev 209880)
</span><span class="lines">@@ -105,7 +105,7 @@
</span><span class="cx"> for (const auto& exp : moduleInformation.exports) {
</span><span class="cx"> JSValue exportedValue;
</span><span class="cx"> switch (exp.kind) {
</span><del>- case Wasm::External::Function: {
</del><ins>+ case Wasm::ExternalKind::Function: {
</ins><span class="cx"> // 1. If e is a closure c:
</span><span class="cx"> // i. If there is an Exported Function Exotic Object func in funcs whose func.[[Closure]] equals c, then return func.
</span><span class="cx"> // ii. (Note: At most one wrapper is created for any closure, so func is unique, even if there are multiple occurrances in the list. Moreover, if the item was an import that is already an Exported Function Exotic Object, then the original function object will be found. For imports that are regular JS functions, a new wrapper will be created.)
</span><span class="lines">@@ -126,7 +126,7 @@
</span><span class="cx"> m_startFunction.set(vm, this, function);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case Wasm::External::Table: {
</del><ins>+ case Wasm::ExternalKind::Table: {
</ins><span class="cx"> // This should be guaranteed by module verification.
</span><span class="cx"> RELEASE_ASSERT(instance->table());
</span><span class="cx"> ASSERT(exp.kindIndex == 0);
</span><span class="lines">@@ -134,7 +134,7 @@
</span><span class="cx"> exportedValue = instance->table();
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case Wasm::External::Memory: {
</del><ins>+ case Wasm::ExternalKind::Memory: {
</ins><span class="cx"> // This should be guaranteed by module verification.
</span><span class="cx"> RELEASE_ASSERT(instance->memory());
</span><span class="cx"> ASSERT(exp.kindIndex == 0);
</span><span class="lines">@@ -142,7 +142,7 @@
</span><span class="cx"> exportedValue = instance->memory();
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- case Wasm::External::Global: {
</del><ins>+ case Wasm::ExternalKind::Global: {
</ins><span class="cx"> // Assert: the global is immutable by MVP validation constraint.
</span><span class="cx"> const Wasm::Global& global = moduleInformation.globals[exp.kindIndex];
</span><span class="cx"> ASSERT(global.mutability == Wasm::Global::Immutable);
</span></span></pre>
</div>
</div>
</body>
</html>