Changeset 209880 in webkit


Ignore:
Timestamp:
Dec 15, 2016 3:42:19 PM (7 years ago)
Author:
jfbastien@apple.com
Message:

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):

Location:
trunk
Files:
24 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r209874 r209880  
     12016-12-15  JF Bastien  <jfbastien@apple.com>
     2
     3        WebAssembly: improve compilation error messages
     4        https://bugs.webkit.org/show_bug.cgi?id=163919
     5
     6        Reviewed by Saam Barati.
     7
     8        Update error messages in these tests.
     9        Use the assert.throws facility in many of them which weren't already.
     10
     11        * wasm/js-api/element.js:
     12        (assert.throws.new.WebAssembly.Module.builder.WebAssembly):
     13        (assert.throws):
     14        * wasm/js-api/global-error.js:
     15        (assert.throws.new.WebAssembly.Module.bin):
     16        (assert.throws):
     17        (new.Number):
     18        * wasm/js-api/table.js:
     19        (assert.throws.new.WebAssembly.Module.builder.WebAssembly):
     20        (assert.throws):
     21        (assertBadTableImport):
     22        * wasm/js-api/test_Data.js:
     23        (DataSectionWithoutMemory):
     24        * wasm/js-api/test_Start.js:
     25        (InvalidStartFunctionIndex):
     26        * wasm/js-api/test_basic_api.js:
     27        (const.c.in.constructorProperties.switch):
     28
    1292016-12-15  JF Bastien  <jfbastien@apple.com>
    230
  • trunk/JSTests/wasm/js-api/element.js

    r209785 r209880  
    11import Builder from '../Builder.js';
    22import * as assert from '../assert.js';
    3 
    4 function assertBadBinary(builder, str) {
    5     const bin = builder.WebAssembly().get();
    6     let threw = false;
    7     try {
    8         new WebAssembly.Module(bin);
    9     } catch(e) {
    10         threw = true;
    11         assert.truthy(e.toString().indexOf(str) !== -1);
    12         assert.truthy(e instanceof WebAssembly.CompileError);
    13     }
    14     assert.truthy(threw);
    15 }
    16 
    17 const badElementSectionString = "couldn't parse section Element";
    183
    194{
     
    3419        .End();
    3520
    36     assertBadBinary(builder, badElementSectionString);
     21    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())')");
    3722}
    3823
     
    5742        .End();
    5843
    59     assertBadBinary(builder, badElementSectionString);
     44    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())')");
    6045}
    6146
     
    8065        .End();
    8166
    82     assertBadBinary(builder, badElementSectionString);
     67    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())')");
    8368}
    8469
     
    10388        .End();
    10489
    105     assertBadBinary(builder, badElementSectionString);
     90    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())')");
    10691}
    10792
     
    126111        .End();
    127112
    128     assertBadBinary(builder, badElementSectionString);
     113    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())')");
    129114}
    130115
  • trunk/JSTests/wasm/js-api/global-error.js

    r209830 r209880  
    2424    bin.trim();
    2525
    26     let passed = false;
    27     try {
    28         const module = new WebAssembly.Module(bin.get());
    29     } catch (e) {
    30         if (e.message === "couldn't parse section Global: Global declarations (evaluating 'new WebAssembly.Module(bin.get())')")
    31             passed = true;
    32     }
    33     assert.truthy(passed);
     26    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())')");
    3427}
    3528
     
    6053    bin.trim();
    6154
    62     let passed = false;
    63     try {
    64         const module = new WebAssembly.Module(bin.get());
    65     } catch (e) {
    66         if (e.message === "couldn't parse section Import: Import declarations (evaluating 'new WebAssembly.Module(bin.get())')")
    67             passed = true;
    68     }
    69     assert.truthy(passed);
     55    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())')");
    7056}
    7157
     
    9278    bin.trim();
    9379
    94     let passed = false;
    95     try {
    96         const module = new WebAssembly.Module(bin.get());
    97     } catch (e) {
    98         if (e.message === "couldn't parse section Export: Exports (evaluating 'new WebAssembly.Module(bin.get())')")
    99             passed = true;
    100     }
    101     assert.truthy(passed);
     80    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())')");
    10281}
    10382
     
    125104    bin.trim();
    126105
    127     let passed = false;
    128     try {
    129         const module = new WebAssembly.Module(bin.get());
    130     } catch (e) {
    131         if (e.message === "Attempt to store to immutable global. (evaluating 'new WebAssembly.Module(bin.get())')")
    132             passed = true;
    133     }
    134     assert.truthy(passed);
     106    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())')");
    135107}
    136108
     
    159131    bin.trim();
    160132
    161     let passed = false;
    162     try {
    163         const module = new WebAssembly.Module(bin.get());
    164     } catch (e) {
    165         if (e.message === "Attempt to use unknown global. (evaluating 'new WebAssembly.Module(bin.get())')")
    166             passed = true;
    167     }
    168     assert.truthy(passed);
     133    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())')");
    169134}
    170135
     
    192157    bin.trim();
    193158
    194     let passed = false;
    195     try {
    196         const module = new WebAssembly.Module(bin.get());
    197     } catch (e) {
    198         if (e.message === "Attempt to set global with type: F32 with a variable of type: I32 (evaluating 'new WebAssembly.Module(bin.get())')")
    199             passed = true;
    200     }
    201     assert.truthy(passed);
     159    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())')");
    202160}
    203161
     
    227185    bin.trim();
    228186
    229     let passed = false;
    230187    const module = new WebAssembly.Module(bin.get());
    231     try {
    232         new WebAssembly.Instance(module, { imp: { global: imp } });
    233     } catch (e) {
    234         if (e.message === "imported global must be a number (evaluating 'new WebAssembly.Instance(module, { imp: { global: imp } })')")
    235             passed = true;
    236     }
    237     assert.truthy(passed);
     188    assert.throws(() => new WebAssembly.Instance(module, { imp: { global: imp } }), TypeError, "imported global must be a number (evaluating 'new WebAssembly.Instance(module, { imp: { global: imp } })')");
    238189}
  • trunk/JSTests/wasm/js-api/table.js

    r209850 r209880  
    22import * as assert from '../assert.js';
    33
    4 const badTableString = "couldn't parse section Table: Indirect function table and other tables (evaluating 'new WebAssembly.Module(bin)')";
    5 const badImportString = "couldn't parse section Import: Import declarations (evaluating 'new WebAssembly.Module(bin)')";
    6 const badExportString = "couldn't parse section Export: Exports (evaluating 'new WebAssembly.Module(bin)')";
    7 
    8 function assertBadBinary(builder, str) {
    9     const bin = builder.WebAssembly().get();
    10     assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, str);
    11 }
    12 
    134{
    145    const builder = new Builder()
     
    2314        .Code()
    2415        .End();
    25     assertBadBinary(builder, badTableString);
    26 }
    27 
    28 {
    29     const builder = new Builder()
    30         .Type().End()
    31         .Function().End()
    32         .Table()
    33             .Table({initial: 20, maximum: 30, element: "anyfunc"})
    34             .Table({initial: 20, maximum: 30, element: "anyfunc"})
    35         .End()
    36         .Code()
    37         .End();
    38     assertBadBinary(builder, badTableString);
     16    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())')");
     17}
     18
     19{
     20    const builder = new Builder()
     21        .Type().End()
     22        .Function().End()
     23        .Table()
     24            .Table({initial: 20, maximum: 30, element: "anyfunc"})
     25            .Table({initial: 20, maximum: 30, element: "anyfunc"})
     26        .End()
     27        .Code()
     28        .End();
     29    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())')");
    3930}
    4031
     
    5243            .End()
    5344        .End();
    54     assertBadBinary(builder, "call_indirect is only valid when a table is defined or imported (evaluating 'new WebAssembly.Module(bin)')");
     45    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())')");
    5546}
    5647
     
    7162            .End()
    7263        .End();
    73     assertBadBinary(builder, "call_indirect 'reserved' varuint1 must be 0x0 (evaluating 'new WebAssembly.Module(bin)')");
     64    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())')");
    7465}
    7566
     
    8475        .Code()
    8576        .End();
    86     assertBadBinary(builder, badExportString);
     77    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())')");
    8778}
    8879
     
    10091        .Code()
    10192        .End();
    102     assertBadBinary(builder, badExportString);
    103 }
    104 
    105 function assertBadTable(tableDescription) {
     93    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())')");
     94}
     95
     96function assertBadTable(tableDescription, message) {
    10697    const builder = new Builder()
    10798        .Type().End()
     
    112103        .Code()
    113104        .End();
    114     assertBadBinary(builder, badTableString);
    115 }
    116 
    117 function assertBadTableImport(tableDescription) {
     105    assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, message);
     106}
     107
     108function assertBadTableImport(tableDescription, message) {
    118109    const builder = new Builder()
    119110        .Type().End()
     
    124115        .Code()
    125116        .End();
    126     assertBadBinary(builder, badImportString);
     117    assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, message);
    127118}
    128119
    129120{
    130121    let badDescriptions = [
    131         {initial: 10, element: "i32"},
    132         {initial: 10, element: "f32"},
    133         {initial: 10, element: "f64"},
    134         {initial: 10, element: "i64"},
    135         {initial: 10, maximum: 20, element: "i32"},
    136         {initial: 10, maximum: 20, element: "f32"},
    137         {initial: 10, maximum: 20, element: "f64"},
    138         {initial: 10, maximum: 20, element: "i64"},
    139 
    140         {initial: 10, maximum: 9, element: "anyfunc"},
    141         {initial: 1, maximum: 0, element: "anyfunc"},
    142         {initial: 2**32 - 1, maximum: 2**32 - 2, element: "anyfunc"},
    143         {initial: 2**31, element: "anyfunc"},
     122        [{initial: 10, element: "i32"},
     123         "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
     124         "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
     125        [{initial: 10, element: "f32"},
     126         "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
     127         "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
     128        [{initial: 10, element: "f64"},
     129         "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
     130         "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
     131        [{initial: 10, element: "i64"},
     132         "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
     133         "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
     134        [{initial: 10, maximum: 20, element: "i32"},
     135         "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
     136         "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
     137        [{initial: 10, maximum: 20, element: "f32"},
     138         "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
     139         "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
     140        [{initial: 10, maximum: 20, element: "f64"},
     141         "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
     142         "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
     143        [{initial: 10, maximum: 20, element: "i64"},
     144         "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
     145         "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
     146
     147        [{initial: 10, maximum: 9, element: "anyfunc"},
     148         "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())')",
     149         "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())')"],
     150        [{initial: 1, maximum: 0, element: "anyfunc"},
     151         "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())')",
     152         "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())')"],
     153        [{initial: 2**32 - 1, maximum: 2**32 - 2, element: "anyfunc"},
     154         "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())')",
     155         "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())')"],
     156        [{initial: 2**31, element: "anyfunc"},
     157         "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())')",
     158         "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())')"],
    144159    ];
    145160
    146161    for (const d of badDescriptions) {
    147         assertBadTable(d);
    148         assertBadTableImport(d);
     162        assertBadTable(d[0], d[1]);
     163        assertBadTableImport(d[0], d[2]);
    149164    }
    150165}
     
    160175        .Code()
    161176        .End();
    162     assertBadBinary(builder, badImportString);
     177    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())')");
    163178}
    164179
     
    174189            .Code()
    175190            .End();
    176 
    177         let threw = false;
    178191        const module = new WebAssembly.Module(builder.WebAssembly().get());
    179         try {
    180             new WebAssembly.Instance(module, {imp: {table}});
    181         } catch (e) {
    182             assert.eq(e.toString(), message);
    183             threw = true;
    184         }
    185         assert.truthy(threw);
     192        assert.throws(() => new WebAssembly.Instance(module, {imp: {table}}), TypeError, message);
    186193    }
    187194
    188195    const badTables = [
    189         [{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"],
    190         [{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'"],
    191         [{initial: 100, element:"anyfunc"}, new WebAssembly.Table({initial:10, element: "anyfunc"}), "TypeError: Table import provided an 'initial' that is too small"],
    192         [{initial: 10, element:"anyfunc"}, new WebAssembly.Table({initial:9, element: "anyfunc"}), "TypeError: Table import provided an 'initial' that is too small"],
     196        [{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"],
     197        [{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'"],
     198        [{initial: 100, element:"anyfunc"}, new WebAssembly.Table({initial:10, element: "anyfunc"}), "Table import provided an 'initial' that is too small"],
     199        [{initial: 10, element:"anyfunc"}, new WebAssembly.Table({initial:9, element: "anyfunc"}), "Table import provided an 'initial' that is too small"],
    193200    ];
    194201    for (const [d, t, m] of badTables) {
  • trunk/JSTests/wasm/js-api/test_Data.js

    r209874 r209880  
    5353        .End();
    5454    const bin = builder.WebAssembly().get();
    55     assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `couldn't parse section Data: Data segments (evaluating 'new WebAssembly.Module(bin)')`);
     55    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)')`);
    5656})();
    5757
     
    6363        .End();
    6464    const bin = builder.WebAssembly().get();
    65     assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `couldn't parse section Data: Data segments (evaluating 'new WebAssembly.Module(bin)')`);
     65    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)')`);
    6666})();
    6767
  • trunk/JSTests/wasm/js-api/test_Start.js

    r209642 r209880  
    3232        .Code().End();
    3333    const bin = b.WebAssembly().get();
    34     assert.throws(() => new WebAssembly.Module(bin), Error, `couldn't parse section Start: Start function declaration (evaluating 'new WebAssembly.Module(bin)')`);
     34    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)')`);
    3535})();
  • trunk/JSTests/wasm/js-api/test_basic_api.js

    r209771 r209880  
    5656        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()])
    5757            // FIXME the following should be WebAssembly.CompileError. https://bugs.webkit.org/show_bug.cgi?id=163768
    58             assert.throws(() => new WebAssembly[c](buffer), Error, `Module is 0 bytes, expected at least 8 bytes (evaluating 'new WebAssembly[c](buffer)')`);
     58            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)')`);
    5959        assert.instanceof(new WebAssembly[c](emptyModuleArray), WebAssembly.Module);
    6060        // FIXME test neutered TypedArray and TypedArrayView. https://bugs.webkit.org/show_bug.cgi?id=163899
  • trunk/Source/JavaScriptCore/ChangeLog

    r209874 r209880  
     12016-12-15  JF Bastien  <jfbastien@apple.com>
     2
     3        WebAssembly: improve compilation error messages
     4        https://bugs.webkit.org/show_bug.cgi?id=163919
     5
     6        Reviewed by Saam Barati.
     7
     8        The error handling messages were underwhelming because most
     9        locations merely returned `false` on failure. This patch uses
     10        std::expected to denote that failure isn't expected. Doing this
     11        makes it almost impossible to mess up the code: either a function
     12        returns a result (or a partial result for internal helpers) or an
     13        error. We're not synchronizing the error string with the m_failed
     14        bool anymore, and the caller will abort if they try to get a
     15        result but the outcome was an error.
     16
     17        This also shortens the code significantly using macros, while also
     18        judiciously preventing inlining of error handling code and biasing
     19        towards success using UNLIKELY. This means that the generated code
     20        should be more efficient (no string formatting on success, and
     21        regalloc can avoid these unlikely paths).
     22
     23        The patch adds a few missing checks as well, especially related to
     24        count limits and memory allocation failure.
     25
     26        As a follow-up I'd like to improve WTF::makeString further, so it
     27        does coercions to string and understands ADL as I did in this
     28        patch.
     29
     30        * wasm/WasmB3IRGenerator.cpp:
     31        (JSC::Wasm::B3IRGenerator::fail):
     32        (JSC::Wasm::parseAndCompile):
     33        * wasm/WasmB3IRGenerator.h:
     34        * wasm/WasmFormat.h:
     35        (JSC::Wasm::isValidExternalKind):
     36        (JSC::Wasm::makeString):
     37        * wasm/WasmFunctionParser.h:
     38        * wasm/WasmModuleParser.cpp:
     39        * wasm/WasmModuleParser.h:
     40        * wasm/WasmParser.h:
     41        (JSC::Wasm::FailureHelper::makeString):
     42        (JSC::Wasm::Parser::fail):
     43        (JSC::Wasm::Parser<SuccessType>::Parser):
     44        (JSC::Wasm::Parser<SuccessType>::consumeCharacter):
     45        (JSC::Wasm::Parser<SuccessType>::consumeString):
     46        (JSC::Wasm::Parser<SuccessType>::consumeUTF8String):
     47        (JSC::Wasm::Parser<SuccessType>::parseVarUInt32):
     48        (JSC::Wasm::Parser<SuccessType>::parseVarUInt64):
     49        (JSC::Wasm::Parser<SuccessType>::parseVarInt32):
     50        (JSC::Wasm::Parser<SuccessType>::parseVarInt64):
     51        (JSC::Wasm::Parser<SuccessType>::parseUInt32):
     52        (JSC::Wasm::Parser<SuccessType>::parseUInt64):
     53        (JSC::Wasm::Parser<SuccessType>::parseUInt8):
     54        (JSC::Wasm::Parser<SuccessType>::parseInt7):
     55        (JSC::Wasm::Parser<SuccessType>::parseUInt7):
     56        (JSC::Wasm::Parser<SuccessType>::parseVarUInt1):
     57        (JSC::Wasm::Parser<SuccessType>::parseResultType):
     58        (JSC::Wasm::Parser<SuccessType>::parseValueType):
     59        (JSC::Wasm::Parser<SuccessType>::parseExternalKind):
     60        * wasm/WasmPlan.cpp:
     61        (JSC::Wasm::Plan::run):
     62        * wasm/WasmSections.h:
     63        (JSC::Wasm::isValidSection):
     64        (JSC::Wasm::validateOrder):
     65        (JSC::Wasm::makeString):
     66        * wasm/WasmValidate.cpp:
     67        (JSC::Wasm::Validate::fail):
     68        (JSC::Wasm::Validate::addUnreachable):
     69        (JSC::Wasm::validateFunction):
     70        * wasm/WasmValidate.h:
     71        * wasm/generateWasmB3IRGeneratorInlinesHeader.py:
     72        * wasm/generateWasmOpsHeader.py:
     73        * wasm/generateWasmValidateInlinesHeader.py:
     74        (loadMacro):
     75        (storeMacro):
     76        * wasm/js/WebAssemblyInstanceConstructor.cpp:
     77        (JSC::constructJSWebAssemblyInstance):
     78        * wasm/js/WebAssemblyModuleRecord.cpp:
     79        (JSC::WebAssemblyModuleRecord::link):
     80
    1812016-12-15  JF Bastien  <jfbastien@apple.com>
    282
  • trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

    r209850 r209880  
    138138    static constexpr ExpressionType emptyExpression = nullptr;
    139139
     140    typedef String ErrorType;
     141    typedef UnexpectedType<ErrorType> UnexpectedResult;
     142    typedef Expected<std::unique_ptr<WasmInternalFunction>, ErrorType> Result;
     143    typedef Expected<void, ErrorType> PartialResult;
     144    template <typename ...Args>
     145    NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const
     146    {
     147        using namespace FailureHelper; // See ADL comment in WasmParser.h.
     148        return UnexpectedResult(makeString(ASCIILiteral("WebAssembly.Module failed compiling: "), makeString(args)...));
     149    }
     150#define WASM_COMPILE_FAIL_IF(condition, ...) do { \
     151        if (UNLIKELY(condition))                  \
     152            return fail(__VA_ARGS__);             \
     153    } while (0)
     154
    140155    B3IRGenerator(VM&, const ModuleInformation&, Procedure&, WasmInternalFunction*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&);
    141156
    142     bool WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
    143     bool WARN_UNUSED_RETURN addLocal(Type, uint32_t);
     157    PartialResult WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
     158    PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t);
    144159    ExpressionType addConstant(Type, uint64_t);
    145160
    146161    // Locals
    147     bool WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
    148     bool WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
     162    PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
     163    PartialResult WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
    149164
    150165    // Globals
    151     bool WARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result);
    152     bool WARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value);
     166    PartialResult WARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result);
     167    PartialResult WARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value);
    153168
    154169    // Memory
    155     bool WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
    156     bool WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
     170    PartialResult WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
     171    PartialResult WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
    157172
    158173    // Basic operators
    159174    template<OpType>
    160     bool WARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result);
     175    PartialResult WARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result);
    161176    template<OpType>
    162     bool WARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result);
    163     bool WARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result);
     177    PartialResult WARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result);
     178    PartialResult WARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result);
    164179
    165180    // Control flow
    166181    ControlData WARN_UNUSED_RETURN addBlock(Type signature);
    167182    ControlData WARN_UNUSED_RETURN addLoop(Type signature);
    168     bool WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);
    169     bool WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);
    170     bool WARN_UNUSED_RETURN addElseToUnreachable(ControlData&);
    171 
    172     bool WARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues);
    173     bool WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& returnValues);
    174     bool WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTargets, const ExpressionList& expressionStack);
    175     bool WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);
    176     bool WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);
     183    PartialResult WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);
     184    PartialResult WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);
     185    PartialResult WARN_UNUSED_RETURN addElseToUnreachable(ControlData&);
     186
     187    PartialResult WARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues);
     188    PartialResult WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& returnValues);
     189    PartialResult WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTargets, const ExpressionList& expressionStack);
     190    PartialResult WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);
     191    PartialResult WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);
    177192
    178193    // Calls
    179     bool WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature*, Vector<ExpressionType>& args, ExpressionType& result);
    180     bool WARN_UNUSED_RETURN addCallIndirect(const Signature*, Vector<ExpressionType>& args, ExpressionType& result);
    181     void addUnreachable();
     194    PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature*, Vector<ExpressionType>& args, ExpressionType& result);
     195    PartialResult WARN_UNUSED_RETURN addCallIndirect(const Signature*, Vector<ExpressionType>& args, ExpressionType& result);
     196    PartialResult WARN_UNUSED_RETURN addUnreachable();
    182197
    183198    void dump(const Vector<ControlEntry>& controlStack, const ExpressionList& expressionStack);
    184 
    185     void setErrorMessage(String&&) { UNREACHABLE_FOR_PLATFORM(); }
    186199
    187200private:
     
    292305}
    293306
    294 bool B3IRGenerator::addLocal(Type type, uint32_t count)
    295 {
    296     if (!m_locals.tryReserveCapacity(m_locals.size() + count))
    297         return false;
     307auto B3IRGenerator::addLocal(Type type, uint32_t count) -> PartialResult
     308{
     309    WASM_COMPILE_FAIL_IF(!m_locals.tryReserveCapacity(m_locals.size() + count), "can't allocate memory for ", m_locals.size() + count, " locals");
    298310
    299311    for (uint32_t i = 0; i < count; ++i) {
     
    302314        m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), local, zeroForType(type));
    303315    }
    304     return true;
    305 }
    306 
    307 bool B3IRGenerator::addArguments(const Vector<Type>& types)
     316    return { };
     317}
     318
     319auto B3IRGenerator::addArguments(const Vector<Type>& types) -> PartialResult
    308320{
    309321    ASSERT(!m_locals.size());
    310     if (!m_locals.tryReserveCapacity(types.size()))
    311         return false;
     322    WASM_COMPILE_FAIL_IF(!m_locals.tryReserveCapacity(types.size()), "can't allocate memory for ", types.size(), " arguments");
    312323
    313324    m_locals.grow(types.size());
     
    318329            m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), argumentVariable, argument);
    319330        });
    320     return true;
    321 }
    322 
    323 bool B3IRGenerator::getLocal(uint32_t index, ExpressionType& result)
     331    return { };
     332}
     333
     334auto B3IRGenerator::getLocal(uint32_t index, ExpressionType& result) -> PartialResult
    324335{
    325336    ASSERT(m_locals[index]);
    326337    result = m_currentBlock->appendNew<VariableValue>(m_proc, B3::Get, Origin(), m_locals[index]);
    327     return true;
    328 }
    329 
    330 void B3IRGenerator::addUnreachable()
     338    return { };
     339}
     340
     341auto B3IRGenerator::addUnreachable() -> PartialResult
    331342{
    332343    B3::PatchpointValue* unreachable = m_currentBlock->appendNew<B3::PatchpointValue>(m_proc, B3::Void, Origin());
     
    335346    });
    336347    unreachable->effects.terminal = true;
    337 }
    338 
    339 bool B3IRGenerator::setLocal(uint32_t index, ExpressionType value)
     348    return { };
     349}
     350
     351auto B3IRGenerator::setLocal(uint32_t index, ExpressionType value) -> PartialResult
    340352{
    341353    ASSERT(m_locals[index]);
    342354    m_currentBlock->appendNew<VariableValue>(m_proc, B3::Set, Origin(), m_locals[index], value);
    343     return true;
    344 }
    345 
    346 bool B3IRGenerator::getGlobal(uint32_t index, ExpressionType& result)
     355    return { };
     356}
     357
     358auto B3IRGenerator::getGlobal(uint32_t index, ExpressionType& result) -> PartialResult
    347359{
    348360    Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfGlobals());
    349361    result = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, toB3Type(m_info.globals[index].type), Origin(), globalsArray, index * sizeof(Register));
    350     return true;
    351 }
    352 
    353 bool B3IRGenerator::setGlobal(uint32_t index, ExpressionType value)
     362    return { };
     363}
     364
     365auto B3IRGenerator::setGlobal(uint32_t index, ExpressionType value) -> PartialResult
    354366{
    355367    ASSERT(toB3Type(m_info.globals[index].type) == value->type());
    356368    Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfGlobals());
    357369    m_currentBlock->appendNew<MemoryValue>(m_proc, Store, Origin(), value, globalsArray, index * sizeof(Register));
    358     return true;
     370    return { };
    359371}
    360372
     
    466478}
    467479
    468 bool B3IRGenerator::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t offset)
     480auto B3IRGenerator::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t offset) -> PartialResult
    469481{
    470482    ASSERT(pointer->type() == Int32);
    471483
    472484    result = emitLoadOp(op, Origin(), emitCheckAndPreparePointer(pointer, offset, sizeOfLoadOp(op)), offset);
    473     return true;
     485    return { };
    474486}
    475487
     
    528540}
    529541
    530 bool B3IRGenerator::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t offset)
     542auto B3IRGenerator::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t offset) -> PartialResult
    531543{
    532544    ASSERT(pointer->type() == Int32);
    533545
    534546    emitStoreOp(op, Origin(), emitCheckAndPreparePointer(pointer, offset, sizeOfStoreOp(op)), value, offset);
    535     return true;
    536 }
    537 
    538 bool B3IRGenerator::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result)
     547    return { };
     548}
     549
     550auto B3IRGenerator::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result) -> PartialResult
    539551{
    540552    result = m_currentBlock->appendNew<Value>(m_proc, B3::Select, Origin(), condition, nonZero, zero);
    541     return true;
     553    return { };
    542554}
    543555
     
    577589}
    578590
    579 bool B3IRGenerator::addIf(ExpressionType condition, Type signature, ControlType& result)
     591auto B3IRGenerator::addIf(ExpressionType condition, Type signature, ControlType& result) -> PartialResult
    580592{
    581593    // FIXME: This needs to do some kind of stack passing.
     
    592604    m_currentBlock = taken;
    593605    result = ControlData(m_proc, signature, BlockType::If, continuation, notTaken);
    594     return true;
    595 }
    596 
    597 bool B3IRGenerator::addElse(ControlData& data, const ExpressionList& currentStack)
     606    return { };
     607}
     608
     609auto B3IRGenerator::addElse(ControlData& data, const ExpressionList& currentStack) -> PartialResult
    598610{
    599611    unifyValuesWithBlock(currentStack, data.result);
     
    602614}
    603615
    604 bool B3IRGenerator::addElseToUnreachable(ControlData& data)
     616auto B3IRGenerator::addElseToUnreachable(ControlData& data) -> PartialResult
    605617{
    606618    ASSERT(data.type() == BlockType::If);
    607619    m_currentBlock = data.special;
    608620    data.convertIfToBlock();
    609     return true;
    610 }
    611 
    612 bool B3IRGenerator::addReturn(const ExpressionList& returnValues)
     621    return { };
     622}
     623
     624auto B3IRGenerator::addReturn(const ExpressionList& returnValues) -> PartialResult
    613625{
    614626    ASSERT(returnValues.size() <= 1);
     
    617629    else
    618630        m_currentBlock->appendNewControlValue(m_proc, B3::Return, Origin());
    619     return true;
    620 }
    621 
    622 bool B3IRGenerator::addBranch(ControlData& data, ExpressionType condition, const ExpressionList& returnValues)
     631    return { };
     632}
     633
     634auto B3IRGenerator::addBranch(ControlData& data, ExpressionType condition, const ExpressionList& returnValues) -> PartialResult
    623635{
    624636    if (data.type() != BlockType::Loop)
     
    638650    }
    639651
    640     return true;
    641 }
    642 
    643 bool B3IRGenerator::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack)
     652    return { };
     653}
     654
     655auto B3IRGenerator::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack) -> PartialResult
    644656{
    645657    for (size_t i = 0; i < targets.size(); ++i)
     
    652664        switchValue->appendCase(SwitchCase(i, FrequentedBlock(targets[i]->targetBlockForBranch())));
    653665
    654     return true;
    655 }
    656 
    657 bool B3IRGenerator::endBlock(ControlEntry& entry, ExpressionList& expressionStack)
     666    return { };
     667}
     668
     669auto B3IRGenerator::endBlock(ControlEntry& entry, ExpressionList& expressionStack) -> PartialResult
    658670{
    659671    ControlData& data = entry.controlData;
     
    667679
    668680
    669 bool B3IRGenerator::addEndToUnreachable(ControlEntry& entry)
     681auto B3IRGenerator::addEndToUnreachable(ControlEntry& entry) -> PartialResult
    670682{
    671683    ControlData& data = entry.controlData;
     
    680692        entry.enclosedExpressionStack.append(m_currentBlock->appendNew<VariableValue>(m_proc, B3::Get, Origin(), result));
    681693
    682     return true;
    683 }
    684 
    685 bool B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result)
     694    return { };
     695}
     696
     697auto B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
    686698{
    687699    ASSERT(signature->arguments.size() == args.size());
     
    706718            });
    707719        });
    708     return true;
    709 }
    710 
    711 bool B3IRGenerator::addCallIndirect(const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result)
     720    return { };
     721}
     722
     723auto B3IRGenerator::addCallIndirect(const Signature* signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
    712724{
    713725    ExpressionType calleeIndex = args.takeLast();
     
    780792        });
    781793
    782     return true;
     794    return { };
    783795}
    784796
     
    908920}
    909921
    910 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)
     922Expected<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)
    911923{
    912924    auto result = std::make_unique<WasmInternalFunction>();
     
    915927    B3IRGenerator context(vm, info, procedure, result.get(), unlinkedWasmToWasmCalls, functionIndexSpace);
    916928    FunctionParser<B3IRGenerator> parser(context, functionStart, functionLength, signature, functionIndexSpace, info);
    917     if (!parser.parse())
    918         RELEASE_ASSERT_NOT_REACHED();
     929    WASM_FAIL_IF_HELPER_FAILS(parser.parse());
    919930
    920931    procedure.resetReachability();
     
    930941    result->wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters();
    931942    result->jsToWasmEntrypoint.compilation = createJSToWasmWrapper(vm, *result, signature, result->wasmEntrypoint.compilation->code(), info.memory);
    932     return result;
     943    return WTFMove(result);
    933944}
    934945
     
    936947
    937948template<>
    938 bool B3IRGenerator::addOp<OpType::I32Ctz>(ExpressionType arg, ExpressionType& result)
     949auto B3IRGenerator::addOp<OpType::I32Ctz>(ExpressionType arg, ExpressionType& result) -> PartialResult
    939950{
    940951    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int32, Origin());
     
    945956    patchpoint->effects = Effects::none();
    946957    result = patchpoint;
    947     return true;
    948 }
    949 
    950 template<>
    951 bool B3IRGenerator::addOp<OpType::I64Ctz>(ExpressionType arg, ExpressionType& result)
     958    return { };
     959}
     960
     961template<>
     962auto B3IRGenerator::addOp<OpType::I64Ctz>(ExpressionType arg, ExpressionType& result) -> PartialResult
    952963{
    953964    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int64, Origin());
     
    958969    patchpoint->effects = Effects::none();
    959970    result = patchpoint;
    960     return true;
    961 }
    962 
    963 template<>
    964 bool B3IRGenerator::addOp<OpType::I32Popcnt>(ExpressionType arg, ExpressionType& result)
     971    return { };
     972}
     973
     974template<>
     975auto B3IRGenerator::addOp<OpType::I32Popcnt>(ExpressionType arg, ExpressionType& result) -> PartialResult
    965976{
    966977    // FIXME: This should use the popcnt instruction if SSE4 is available but we don't have code to detect SSE4 yet.
     
    969980    Value* funcAddress = m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), bitwise_cast<void*>(popcount));
    970981    result = m_currentBlock->appendNew<CCallValue>(m_proc, Int32, Origin(), Effects::none(), funcAddress, arg);
    971     return true;
    972 }
    973 
    974 template<>
    975 bool B3IRGenerator::addOp<OpType::I64Popcnt>(ExpressionType arg, ExpressionType& result)
     982    return { };
     983}
     984
     985template<>
     986auto B3IRGenerator::addOp<OpType::I64Popcnt>(ExpressionType arg, ExpressionType& result) -> PartialResult
    976987{
    977988    // FIXME: This should use the popcnt instruction if SSE4 is available but we don't have code to detect SSE4 yet.
     
    980991    Value* funcAddress = m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), bitwise_cast<void*>(popcount));
    981992    result = m_currentBlock->appendNew<CCallValue>(m_proc, Int64, Origin(), Effects::none(), funcAddress, arg);
    982     return true;
    983 }
    984 
    985 template<>
    986 bool B3IRGenerator::addOp<F64ConvertUI64>(ExpressionType arg, ExpressionType& result)
     993    return { };
     994}
     995
     996template<>
     997auto B3IRGenerator::addOp<F64ConvertUI64>(ExpressionType arg, ExpressionType& result) -> PartialResult
    987998{
    988999    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Double, Origin());
     
    10001011    patchpoint->effects = Effects::none();
    10011012    result = patchpoint;
    1002     return true;
    1003 }
    1004 
    1005 template<>
    1006 bool B3IRGenerator::addOp<OpType::F32ConvertUI64>(ExpressionType arg, ExpressionType& result)
     1013    return { };
     1014}
     1015
     1016template<>
     1017auto B3IRGenerator::addOp<OpType::F32ConvertUI64>(ExpressionType arg, ExpressionType& result) -> PartialResult
    10071018{
    10081019    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Float, Origin());
     
    10201031    patchpoint->effects = Effects::none();
    10211032    result = patchpoint;
    1022     return true;
    1023 }
    1024 
    1025 template<>
    1026 bool B3IRGenerator::addOp<OpType::F64Nearest>(ExpressionType arg, ExpressionType& result)
     1033    return { };
     1034}
     1035
     1036template<>
     1037auto B3IRGenerator::addOp<OpType::F64Nearest>(ExpressionType arg, ExpressionType& result) -> PartialResult
    10271038{
    10281039    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Double, Origin());
     
    10331044    patchpoint->effects = Effects::none();
    10341045    result = patchpoint;
    1035     return true;
    1036 }
    1037 
    1038 template<>
    1039 bool B3IRGenerator::addOp<OpType::F32Nearest>(ExpressionType arg, ExpressionType& result)
     1046    return { };
     1047}
     1048
     1049template<>
     1050auto B3IRGenerator::addOp<OpType::F32Nearest>(ExpressionType arg, ExpressionType& result) -> PartialResult
    10401051{
    10411052    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Float, Origin());
     
    10461057    patchpoint->effects = Effects::none();
    10471058    result = patchpoint;
    1048     return true;
    1049 }
    1050 
    1051 template<>
    1052 bool B3IRGenerator::addOp<OpType::F64Trunc>(ExpressionType arg, ExpressionType& result)
     1059    return { };
     1060}
     1061
     1062template<>
     1063auto B3IRGenerator::addOp<OpType::F64Trunc>(ExpressionType arg, ExpressionType& result) -> PartialResult
    10531064{
    10541065    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Double, Origin());
     
    10591070    patchpoint->effects = Effects::none();
    10601071    result = patchpoint;
    1061     return true;
    1062 }
    1063 
    1064 template<>
    1065 bool B3IRGenerator::addOp<OpType::F32Trunc>(ExpressionType arg, ExpressionType& result)
     1072    return { };
     1073}
     1074
     1075template<>
     1076auto B3IRGenerator::addOp<OpType::F32Trunc>(ExpressionType arg, ExpressionType& result) -> PartialResult
    10661077{
    10671078    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Float, Origin());
     
    10721083    patchpoint->effects = Effects::none();
    10731084    result = patchpoint;
    1074     return true;
    1075 }
    1076 
    1077 template<>
    1078 bool B3IRGenerator::addOp<OpType::I32TruncSF64>(ExpressionType arg, ExpressionType& result)
     1085    return { };
     1086}
     1087
     1088template<>
     1089auto B3IRGenerator::addOp<OpType::I32TruncSF64>(ExpressionType arg, ExpressionType& result) -> PartialResult
    10791090{
    10801091    Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), -static_cast<double>(std::numeric_limits<int32_t>::min()));
     
    10951106    patchpoint->effects = Effects::none();
    10961107    result = patchpoint;
    1097     return true;
    1098 }
    1099 
    1100 template<>
    1101 bool B3IRGenerator::addOp<OpType::I32TruncSF32>(ExpressionType arg, ExpressionType& result)
     1108    return { };
     1109}
     1110
     1111template<>
     1112auto B3IRGenerator::addOp<OpType::I32TruncSF32>(ExpressionType arg, ExpressionType& result) -> PartialResult
    11021113{
    11031114    Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), -static_cast<float>(std::numeric_limits<int32_t>::min()));
     
    11181129    patchpoint->effects = Effects::none();
    11191130    result = patchpoint;
    1120     return true;
    1121 }
    1122 
    1123 
    1124 template<>
    1125 bool B3IRGenerator::addOp<OpType::I32TruncUF64>(ExpressionType arg, ExpressionType& result)
     1131    return { };
     1132}
     1133
     1134
     1135template<>
     1136auto B3IRGenerator::addOp<OpType::I32TruncUF64>(ExpressionType arg, ExpressionType& result) -> PartialResult
    11261137{
    11271138    Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<int32_t>::min()) * -2.0);
     
    11421153    patchpoint->effects = Effects::none();
    11431154    result = patchpoint;
    1144     return true;
    1145 }
    1146 
    1147 template<>
    1148 bool B3IRGenerator::addOp<OpType::I32TruncUF32>(ExpressionType arg, ExpressionType& result)
     1155    return { };
     1156}
     1157
     1158template<>
     1159auto B3IRGenerator::addOp<OpType::I32TruncUF32>(ExpressionType arg, ExpressionType& result) -> PartialResult
    11491160{
    11501161    Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<int32_t>::min()) * -2.0);
     
    11651176    patchpoint->effects = Effects::none();
    11661177    result = patchpoint;
    1167     return true;
    1168 }
    1169 
    1170 template<>
    1171 bool B3IRGenerator::addOp<OpType::I64TruncSF64>(ExpressionType arg, ExpressionType& result)
     1178    return { };
     1179}
     1180
     1181template<>
     1182auto B3IRGenerator::addOp<OpType::I64TruncSF64>(ExpressionType arg, ExpressionType& result) -> PartialResult
    11721183{
    11731184    Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), -static_cast<double>(std::numeric_limits<int64_t>::min()));
     
    11881199    patchpoint->effects = Effects::none();
    11891200    result = patchpoint;
    1190     return true;
    1191 }
    1192 
    1193 template<>
    1194 bool B3IRGenerator::addOp<OpType::I64TruncUF64>(ExpressionType arg, ExpressionType& result)
     1201    return { };
     1202}
     1203
     1204template<>
     1205auto B3IRGenerator::addOp<OpType::I64TruncUF64>(ExpressionType arg, ExpressionType& result) -> PartialResult
    11951206{
    11961207    Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<int64_t>::min()) * -2.0);
     
    12301241    patchpoint->effects = Effects::none();
    12311242    result = patchpoint;
    1232     return true;
    1233 }
    1234 
    1235 template<>
    1236 bool B3IRGenerator::addOp<OpType::I64TruncSF32>(ExpressionType arg, ExpressionType& result)
     1243    return { };
     1244}
     1245
     1246template<>
     1247auto B3IRGenerator::addOp<OpType::I64TruncSF32>(ExpressionType arg, ExpressionType& result) -> PartialResult
    12371248{
    12381249    Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), -static_cast<float>(std::numeric_limits<int64_t>::min()));
     
    12531264    patchpoint->effects = Effects::none();
    12541265    result = patchpoint;
    1255     return true;
    1256 }
    1257 
    1258 template<>
    1259 bool B3IRGenerator::addOp<OpType::I64TruncUF32>(ExpressionType arg, ExpressionType& result)
     1266    return { };
     1267}
     1268
     1269template<>
     1270auto B3IRGenerator::addOp<OpType::I64TruncUF32>(ExpressionType arg, ExpressionType& result) -> PartialResult
    12601271{
    12611272    Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<int64_t>::min()) * -2.0);
     
    12951306    patchpoint->effects = Effects::none();
    12961307    result = patchpoint;
    1297     return true;
     1308    return { };
    12981309}
    12991310
  • trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h

    r209652 r209880  
    3131#include "VM.h"
    3232#include "WasmFormat.h"
     33#include <wtf/Expected.h>
    3334
    3435extern "C" void dumpProcedure(void*);
     
    3839class MemoryInformation;
    3940
    40 std::unique_ptr<WasmInternalFunction> parseAndCompile(VM&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&, const ModuleInformation&, unsigned optLevel = 1);
     41Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&, const ModuleInformation&, unsigned optLevel = 1);
    4142
    4243} } // namespace JSC::Wasm
  • trunk/Source/JavaScriptCore/wasm/WasmFormat.h

    r209830 r209880  
    6262}
    6363   
    64 struct External {
    65     enum Kind : uint8_t {
    66         // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
    67         Function = 0,
    68         Table = 1,
    69         Memory = 2,
    70         Global = 3,
    71     };
    72     template<typename Int>
    73     static bool isValid(Int val)
    74     {
    75         switch (val) {
    76         case Function:
    77         case Table:
    78         case Memory:
    79         case Global:
    80             return true;
    81         default:
    82             return false;
    83         }
    84     }
    85    
    86     static_assert(Function == 0, "Wasm needs Function to have the value 0");
    87     static_assert(Table    == 1, "Wasm needs Table to have the value 1");
    88     static_assert(Memory   == 2, "Wasm needs Memory to have the value 2");
    89     static_assert(Global   == 3, "Wasm needs Global to have the value 3");
    90 };
     64enum class ExternalKind : uint8_t {
     65    // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
     66    Function = 0,
     67    Table = 1,
     68    Memory = 2,
     69    Global = 3,
     70};
     71
     72template<typename Int>
     73static bool isValidExternalKind(Int val)
     74{
     75    switch (val) {
     76    case static_cast<Int>(ExternalKind::Function):
     77    case static_cast<Int>(ExternalKind::Table):
     78    case static_cast<Int>(ExternalKind::Memory):
     79    case static_cast<Int>(ExternalKind::Global):
     80        return true;
     81    default:
     82        return false;
     83    }
     84}
     85
     86static_assert(static_cast<int>(ExternalKind::Function) == 0, "Wasm needs Function to have the value 0");
     87static_assert(static_cast<int>(ExternalKind::Table)    == 1, "Wasm needs Table to have the value 1");
     88static_assert(static_cast<int>(ExternalKind::Memory)   == 2, "Wasm needs Memory to have the value 2");
     89static_assert(static_cast<int>(ExternalKind::Global)   == 3, "Wasm needs Global to have the value 3");
     90
     91static inline const char* makeString(ExternalKind kind)
     92{
     93    switch (kind) {
     94    case ExternalKind::Function: return "Function";
     95    case ExternalKind::Table: return "Table";
     96    case ExternalKind::Memory: return "Memory";
     97    case ExternalKind::Global: return "Global";
     98    }
     99    RELEASE_ASSERT_NOT_REACHED();
     100    return "?";
     101}
    91102
    92103struct Signature {
     
    98109    Identifier module;
    99110    Identifier field;
    100     External::Kind kind;
     111    ExternalKind kind;
    101112    unsigned kindIndex; // Index in the vector of the corresponding kind.
    102113};
     
    104115struct Export {
    105116    Identifier field;
    106     External::Kind kind;
     117    ExternalKind kind;
    107118    unsigned kindIndex; // Index in the vector of the corresponding kind.
    108119};
  • trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h

    r209852 r209880  
    4040
    4141template<typename Context>
    42 class FunctionParser : public Parser {
     42class FunctionParser : public Parser<void> {
    4343public:
    4444    typedef typename Context::ExpressionType ExpressionType;
     
    4848    FunctionParser(Context&, const uint8_t* functionStart, size_t functionLength, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);
    4949
    50     bool WARN_UNUSED_RETURN parse();
     50    Result WARN_UNUSED_RETURN parse();
    5151
    5252    struct ControlEntry {
     
    5858    static const bool verbose = false;
    5959
    60     bool WARN_UNUSED_RETURN parseBody();
    61     bool WARN_UNUSED_RETURN parseExpression(OpType);
    62     bool WARN_UNUSED_RETURN parseUnreachableExpression(OpType);
    63     bool WARN_UNUSED_RETURN addReturn();
    64     bool WARN_UNUSED_RETURN unifyControl(Vector<ExpressionType>&, unsigned level);
    65 
    66     bool WARN_UNUSED_RETURN popExpressionStack(ExpressionType& result);
     60    PartialResult WARN_UNUSED_RETURN parseBody();
     61    PartialResult WARN_UNUSED_RETURN parseExpression(OpType);
     62    PartialResult WARN_UNUSED_RETURN parseUnreachableExpression(OpType);
     63    PartialResult WARN_UNUSED_RETURN addReturn();
     64    PartialResult WARN_UNUSED_RETURN unifyControl(Vector<ExpressionType>&, unsigned level);
     65
     66#define WASM_TRY_POP_EXPRESSION_STACK_INTO(result, what) do {                               \
     67        WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't pop empty stack in " what); \
     68        result = m_expressionStack.takeLast();                                              \
     69    } while (0)
    6770
    6871    template<OpType>
    69     bool WARN_UNUSED_RETURN unaryCase();
     72    PartialResult WARN_UNUSED_RETURN unaryCase();
    7073
    7174    template<OpType>
    72     bool WARN_UNUSED_RETURN binaryCase();
    73 
    74     bool setErrorMessage(String&& message)
    75     {
    76         m_context.setErrorMessage(WTFMove(message));
    77         return false;
    78     }
     75    PartialResult WARN_UNUSED_RETURN binaryCase();
     76
     77#define WASM_TRY_ADD_TO_CONTEXT(add_expression) WASM_FAIL_IF_HELPER_FAILS(m_context.add_expression)
     78
     79    // FIXME add a macro as above for WASM_TRY_APPEND_TO_CONTROL_STACK https://bugs.webkit.org/show_bug.cgi?id=165862
    7980
    8081    Context& m_context;
     
    100101
    101102template<typename Context>
    102 bool FunctionParser<Context>::parse()
    103 {
    104     if (!m_context.addArguments(m_signature->arguments))
    105         return false;
    106 
     103auto FunctionParser<Context>::parse() -> Result
     104{
    107105    uint32_t localCount;
    108     if (!parseVarUInt32(localCount))
    109         return false;
     106
     107    WASM_PARSER_FAIL_IF(!m_context.addArguments(m_signature->arguments), "can't add ", m_signature->arguments.size(), " arguments to Function");
     108    WASM_PARSER_FAIL_IF(!parseVarUInt32(localCount), "can't get local count");
     109    WASM_PARSER_FAIL_IF(localCount == std::numeric_limits<uint32_t>::max(), "Function section's local count is too big ", localCount);
    110110
    111111    for (uint32_t i = 0; i < localCount; ++i) {
    112112        uint32_t numberOfLocals;
    113         if (!parseVarUInt32(numberOfLocals))
    114             return false;
    115 
    116113        Type typeOfLocal;
    117         if (!parseValueType(typeOfLocal))
    118             return false;
    119 
    120         if (!m_context.addLocal(typeOfLocal, numberOfLocals))
    121             return false;
    122     }
    123 
    124     return parseBody();
    125 }
    126 
    127 template<typename Context>
    128 bool FunctionParser<Context>::parseBody()
     114
     115        WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfLocals), "can't get Function's number of locals in group ", i);
     116        WASM_PARSER_FAIL_IF(numberOfLocals == std::numeric_limits<uint32_t>::max(), "Function section's ", i, "th local group count is too big ", numberOfLocals);
     117        WASM_PARSER_FAIL_IF(!parseValueType(typeOfLocal), "can't get Function local's type in group ", i);
     118        WASM_PARSER_FAIL_IF(!m_context.addLocal(typeOfLocal, numberOfLocals), "can't add ", numberOfLocals, " Function locals from group ", i);
     119    }
     120
     121    WASM_FAIL_IF_HELPER_FAILS(parseBody());
     122
     123    return { };
     124}
     125
     126template<typename Context>
     127auto FunctionParser<Context>::parseBody() -> PartialResult
    129128{
    130129    while (true) {
    131130        uint8_t op;
    132         if (!parseUInt8(op) || !isValidOpType(op)) {
    133             if (verbose)
    134                 WTF::dataLogLn("attempted to decode invalid op: ", RawPointer(reinterpret_cast<void*>(op)), " at offset: ", RawPointer(reinterpret_cast<void*>(m_offset)));
    135             return false;
    136         }
     131        WASM_PARSER_FAIL_IF(!parseUInt8(op), "can't decode opcode");
     132        WASM_PARSER_FAIL_IF(!isValidOpType(op), "invalid opcode ", op);
    137133
    138134        if (verbose) {
     
    141137        }
    142138
    143         if (op == OpType::End && !m_controlStack.size())
    144             return m_unreachableBlocks ? true : addReturn();
    145 
    146         if (m_unreachableBlocks) {
    147             if (!parseUnreachableExpression(static_cast<OpType>(op))) {
    148                 if (verbose)
    149                     dataLogLn("failed to process unreachable op:", op);
    150                 return false;
    151             }
    152         } else if (!parseExpression(static_cast<OpType>(op))) {
    153             if (verbose)
    154                 dataLogLn("failed to process op:", op);
    155             return false;
     139        if (op == OpType::End && !m_controlStack.size()) {
     140            if (m_unreachableBlocks)
     141                return { };
     142            return addReturn();
    156143        }
    157144
     145        if (m_unreachableBlocks)
     146            WASM_FAIL_IF_HELPER_FAILS(parseUnreachableExpression(static_cast<OpType>(op)));
     147        else
     148            WASM_FAIL_IF_HELPER_FAILS(parseExpression(static_cast<OpType>(op)));
    158149    }
    159150
     
    162153
    163154template<typename Context>
    164 bool FunctionParser<Context>::addReturn()
     155auto FunctionParser<Context>::addReturn() -> PartialResult
    165156{
    166157    ExpressionList returnValues;
    167158    if (m_signature->returnType != Void) {
    168159        ExpressionType returnValue;
    169         if (!popExpressionStack(returnValue))
    170             return false;
     160        WASM_TRY_POP_EXPRESSION_STACK_INTO(returnValue, "return");
    171161        returnValues.append(returnValue);
    172162    }
    173163
    174164    m_unreachableBlocks = 1;
    175     return m_context.addReturn(returnValues);
     165    WASM_TRY_ADD_TO_CONTEXT(addReturn(returnValues));
     166    return { };
    176167}
    177168
    178169template<typename Context>
    179170template<OpType op>
    180 bool FunctionParser<Context>::binaryCase()
     171auto FunctionParser<Context>::binaryCase() -> PartialResult
    181172{
    182173    ExpressionType right;
    183     if (!popExpressionStack(right))
    184         return false;
    185 
    186174    ExpressionType left;
    187     if (!popExpressionStack(left))
    188         return false;
    189 
    190175    ExpressionType result;
    191     if (!m_context.template addOp<op>(left, right, result))
    192         return false;
     176
     177    WASM_TRY_POP_EXPRESSION_STACK_INTO(right, "binary right");
     178    WASM_TRY_POP_EXPRESSION_STACK_INTO(left, "binary left");
     179    WASM_TRY_ADD_TO_CONTEXT(template addOp<op>(left, right, result));
     180
    193181    m_expressionStack.append(result);
    194     return true;
     182    return { };
    195183}
    196184
    197185template<typename Context>
    198186template<OpType op>
    199 bool FunctionParser<Context>::unaryCase()
     187auto FunctionParser<Context>::unaryCase() -> PartialResult
    200188{
    201189    ExpressionType value;
    202     if (!popExpressionStack(value))
    203         return false;
    204 
    205190    ExpressionType result;
    206     if (!m_context.template addOp<op>(value, result))
    207         return false;
     191
     192    WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "unary");
     193    WASM_TRY_ADD_TO_CONTEXT(template addOp<op>(value, result));
     194
    208195    m_expressionStack.append(result);
    209     return true;
    210 }
    211 
    212 template<typename Context>
    213 bool FunctionParser<Context>::parseExpression(OpType op)
     196    return { };
     197}
     198
     199template<typename Context>
     200auto FunctionParser<Context>::parseExpression(OpType op) -> PartialResult
    214201{
    215202    switch (op) {
     
    242229    case OpType::Select: {
    243230        ExpressionType condition;
    244         if (!popExpressionStack(condition))
    245             return false;
    246 
    247231        ExpressionType zero;
    248         if (!popExpressionStack(zero))
    249             return false;
    250 
    251232        ExpressionType nonZero;
    252         if (!popExpressionStack(nonZero))
    253             return false;
     233
     234        WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "select condition");
     235        WASM_TRY_POP_EXPRESSION_STACK_INTO(zero, "select zero");
     236        WASM_TRY_POP_EXPRESSION_STACK_INTO(nonZero, "select non-zero");
    254237
    255238        ExpressionType result;
    256         if (!m_context.addSelect(condition, nonZero, zero, result))
    257             return false;
     239        WASM_TRY_ADD_TO_CONTEXT(addSelect(condition, nonZero, zero, result));
    258240
    259241        m_expressionStack.append(result);
    260         return true;
     242        return { };
    261243    }
    262244
     
    264246    FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE) {
    265247        uint32_t alignment;
    266         if (!parseVarUInt32(alignment))
    267             return false;
    268 
    269248        uint32_t offset;
    270         if (!parseVarUInt32(offset))
    271             return false;
    272 
    273249        ExpressionType pointer;
    274         if (!popExpressionStack(pointer))
    275             return false;
    276 
    277250        ExpressionType result;
    278         if (!m_context.load(static_cast<LoadOpType>(op), pointer, result, offset))
    279             return false;
     251        WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get load alignment");
     252        WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get load offset");
     253        WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "load pointer");
     254        WASM_TRY_ADD_TO_CONTEXT(load(static_cast<LoadOpType>(op), pointer, result, offset));
    280255        m_expressionStack.append(result);
    281         return true;
     256        return { };
    282257    }
    283258
    284259    FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) {
    285260        uint32_t alignment;
    286         if (!parseVarUInt32(alignment))
    287             return false;
    288 
    289261        uint32_t offset;
    290         if (!parseVarUInt32(offset))
    291             return false;
    292 
    293262        ExpressionType value;
    294         if (!popExpressionStack(value))
    295             return false;
    296 
    297263        ExpressionType pointer;
    298         if (!popExpressionStack(pointer))
    299             return false;
    300 
    301         return m_context.store(static_cast<StoreOpType>(op), pointer, value, offset);
     264        WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get store alignment");
     265        WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get store offset");
     266        WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "store value");
     267        WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "store pointer");
     268        WASM_TRY_ADD_TO_CONTEXT(store(static_cast<StoreOpType>(op), pointer, value, offset));
     269        return { };
    302270    }
    303271#undef CREATE_CASE
     
    305273    case OpType::F32Const: {
    306274        uint32_t constant;
    307         if (!parseUInt32(constant))
    308             return false;
     275        WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't parse 32-bit floating-point constant");
    309276        m_expressionStack.append(m_context.addConstant(F32, constant));
    310         return true;
     277        return { };
    311278    }
    312279
    313280    case OpType::I32Const: {
    314281        int32_t constant;
    315         if (!parseVarInt32(constant))
    316             return false;
     282        WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't parse 32-bit constant");
    317283        m_expressionStack.append(m_context.addConstant(I32, constant));
    318         return true;
     284        return { };
    319285    }
    320286
    321287    case OpType::F64Const: {
    322288        uint64_t constant;
    323         if (!parseUInt64(constant))
    324             return false;
     289        WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't parse 64-bit floating-point constant");
    325290        m_expressionStack.append(m_context.addConstant(F64, constant));
    326         return true;
     291        return { };
    327292    }
    328293
    329294    case OpType::I64Const: {
    330295        int64_t constant;
    331         if (!parseVarInt64(constant))
    332             return false;
     296        WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't parse 64-bit constant");
    333297        m_expressionStack.append(m_context.addConstant(I64, constant));
    334         return true;
     298        return { };
    335299    }
    336300
    337301    case OpType::GetLocal: {
    338302        uint32_t index;
    339         if (!parseVarUInt32(index))
    340             return false;
    341303        ExpressionType result;
    342         if (!m_context.getLocal(index, result))
    343             return false;
    344 
     304        WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for get_local");
     305        WASM_PARSER_FAIL_IF(!m_context.getLocal(index, result), "can't get_local at index", index);
    345306        m_expressionStack.append(result);
    346         return true;
     307        return { };
    347308    }
    348309
    349310    case OpType::SetLocal: {
    350311        uint32_t index;
    351         if (!parseVarUInt32(index))
    352             return false;
    353312        ExpressionType value;
    354         if (!popExpressionStack(value))
    355             return false;
    356         return m_context.setLocal(index, value);
     313        WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for set_local");
     314        WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_local");
     315        WASM_TRY_ADD_TO_CONTEXT(setLocal(index, value));
     316        return { };
    357317    }
    358318
    359319    case OpType::TeeLocal: {
    360320        uint32_t index;
    361         if (!parseVarUInt32(index))
    362             return false;
    363         if (!m_expressionStack.size())
    364             return false;
    365         return m_context.setLocal(index, m_expressionStack.last());
     321        WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for tee_local");
     322        WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't tee_local on empty expression stack");
     323        WASM_TRY_ADD_TO_CONTEXT(setLocal(index, m_expressionStack.last()));
     324        return { };
    366325    }
    367326
    368327    case OpType::GetGlobal: {
    369328        uint32_t index;
    370         if (!parseVarUInt32(index))
    371             return false;
    372329        ExpressionType result;
    373         if (!m_context.getGlobal(index, result))
    374             return false;
    375 
     330        WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index");
     331        WASM_TRY_ADD_TO_CONTEXT(getGlobal(index, result));
    376332        m_expressionStack.append(result);
    377         return true;
     333        return { };
    378334    }
    379335
    380336    case OpType::SetGlobal: {
    381337        uint32_t index;
    382         if (!parseVarUInt32(index))
    383             return false;
    384338        ExpressionType value;
    385         if (!popExpressionStack(value))
    386             return false;
     339        WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get set_global's index");
     340        WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_global value");
     341        WASM_TRY_ADD_TO_CONTEXT(setGlobal(index, value));
    387342        return m_context.setGlobal(index, value);
    388343    }
     
    390345    case OpType::Call: {
    391346        uint32_t functionIndex;
    392         if (!parseVarUInt32(functionIndex))
    393             return false;
    394 
    395         if (functionIndex >= m_functionIndexSpace.size)
    396             return false;
     347        WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't parse call's function index");
     348        WASM_PARSER_FAIL_IF(functionIndex >= m_functionIndexSpace.size, "call function index ", functionIndex, " exceeds function index space ", m_functionIndexSpace.size);
    397349
    398350        const Signature* calleeSignature = m_functionIndexSpace.buffer.get()[functionIndex].signature;
    399 
    400         if (calleeSignature->arguments.size() > m_expressionStack.size())
    401             return false;
     351        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");
    402352
    403353        size_t firstArgumentIndex = m_expressionStack.size() - calleeSignature->arguments.size();
    404354        Vector<ExpressionType> args;
    405         args.reserveInitialCapacity(calleeSignature->arguments.size());
    406         for (unsigned i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
    407             args.append(m_expressionStack[i]);
     355        WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(calleeSignature->arguments.size()), "can't allocate enough memory for call's ", calleeSignature->arguments.size(), " arguments");
     356        for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
     357            args.uncheckedAppend(m_expressionStack[i]);
    408358        m_expressionStack.shrink(firstArgumentIndex);
    409359
    410360        ExpressionType result = Context::emptyExpression;
    411         if (!m_context.addCall(functionIndex, calleeSignature, args, result))
    412             return false;
     361        WASM_TRY_ADD_TO_CONTEXT(addCall(functionIndex, calleeSignature, args, result));
    413362
    414363        if (result != Context::emptyExpression)
    415364            m_expressionStack.append(result);
    416365
    417         return true;
     366            return { };
    418367    }
    419368
    420369    case OpType::CallIndirect: {
    421         if (!m_info.tableInformation)
    422             return setErrorMessage("call_indirect is only valid when a table is defined or imported");
    423370        uint32_t signatureIndex;
    424         if (!parseVarUInt32(signatureIndex))
    425             return false;
    426 
    427371        uint8_t reserved;
    428         if (!parseVarUInt1(reserved))
    429             return false;
    430 
    431         if (reserved != 0)
    432             return setErrorMessage("call_indirect 'reserved' varuint1 must be 0x0");
    433 
    434         if (m_info.signatures.size() <= signatureIndex)
    435             return setErrorMessage("Tried to use a signature outside the range of valid signatures");
     372        WASM_PARSER_FAIL_IF(!m_info.tableInformation, "call_indirect is only valid when a table is defined or imported");
     373        WASM_PARSER_FAIL_IF(!parseVarUInt32(signatureIndex), "can't get call_indirect's signature index");
     374        WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't get call_indirect's reserved byte");
     375        WASM_PARSER_FAIL_IF(reserved, "call_indirect's 'reserved' varuint1 must be 0x0");
     376        WASM_PARSER_FAIL_IF(m_info.signatures.size() <= signatureIndex, "call_indirect's signature index ", signatureIndex, " exceeds known signatures ", m_info.signatures.size());
    436377
    437378        const Signature* calleeSignature = &m_info.signatures[signatureIndex];
    438379        size_t argumentCount = calleeSignature->arguments.size() + 1; // Add the callee's index.
    439         if (argumentCount > m_expressionStack.size())
    440             return setErrorMessage("Not enough values on the stack for call_indirect");
     380        WASM_PARSER_FAIL_IF(argumentCount > m_expressionStack.size(), "call_indirect expects ", argumentCount, " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");
    441381
    442382        Vector<ExpressionType> args;
    443         if (!args.tryReserveCapacity(argumentCount))
    444             return setErrorMessage("Out of memory");
    445 
     383        WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(argumentCount), "can't allocate enough memory for ", argumentCount, " call_indirect arguments");
    446384        size_t firstArgumentIndex = m_expressionStack.size() - argumentCount;
    447         for (unsigned i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
     385        for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
    448386            args.uncheckedAppend(m_expressionStack[i]);
    449387        m_expressionStack.shrink(firstArgumentIndex);
    450388
    451389        ExpressionType result = Context::emptyExpression;
    452         if (!m_context.addCallIndirect(calleeSignature, args, result))
    453             return false;
     390        WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(calleeSignature, args, result));
    454391
    455392        if (result != Context::emptyExpression)
    456393            m_expressionStack.append(result);
    457394
    458         return true;
     395        return { };
    459396    }
    460397
    461398    case OpType::Block: {
    462399        Type inlineSignature;
    463         if (!parseResultType(inlineSignature))
    464             return false;
    465 
     400        WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get block's inline signature");
    466401        m_controlStack.append({ WTFMove(m_expressionStack), m_context.addBlock(inlineSignature) });
    467402        m_expressionStack = ExpressionList();
    468         return true;
     403        return { };
    469404    }
    470405
    471406    case OpType::Loop: {
    472407        Type inlineSignature;
    473         if (!parseResultType(inlineSignature))
    474             return false;
    475 
     408        WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get loop's inline signature");
    476409        m_controlStack.append({ WTFMove(m_expressionStack), m_context.addLoop(inlineSignature) });
    477410        m_expressionStack = ExpressionList();
    478         return true;
     411        return { };
    479412    }
    480413
    481414    case OpType::If: {
    482415        Type inlineSignature;
    483         if (!parseResultType(inlineSignature))
    484             return false;
    485 
    486416        ExpressionType condition;
    487         if (!popExpressionStack(condition))
    488             return false;
    489 
    490417        ControlType control;
    491         if (!m_context.addIf(condition, inlineSignature, control))
    492             return false;
    493 
     418        WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get if's inline signature");
     419        WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "if condition");
     420        WASM_TRY_ADD_TO_CONTEXT(addIf(condition, inlineSignature, control));
    494421        m_controlStack.append({ WTFMove(m_expressionStack), control });
    495422        m_expressionStack = ExpressionList();
    496         return true;
     423        return { };
    497424    }
    498425
    499426    case OpType::Else: {
    500         if (!m_controlStack.size()) {
    501             setErrorMessage("Attempted to use else block at the top-level of a function");
    502             return false;
    503         }
    504 
    505         if (!m_context.addElse(m_controlStack.last().controlData, m_expressionStack))
    506             return false;
     427        WASM_PARSER_FAIL_IF(m_controlStack.isEmpty(), "can't use else block at the top-level of a function");
     428        WASM_TRY_ADD_TO_CONTEXT(addElse(m_controlStack.last().controlData, m_expressionStack));
    507429        m_expressionStack.shrink(0);
    508         return true;
     430        return { };
    509431    }
    510432
     
    512434    case OpType::BrIf: {
    513435        uint32_t target;
    514         if (!parseVarUInt32(target) || target >= m_controlStack.size())
    515             return false;
    516 
    517436        ExpressionType condition = Context::emptyExpression;
    518         if (op == OpType::BrIf) {
    519             if (!popExpressionStack(condition))
    520                 return false;
    521         } else
     437        WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get br / br_if's target");
     438        WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br / br_if's target ", target, " exceeds control stack size ", m_controlStack.size());
     439        if (op == OpType::BrIf)
     440            WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br / br_if condition");
     441        else
    522442            m_unreachableBlocks = 1;
    523443
    524444        ControlType& data = m_controlStack[m_controlStack.size() - 1 - target].controlData;
    525445
    526         return m_context.addBranch(data, condition, m_expressionStack);
     446        WASM_TRY_ADD_TO_CONTEXT(addBranch(data, condition, m_expressionStack));
     447        return { };
    527448    }
    528449
    529450    case OpType::BrTable: {
    530451        uint32_t numberOfTargets;
    531         if (!parseVarUInt32(numberOfTargets))
    532             return false;
     452        ExpressionType condition;
     453        uint32_t defaultTarget;
     454        WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfTargets), "can't get the number of targets for br_table");
     455        WASM_PARSER_FAIL_IF(numberOfTargets == std::numeric_limits<uint32_t>::max(), "br_table's number of targets is too big ", numberOfTargets);
    533456
    534457        Vector<ControlType*> targets;
    535         if (!targets.tryReserveCapacity(numberOfTargets))
    536             return false;
    537 
     458        WASM_PARSER_FAIL_IF(!targets.tryReserveCapacity(numberOfTargets), "can't allocate memory for ", numberOfTargets, " br_table targets");
    538459        for (uint32_t i = 0; i < numberOfTargets; ++i) {
    539460            uint32_t target;
    540             if (!parseVarUInt32(target))
    541                 return false;
    542 
    543             if (target >= m_controlStack.size())
    544                 return false;
    545 
     461            WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get ", i, "th target for br_table");
     462            WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br_table's ", i, "th target ", target, " exceeds control stack size ", m_controlStack.size());
    546463            targets.uncheckedAppend(&m_controlStack[m_controlStack.size() - 1 - target].controlData);
    547464        }
    548465
    549         uint32_t defaultTarget;
    550         if (!parseVarUInt32(defaultTarget))
    551             return false;
    552 
    553         if (defaultTarget >= m_controlStack.size())
    554             return false;
    555 
    556         ExpressionType condition;
    557         if (!popExpressionStack(condition))
    558             return false;
    559        
    560         if (!m_context.addSwitch(condition, targets, m_controlStack[m_controlStack.size() - 1 - defaultTarget].controlData, m_expressionStack))
    561             return false;
     466        WASM_PARSER_FAIL_IF(!parseVarUInt32(defaultTarget), "can't get default target for br_table");
     467        WASM_PARSER_FAIL_IF(defaultTarget >= m_controlStack.size(), "br_table's default target ", defaultTarget, " exceeds control stack size ", m_controlStack.size());
     468        WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br_table condition");
     469        WASM_TRY_ADD_TO_CONTEXT(addSwitch(condition, targets, m_controlStack[m_controlStack.size() - 1 - defaultTarget].controlData, m_expressionStack));
    562470
    563471        m_unreachableBlocks = 1;
    564         return true;
     472        return { };
    565473    }
    566474
     
    574482        // That's a little too effectful for me but I don't have a better API right now.
    575483        // see: https://bugs.webkit.org/show_bug.cgi?id=164353
    576         if (!m_context.endBlock(data, m_expressionStack))
    577             return false;
     484        WASM_TRY_ADD_TO_CONTEXT(endBlock(data, m_expressionStack));
    578485        m_expressionStack.swap(data.enclosedExpressionStack);
    579         return true;
     486        return { };
    580487    }
    581488
    582489    case OpType::Unreachable: {
    583         m_context.addUnreachable();
     490        WASM_TRY_ADD_TO_CONTEXT(addUnreachable());
    584491        m_unreachableBlocks = 1;
    585         return true;
     492        return { };
    586493    }
    587494
    588495    case OpType::Drop: {
    589         if (!m_expressionStack.size()) {
    590             setErrorMessage("Attempted to drop an expression from an empty stack.");
    591             return false;
    592         }
     496        WASM_PARSER_FAIL_IF(!m_expressionStack.size(), "can't drop on empty stack");
    593497        m_expressionStack.takeLast();
    594         return true;
     498        return { };
    595499    }
    596500
    597501    case OpType::Nop: {
    598         return true;
     502        return { };
    599503    }
    600504
    601505    case OpType::GrowMemory:
     506        return fail("not yet implemented: grow_memory"); // FIXME: Not yet implemented.
     507
    602508    case OpType::CurrentMemory:
    603         // FIXME: Not yet implemented.
    604         return false;
     509        return fail("not yet implemented: current_memory"); // FIXME: Not yet implemented.
     510
    605511    }
    606512
     
    609515
    610516template<typename Context>
    611 bool FunctionParser<Context>::parseUnreachableExpression(OpType op)
     517auto FunctionParser<Context>::parseUnreachableExpression(OpType op) -> PartialResult
    612518{
    613519    ASSERT(m_unreachableBlocks);
     
    615521    case OpType::Else: {
    616522        if (m_unreachableBlocks > 1)
    617             return true;
     523            return { };
    618524
    619525        ControlEntry& data = m_controlStack.last();
    620526        m_unreachableBlocks = 0;
    621         if (!m_context.addElseToUnreachable(data.controlData))
    622             return false;
     527        WASM_TRY_ADD_TO_CONTEXT(addElseToUnreachable(data.controlData));
    623528        m_expressionStack.shrink(0);
    624         return true;
     529        return { };
    625530    }
    626531
     
    628533        if (m_unreachableBlocks == 1) {
    629534            ControlEntry data = m_controlStack.takeLast();
    630             if (!m_context.addEndToUnreachable(data))
    631                 return false;
     535            WASM_TRY_ADD_TO_CONTEXT(addEndToUnreachable(data));
    632536            m_expressionStack.swap(data.enclosedExpressionStack);
    633537        }
    634538        m_unreachableBlocks--;
    635         return true;
     539        return { };
    636540    }
    637541
     
    640544    case OpType::Block: {
    641545        m_unreachableBlocks++;
    642         return true;
     546        return { };
    643547    }
    644548
     
    647551    case OpType::BrIf: {
    648552        uint32_t unused;
    649         if (!parseVarUInt32(unused))
    650             return false;
    651         return parseVarUInt32(unused);
     553        WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get br / br_if in unreachable context");
     554        WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get br / br_if in unreachable context");
     555        return { };
    652556    }
    653557
     
    660564    case OpType::GetLocal: {
    661565        uint32_t unused;
    662         return parseVarUInt32(unused);
     566        WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get const / local in unreachable context");
     567        return { };
    663568    }
    664569
     
    666571        break;
    667572    }
    668     return true;
    669 }
    670 
    671 template<typename Context>
    672 bool FunctionParser<Context>::popExpressionStack(ExpressionType& result)
    673 {
    674     if (m_expressionStack.size()) {
    675         result = m_expressionStack.takeLast();
    676         return true;
    677     }
    678 
    679     setErrorMessage("Attempted to use a stack value when none existed");
    680     return false;
     573    return { };
    681574}
    682575
  • trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp

    r209874 r209880  
    4040namespace JSC { namespace Wasm {
    4141
    42 static const bool verbose = false;
    43 
    44 bool ModuleParser::parse()
    45 {
    46     m_module = std::make_unique<ModuleInformation>();
    47 
     42auto ModuleParser::parse() -> Result
     43{
     44    m_result.module = std::make_unique<ModuleInformation>();
    4845    const size_t minSize = 8;
    49     if (length() < minSize) {
    50         m_errorMessage = "Module is " + String::number(length()) + " bytes, expected at least " + String::number(minSize) + " bytes";
    51         return false;
    52     }
    53     if (!consumeCharacter(0) || !consumeString("asm")) {
    54         m_errorMessage = "Modules doesn't start with '\\0asm'";
    55         return false;
    56     }
    57 
    5846    uint32_t versionNumber;
    59     if (!parseUInt32(versionNumber)) {
    60         // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
    61         m_errorMessage = "couldn't parse version number";
    62         return false;
    63     }
    64 
    65     if (versionNumber != expectedVersionNumber) {
    66         // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
    67         m_errorMessage = "unexpected version number";
    68         return false;
    69     }
    70 
    71 
    72     if (verbose)
    73         dataLogLn("Passed processing header.");
    74 
    75     Sections::Section previousSection = Sections::Unknown;
     47
     48    WASM_PARSER_FAIL_IF(length() < minSize, "expected a module of at least ", minSize, " bytes");
     49    WASM_PARSER_FAIL_IF(!consumeCharacter(0) || !consumeString("asm"), "modules doesn't start with '\\0asm'");
     50    WASM_PARSER_FAIL_IF(!parseUInt32(versionNumber), "can't parse version number");
     51    WASM_PARSER_FAIL_IF(versionNumber != expectedVersionNumber, "unexpected version number ", versionNumber, " expected ", expectedVersionNumber);
     52
     53    Section previousSection = Section::Unknown;
    7654    while (m_offset < length()) {
    77         if (verbose)
    78             dataLogLn("Starting to parse next section at offset: ", m_offset);
    79 
    8055        uint8_t sectionByte;
    81         if (!parseUInt7(sectionByte)) {
    82             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
    83             m_errorMessage = "couldn't get section byte";
    84             return false;
    85         }
    86 
    87         if (verbose)
    88             dataLogLn("Section byte: ", sectionByte);
    89 
    90         Sections::Section section = Sections::Unknown;
     56
     57        WASM_PARSER_FAIL_IF(!parseUInt7(sectionByte), "can't get section byte");
     58
     59        Section section = Section::Unknown;
    9160        if (sectionByte) {
    92             if (sectionByte < Sections::Unknown)
    93                 section = static_cast<Sections::Section>(sectionByte);
    94         }
    95 
    96         if (!Sections::validateOrder(previousSection, section)) {
    97             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
    98             m_errorMessage = "invalid section order";
    99             return false;
     61            if (isValidSection(sectionByte))
     62                section = static_cast<Section>(sectionByte);
    10063        }
    10164
    10265        uint32_t sectionLength;
    103         if (!parseVarUInt32(sectionLength)) {
    104             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
    105             m_errorMessage = "couldn't get section length";
    106             return false;
    107         }
    108 
    109         if (sectionLength > length() - m_offset) {
    110             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
    111             m_errorMessage = "section content would overflow Module's size";
    112             return false;
    113         }
     66        WASM_PARSER_FAIL_IF(!validateOrder(previousSection, section), "invalid section order, ", previousSection, " followed by ", section);
     67        WASM_PARSER_FAIL_IF(!parseVarUInt32(sectionLength), "can't get ", section, " section's length");
     68        WASM_PARSER_FAIL_IF(sectionLength > length() - m_offset, section, "section of size ", sectionLength, " would overflow Module's size");
    11469
    11570        auto end = m_offset + sectionLength;
    11671
    11772        switch (section) {
    118         // FIXME improve error message in macro below https://bugs.webkit.org/show_bug.cgi?id=163919
    119 #define WASM_SECTION_PARSE(NAME, ID, DESCRIPTION) \
    120         case Sections::NAME: { \
    121             if (verbose) \
    122                 dataLogLn("Parsing " DESCRIPTION); \
    123             if (!parse ## NAME()) { \
    124                 m_errorMessage = "couldn't parse section " #NAME ": " DESCRIPTION; \
    125                 return false; \
    126             } \
    127             break; \
     73#define WASM_SECTION_PARSE(NAME, ID, DESCRIPTION)                   \
     74        case Section::NAME: {                                       \
     75            WASM_FAIL_IF_HELPER_FAILS(parse ## NAME());             \
     76            break;                                                  \
    12877        }
    12978        FOR_EACH_WASM_SECTION(WASM_SECTION_PARSE)
    13079#undef WASM_SECTION_PARSE
    13180
    132         case Sections::Unknown: {
    133             if (verbose)
    134                 dataLogLn("Unknown section, skipping.");
     81        case Section::Unknown: {
    13582            // Ignore section's name LEB and bytes: they're already included in sectionLength.
    13683            m_offset += sectionLength;
     
    13986        }
    14087
    141         if (verbose)
    142             dataLogLn("Finished parsing section.");
    143 
    144         if (end != m_offset) {
    145             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
    146             m_errorMessage = "parsing ended before the end of the section";
    147             return false;
    148         }
     88        WASM_PARSER_FAIL_IF(end != m_offset, "parsing ended before the end of ", section, " section");
    14989
    15090        previousSection = section;
    15191    }
    15292
    153     // TODO
    154     m_failed = false;
    155     return true;
    156 }
    157 
    158 bool ModuleParser::parseType()
     93    return WTFMove(m_result);
     94}
     95
     96auto ModuleParser::parseType() -> PartialResult
    15997{
    16098    uint32_t count;
    161     if (!parseVarUInt32(count)
    162         || count == std::numeric_limits<uint32_t>::max()
    163         || !m_module->signatures.tryReserveCapacity(count))
    164         return false;
    165     if (verbose)
    166         dataLogLn("  count: ", count);
     99
     100    WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Type section's count");
     101    WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Type section's count is too big ", count);
     102    WASM_PARSER_FAIL_IF(!m_result.module->signatures.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries");
    167103
    168104    for (uint32_t i = 0; i < count; ++i) {
    169105        int8_t type;
    170         if (!parseInt7(type))
    171             return false;
    172         if (type != Func)
    173             return false;
    174 
    175         if (verbose)
    176             dataLogLn("Got function type.");
    177 
    178106        uint32_t argumentCount;
    179107        Vector<Type> argumentTypes;
    180         if (!parseVarUInt32(argumentCount)
    181             || argumentCount == std::numeric_limits<uint32_t>::max()
    182             || !argumentTypes.tryReserveCapacity(argumentCount))
    183             return false;
    184         if (verbose)
    185             dataLogLn("  argument count: ", argumentCount);
     108
     109        WASM_PARSER_FAIL_IF(!parseInt7(type), "can't get ", i, "th Type's type");
     110        WASM_PARSER_FAIL_IF(type != Func, i, "th Type is non-Func ", type);
     111        WASM_PARSER_FAIL_IF(!parseVarUInt32(argumentCount), "can't get ", i, "th Type's argument count");
     112        WASM_PARSER_FAIL_IF(argumentCount == std::numeric_limits<uint32_t>::max(), i, "th argument count is too big ", argumentCount);
     113        WASM_PARSER_FAIL_IF(!argumentTypes.tryReserveCapacity(argumentCount), "can't allocate enough memory for Type section's ", i, "th ", argumentCount, " arguments");
    186114
    187115        for (unsigned i = 0; i < argumentCount; ++i) {
    188116            Type argumentType;
    189             if (!parseResultType(argumentType))
    190                 return false;
     117            WASM_PARSER_FAIL_IF(!parseResultType(argumentType), "can't get ", i, "th argument Type");
    191118            argumentTypes.uncheckedAppend(argumentType);
    192119        }
    193120
    194121        uint8_t returnCount;
    195         if (!parseVarUInt1(returnCount))
    196             return false;
     122        WASM_PARSER_FAIL_IF(!parseVarUInt1(returnCount), "can't get ", i, "th Type's return count");
    197123        Type returnType;
    198 
    199         if (verbose)
    200             dataLogLn(returnCount);
    201124
    202125        if (returnCount) {
    203126            Type value;
    204             if (!parseValueType(value))
    205                 return false;
     127            WASM_PARSER_FAIL_IF(!parseValueType(value), "can't get ", i, "th Type's return value");
    206128            returnType = static_cast<Type>(value);
    207129        } else
    208130            returnType = Type::Void;
    209131
    210         m_module->signatures.uncheckedAppend({ returnType, WTFMove(argumentTypes) });
    211     }
    212     return true;
    213 }
    214 
    215 bool ModuleParser::parseImport()
     132        m_result.module->signatures.uncheckedAppend({ returnType, WTFMove(argumentTypes) });
     133    }
     134    return { };
     135}
     136
     137auto ModuleParser::parseImport() -> PartialResult
    216138{
    217139    uint32_t importCount;
    218     if (!parseVarUInt32(importCount)
    219         || importCount == std::numeric_limits<uint32_t>::max()
    220         || !m_module->globals.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
    221         || !m_module->imports.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
    222         || !m_module->importFunctions.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
    223         || !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.
    224         return false;
     140    WASM_PARSER_FAIL_IF(!parseVarUInt32(importCount), "can't get Import section's count");
     141    WASM_PARSER_FAIL_IF(importCount == std::numeric_limits<uint32_t>::max(), "Import section's count is too big ", importCount);
     142    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.
     143    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.
     144    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.
     145    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.
    225146
    226147    for (uint32_t importNumber = 0; importNumber < importCount; ++importNumber) {
     
    230151        String moduleString;
    231152        String fieldString;
    232         if (!parseVarUInt32(moduleLen)
    233             || !consumeUTF8String(moduleString, moduleLen))
    234             return false;
     153
     154        WASM_PARSER_FAIL_IF(!parseVarUInt32(moduleLen), "can't get ", importNumber, "th Import's module name length");
     155        WASM_PARSER_FAIL_IF(!consumeUTF8String(moduleString, moduleLen), "can't get ", importNumber, "th Import's module name of length ", moduleLen);
    235156        imp.module = Identifier::fromString(m_vm, moduleString);
    236         if (!parseVarUInt32(fieldLen)
    237             || !consumeUTF8String(fieldString, fieldLen))
    238             return false;
     157
     158        WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", importNumber, "th Import's field name length in module '", moduleString, "'");
     159        WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", importNumber, "th Import's field name of length ", moduleLen, " in module '", moduleString, "'");
    239160        imp.field = Identifier::fromString(m_vm, fieldString);
    240         if (!parseExternalKind(imp.kind))
    241             return false;
     161
     162        WASM_PARSER_FAIL_IF(!parseExternalKind(imp.kind), "can't get ", importNumber, "th Import's kind in module '", moduleString, "' field '", fieldString, "'");
    242163        switch (imp.kind) {
    243         case External::Function: {
     164        case ExternalKind::Function: {
    244165            uint32_t functionSignatureIndex;
    245             if (!parseVarUInt32(functionSignatureIndex)
    246                 || functionSignatureIndex >= m_module->signatures.size())
    247                 return false;
    248             imp.kindIndex = m_module->importFunctions.size();
    249             Signature* signature = &m_module->signatures[functionSignatureIndex];
    250             m_module->importFunctions.uncheckedAppend(signature);
    251             m_functionIndexSpace.uncheckedAppend(signature);
    252             break;
    253         }
    254         case External::Table: {
     166            WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSignatureIndex), "can't get ", importNumber, "th Import's function signature in module '", moduleString, "' field '", fieldString, "'");
     167            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, "'");
     168            imp.kindIndex = m_result.module->importFunctions.size();
     169            Signature* signature = &m_result.module->signatures[functionSignatureIndex];
     170            m_result.module->importFunctions.uncheckedAppend(signature);
     171            m_result.functionIndexSpace.uncheckedAppend(signature);
     172            break;
     173        }
     174        case ExternalKind::Table: {
    255175            bool isImport = true;
    256             if (!parseTableHelper(isImport))
    257                 return false;
    258             break;
    259         }
    260         case External::Memory: {
     176            PartialResult result = parseTableHelper(isImport);
     177            if (UNLIKELY(!result))
     178                return result.getUnexpected();
     179            break;
     180        }
     181        case ExternalKind::Memory: {
    261182            bool isImport = true;
    262             if (!parseMemoryHelper(isImport))
    263                 return false;
    264             break;
    265         }
    266         case External::Global: {
     183            PartialResult result = parseMemoryHelper(isImport);
     184            if (UNLIKELY(!result))
     185                return result.getUnexpected();
     186            break;
     187        }
     188        case ExternalKind::Global: {
    267189            Global global;
    268             if (!parseGlobalType(global))
    269                 return false;
    270 
    271             if (global.mutability == Global::Mutable)
    272                 return false;
    273 
    274             imp.kindIndex = m_module->globals.size();
    275             m_module->globals.uncheckedAppend(WTFMove(global));
    276             break;
    277         }
    278         }
    279 
    280         m_module->imports.uncheckedAppend(imp);
    281     }
    282 
    283     m_module->firstInternalGlobal = m_module->globals.size();
    284     return true;
    285 }
    286 
    287 bool ModuleParser::parseFunction()
     190            WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global));
     191            WASM_PARSER_FAIL_IF(global.mutability == Global::Mutable, "Mutable Globals aren't supported");
     192
     193            imp.kindIndex = m_result.module->globals.size();
     194            m_result.module->globals.uncheckedAppend(WTFMove(global));
     195            break;
     196        }
     197        }
     198
     199        m_result.module->imports.uncheckedAppend(imp);
     200    }
     201
     202    m_result.module->firstInternalGlobal = m_result.module->globals.size();
     203    return { };
     204}
     205
     206auto ModuleParser::parseFunction() -> PartialResult
    288207{
    289208    uint32_t count;
    290     if (!parseVarUInt32(count)
    291         || count == std::numeric_limits<uint32_t>::max()
    292         || !m_module->internalFunctionSignatures.tryReserveCapacity(count)
    293         || !m_functionLocationInBinary.tryReserveCapacity(count)
    294         || !m_functionIndexSpace.tryReserveCapacity(m_functionIndexSpace.size() + count))
    295         return false;
     209    WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Function section's count");
     210    WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Function section's count is too big ", count);
     211    WASM_PARSER_FAIL_IF(!m_result.module->internalFunctionSignatures.tryReserveCapacity(count), "can't allocate enough memory for ", count, " Function signatures");
     212    WASM_PARSER_FAIL_IF(!m_result.functionLocationInBinary.tryReserveCapacity(count), "can't allocate enough memory for ", count, "Function locations");
     213    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");
    296214
    297215    for (uint32_t i = 0; i < count; ++i) {
    298216        uint32_t typeNumber;
    299         if (!parseVarUInt32(typeNumber)
    300             || typeNumber >= m_module->signatures.size())
    301             return false;
    302 
    303         Signature* signature = &m_module->signatures[typeNumber];
     217        WASM_PARSER_FAIL_IF(!parseVarUInt32(typeNumber), "can't get ", i, "th Function's type number");
     218        WASM_PARSER_FAIL_IF(typeNumber >= m_result.module->signatures.size(), i, "th Function type number is invalid ", typeNumber);
     219
     220        Signature* signature = &m_result.module->signatures[typeNumber];
    304221        // The Code section fixes up start and end.
    305222        size_t start = 0;
    306223        size_t end = 0;
    307         m_module->internalFunctionSignatures.uncheckedAppend(signature);
    308         m_functionLocationInBinary.uncheckedAppend({ start, end });
    309         m_functionIndexSpace.uncheckedAppend(signature);
    310     }
    311 
    312     return true;
    313 }
    314 
    315 bool ModuleParser::parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum)
     224        m_result.module->internalFunctionSignatures.uncheckedAppend(signature);
     225        m_result.functionLocationInBinary.uncheckedAppend({ start, end });
     226        m_result.functionIndexSpace.uncheckedAppend(signature);
     227    }
     228
     229    return { };
     230}
     231
     232auto ModuleParser::parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum) -> PartialResult
    316233{
    317234    ASSERT(!maximum);
    318235
    319236    uint8_t flags;
    320     if (!parseVarUInt1(flags))
    321         return false;
    322 
    323     if (!parseVarUInt32(initial))
    324         return false;
     237    WASM_PARSER_FAIL_IF(!parseVarUInt1(flags), "can't parse resizable limits flags");
     238    WASM_PARSER_FAIL_IF(!parseVarUInt32(initial), "can't parse resizable limits initial page count");
    325239
    326240    if (flags) {
    327241        uint32_t maximumInt;
    328         if (!parseVarUInt32(maximumInt))
    329             return false;
    330 
    331         if (initial > maximumInt)
    332             return false;
    333 
     242        WASM_PARSER_FAIL_IF(!parseVarUInt32(maximumInt), "can't parse resizable limits maximum page count");
     243        WASM_PARSER_FAIL_IF(initial > maximumInt, "resizable limits has a initial page count of ", initial, " which is greater than its maximum ", maximumInt);
    334244        maximum = maximumInt;
    335245    }
    336246
    337     return true;
    338 }
    339 
    340 bool ModuleParser::parseTableHelper(bool isImport)
    341 {
    342     // We're only allowed a total of one Table import or definition.
    343     if (m_hasTable)
    344         return false;
     247    return { };
     248}
     249
     250auto ModuleParser::parseTableHelper(bool isImport) -> PartialResult
     251{
     252    WASM_PARSER_FAIL_IF(m_hasTable, "Table section cannot exist if an Import has a table");
    345253
    346254    m_hasTable = true;
    347255
    348256    int8_t type;
    349     if (!parseInt7(type))
    350         return false;
    351     if (type != Wasm::Anyfunc)
    352         return false;
     257    WASM_PARSER_FAIL_IF(!parseInt7(type), "can't parse Table type");
     258    WASM_PARSER_FAIL_IF(type != Wasm::Anyfunc, "Table type should be anyfunc, got ", type);
    353259
    354260    uint32_t initial;
    355261    std::optional<uint32_t> maximum;
    356     if (!parseResizableLimits(initial, maximum))
    357         return false;
    358 
    359     if (!JSWebAssemblyTable::isValidSize(initial))
    360         return false;
     262    PartialResult limits = parseResizableLimits(initial, maximum);
     263    if (UNLIKELY(!limits))
     264        return limits.getUnexpected();
     265    WASM_PARSER_FAIL_IF(!JSWebAssemblyTable::isValidSize(initial), "Table's initial page count of ", initial, " is invalid");
    361266
    362267    ASSERT(!maximum || *maximum >= initial);
    363268
    364     m_module->tableInformation = TableInformation(initial, maximum, isImport);
    365 
    366     return true;
    367 }
    368 
    369 bool ModuleParser::parseTable()
     269    m_result.module->tableInformation = TableInformation(initial, maximum, isImport);
     270
     271    return { };
     272}
     273
     274auto ModuleParser::parseTable() -> PartialResult
    370275{
    371276    uint32_t count;
    372     if (!parseVarUInt32(count))
    373         return false;
    374 
    375     // We only allow one table for now.
    376     if (count != 1)
    377         return false;
     277    WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Table's count");
     278    WASM_PARSER_FAIL_IF(count != 1, "Table count of ", count, " is invalid, only 1 is allowed for now");
    378279
    379280    bool isImport = false;
    380     return parseTableHelper(isImport);
    381 }
    382 
    383 bool ModuleParser::parseMemoryHelper(bool isImport)
    384 {
    385     // We don't allow redeclaring memory. Either via import or definition.
    386     if (m_module->memory)
    387         return false;
     281    PartialResult result = parseTableHelper(isImport);
     282    if (UNLIKELY(!result))
     283        return result.getUnexpected();
     284
     285    return { };
     286}
     287
     288auto ModuleParser::parseMemoryHelper(bool isImport) -> PartialResult
     289{
     290    WASM_PARSER_FAIL_IF(m_result.module->memory, "Memory section cannot exist if an Import has a memory");
    388291
    389292    PageCount initialPageCount;
     
    392295        uint32_t initial;
    393296        std::optional<uint32_t> maximum;
    394         if (!parseResizableLimits(initial, maximum))
    395             return false;
     297        PartialResult limits = parseResizableLimits(initial, maximum);
     298        if (UNLIKELY(!limits))
     299            return limits.getUnexpected();
    396300        ASSERT(!maximum || *maximum >= initial);
    397         if (!PageCount::isValid(initial))
    398             return false;
     301        WASM_PARSER_FAIL_IF(!PageCount::isValid(initial), "Memory's initial page count of ", initial, " is invalid");
    399302
    400303        initialPageCount = PageCount(initial);
    401304
    402305        if (maximum) {
    403             if (!PageCount::isValid(*maximum))
    404                 return false;
     306            WASM_PARSER_FAIL_IF(!PageCount::isValid(*maximum), "Memory's maximum page count of ", *maximum, " is invalid");
    405307            maximumPageCount = PageCount(*maximum);
    406308        }
     
    410312
    411313    Vector<unsigned> pinnedSizes = { 0 };
    412     m_module->memory = MemoryInformation(initialPageCount, maximumPageCount, pinnedSizes, isImport);
    413     return true;
    414 }
    415 
    416 bool ModuleParser::parseMemory()
     314    m_result.module->memory = MemoryInformation(initialPageCount, maximumPageCount, pinnedSizes, isImport);
     315    return { };
     316}
     317
     318auto ModuleParser::parseMemory() -> PartialResult
    417319{
    418320    uint8_t count;
    419     if (!parseVarUInt1(count))
    420         return false;
     321    WASM_PARSER_FAIL_IF(!parseVarUInt1(count), "can't parse Memory section's count");
    421322
    422323    if (!count)
    423         return true;
    424 
    425     // We only allow one memory for now.
    426     if (count != 1)
    427         return false;
     324        return { };
     325
     326    WASM_PARSER_FAIL_IF(count != 1, "Memory section has more than one memory, WebAssembly currently only allows zero or one");
    428327
    429328    bool isImport = false;
     
    431330}
    432331
    433 bool ModuleParser::parseGlobal()
     332auto ModuleParser::parseGlobal() -> PartialResult
    434333{
    435334    uint32_t globalCount;
    436     if (!parseVarUInt32(globalCount))
    437         return false;
    438     if (!m_module->globals.tryReserveCapacity(globalCount + m_module->firstInternalGlobal))
    439         return false;
     335    WASM_PARSER_FAIL_IF(!parseVarUInt32(globalCount), "can't get Global section's count");
     336    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");
    440337
    441338    for (uint32_t globalIndex = 0; globalIndex < globalCount; ++globalIndex) {
    442339        Global global;
    443         if (!parseGlobalType(global))
    444             return false;
    445 
    446340        uint8_t initOpcode;
    447         if (!parseInitExpr(initOpcode, global.initialBitsOrImportNumber))
    448             return false;
     341
     342        WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global));
     343        WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, global.initialBitsOrImportNumber));
    449344
    450345        global.initializationType = Global::FromExpression;
     
    464359            break;
    465360        case GetGlobal:
    466             if (global.initialBitsOrImportNumber >= m_module->firstInternalGlobal)
    467                 return false;
    468             typeForInitOpcode = m_module->globals[global.initialBitsOrImportNumber].type;
     361            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);
     362            typeForInitOpcode = m_result.module->globals[global.initialBitsOrImportNumber].type;
    469363            global.initializationType = Global::FromGlobalImport;
    470364            break;
     
    473367        }
    474368
    475         if (typeForInitOpcode != global.type)
    476             return false;
    477 
    478         m_module->globals.uncheckedAppend(WTFMove(global));
    479     }
    480 
    481     return true;
    482 }
    483 
    484 bool ModuleParser::parseExport()
     369        WASM_PARSER_FAIL_IF(typeForInitOpcode != global.type, "Global init_expr opcode of type ", typeForInitOpcode, " doesn't match global's type ", global.type);
     370
     371        m_result.module->globals.uncheckedAppend(WTFMove(global));
     372    }
     373
     374    return { };
     375}
     376
     377auto ModuleParser::parseExport() -> PartialResult
    485378{
    486379    uint32_t exportCount;
    487     if (!parseVarUInt32(exportCount)
    488         || exportCount == std::numeric_limits<uint32_t>::max()
    489         || !m_module->exports.tryReserveCapacity(exportCount))
    490         return false;
     380    WASM_PARSER_FAIL_IF(!parseVarUInt32(exportCount), "can't get Export section's count");
     381    WASM_PARSER_FAIL_IF(exportCount == std::numeric_limits<uint32_t>::max(), "Export section's count is too big ", exportCount);
     382    WASM_PARSER_FAIL_IF(!m_result.module->exports.tryReserveCapacity(exportCount), "can't allocate enough memory for ", exportCount, " exports");
    491383
    492384    for (uint32_t exportNumber = 0; exportNumber < exportCount; ++exportNumber) {
     
    494386        uint32_t fieldLen;
    495387        String fieldString;
    496         if (!parseVarUInt32(fieldLen)
    497             || !consumeUTF8String(fieldString, fieldLen))
    498             return false;
     388
     389        WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", exportNumber, "th Export's field name length");
     390        WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", exportNumber, "th Export's field name of length ", fieldLen);
    499391        exp.field = Identifier::fromString(m_vm, fieldString);
    500392
    501         if (!parseExternalKind(exp.kind))
    502             return false;
    503 
    504         if (!parseVarUInt32(exp.kindIndex))
    505             return false;
    506 
     393        WASM_PARSER_FAIL_IF(!parseExternalKind(exp.kind), "can't get ", exportNumber, "th Export's kind, named '", fieldString, "'");
     394        WASM_PARSER_FAIL_IF(!parseVarUInt32(exp.kindIndex), "can't get ", exportNumber, "th Export's kind index, named '", fieldString, "'");
    507395        switch (exp.kind) {
    508         case External::Function: {
    509             if (exp.kindIndex >= m_functionIndexSpace.size())
    510                 return false;
    511             break;
    512         }
    513         case External::Table: {
    514             if (!m_hasTable)
    515                 return false;
    516             if (exp.kindIndex != 0)
    517                 return false;
    518             break;
    519         }
    520         case External::Memory: {
    521             if (!m_module->memory)
    522                 return false;
    523             if (exp.kindIndex != 0)
    524                 return false;
    525             break;
    526         }
    527         case External::Global: {
    528             if (exp.kindIndex >= m_module->globals.size())
    529                 return false;
    530 
    531             if (m_module->globals[exp.kindIndex].mutability != Global::Immutable)
    532                 return false;
    533             break;
    534         }
    535         }
    536 
    537         m_module->exports.uncheckedAppend(exp);
    538     }
    539 
    540     return true;
    541 }
    542 
    543 bool ModuleParser::parseStart()
     396        case ExternalKind::Function: {
     397            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, "'");
     398            break;
     399        }
     400        case ExternalKind::Table: {
     401            WASM_PARSER_FAIL_IF(!m_hasTable, "can't export a non-existent Table");
     402            WASM_PARSER_FAIL_IF(exp.kindIndex, "can't export Table ", exp.kindIndex, " only zero-index Table is currently supported");
     403            break;
     404        }
     405        case ExternalKind::Memory: {
     406            WASM_PARSER_FAIL_IF(!m_result.module->memory, "can't export a non-existent Memory");
     407            WASM_PARSER_FAIL_IF(exp.kindIndex, "can't export Memory ", exp.kindIndex, " only one Table is currently supported");
     408            break;
     409        }
     410        case ExternalKind::Global: {
     411            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, "'");
     412            WASM_PARSER_FAIL_IF(m_result.module->globals[exp.kindIndex].mutability != Global::Immutable, exportNumber, "th Export isn't immutable, named '", fieldString, "'");
     413            break;
     414        }
     415        }
     416
     417        m_result.module->exports.uncheckedAppend(exp);
     418    }
     419
     420    return { };
     421}
     422
     423auto ModuleParser::parseStart() -> PartialResult
    544424{
    545425    uint32_t startFunctionIndex;
    546     if (!parseVarUInt32(startFunctionIndex)
    547         || startFunctionIndex >= m_functionIndexSpace.size())
    548         return false;
    549     Signature* signature = m_functionIndexSpace[startFunctionIndex].signature;
    550     if (signature->arguments.size() != 0
    551         || signature->returnType != Void)
    552         return false;
    553     m_module->startFunctionIndexSpace = startFunctionIndex;
    554     return true;
    555 }
    556 
    557 bool ModuleParser::parseElement()
    558 {
    559     if (!m_hasTable)
    560         return false;
     426    WASM_PARSER_FAIL_IF(!parseVarUInt32(startFunctionIndex), "can't get Start index");
     427    WASM_PARSER_FAIL_IF(startFunctionIndex >= m_result.functionIndexSpace.size(), "Start index ", startFunctionIndex, " exceeds function index space ", m_result.functionIndexSpace.size());
     428    Signature* signature = m_result.functionIndexSpace[startFunctionIndex].signature;
     429    WASM_PARSER_FAIL_IF(!signature->arguments.isEmpty(), "Start function can't have arguments");
     430    WASM_PARSER_FAIL_IF(signature->returnType != Void, "Start function can't return a value");
     431    m_result.module->startFunctionIndexSpace = startFunctionIndex;
     432    return { };
     433}
     434
     435auto ModuleParser::parseElement() -> PartialResult
     436{
     437    WASM_PARSER_FAIL_IF(!m_hasTable, "Element section expects a Table to be present");
    561438
    562439    uint32_t elementCount;
    563     if (!parseVarUInt32(elementCount))
    564         return false;
    565     if (!m_module->elements.tryReserveCapacity(elementCount))
    566         return false;
    567 
    568     for (unsigned i = 0; i < elementCount; ++i) {
     440    WASM_PARSER_FAIL_IF(!parseVarUInt32(elementCount), "can't get Element section's count");
     441    WASM_PARSER_FAIL_IF(elementCount == std::numeric_limits<uint32_t>::max(), "Element section's count is too big ", elementCount);
     442    WASM_PARSER_FAIL_IF(!m_result.module->elements.tryReserveCapacity(elementCount), "can't allocate memory for ", elementCount, " Elements");
     443    for (unsigned elementNum = 0; elementNum < elementCount; ++elementNum) {
    569444        uint32_t tableIndex;
    570         if (!parseVarUInt32(tableIndex))
    571             return false;
    572         // We only support one table for now.
    573         if (tableIndex != 0)
    574             return false;
    575 
    576445        uint64_t offset;
    577446        uint8_t initOpcode;
    578         if (!parseInitExpr(initOpcode, offset))
    579             return false;
    580 
    581         if (initOpcode != OpType::I32Const)
    582             return false;
    583 
    584447        uint32_t indexCount;
    585         if (!parseVarUInt32(indexCount))
    586             return false;
    587 
    588         ASSERT(!!m_module->tableInformation);
    589         if (std::optional<uint32_t> maximum = m_module->tableInformation.maximum()) {
     448
     449        WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index");
     450        WASM_PARSER_FAIL_IF(tableIndex, "Element section can only have one Table for now");
     451        WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, offset));
     452        WASM_PARSER_FAIL_IF(initOpcode != OpType::I32Const, "Element section doesn't support non-i32 init_expr opcode for now, got ", initOpcode);
     453        WASM_PARSER_FAIL_IF(!parseVarUInt32(indexCount), "can't get ", elementNum, "th index count for Element section");
     454        WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount);
     455
     456        ASSERT(!!m_result.module->tableInformation);
     457        if (std::optional<uint32_t> maximum = m_result.module->tableInformation.maximum()) {
    590458            // FIXME: should indexCount being zero be a validation error?
    591459            // https://bugs.webkit.org/show_bug.cgi?id=165826
     
    595463                // https://bugs.webkit.org/show_bug.cgi?id=165827
    596464                uint64_t lastWrittenIndex = static_cast<uint64_t>(indexCount) + static_cast<uint64_t>(offset) - 1;
    597                 if (lastWrittenIndex >= static_cast<uint64_t>(*maximum))
    598                     return false;
     465                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);
    599466            }
    600467        }
    601468
    602469        Element element;
    603         if (!element.functionIndices.tryReserveCapacity(indexCount))
    604             return false;
     470        WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
    605471
    606472        element.offset = offset;
    607473
    608         for (unsigned i = 0; i < indexCount; ++i) {
     474        for (unsigned index = 0; index < indexCount; ++index) {
    609475            uint32_t functionIndex;
    610             if (!parseVarUInt32(functionIndex))
    611                 return false;
    612 
    613             if (functionIndex >= m_functionIndexSpace.size())
    614                 return false;
     476            WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index");
     477            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());
    615478
    616479            element.functionIndices.uncheckedAppend(functionIndex);
    617480        }
    618481
    619         m_module->elements.uncheckedAppend(WTFMove(element));
    620     }
    621 
    622     return true;
    623 }
    624 
    625 bool ModuleParser::parseCode()
     482        m_result.module->elements.uncheckedAppend(WTFMove(element));
     483    }
     484
     485    return { };
     486}
     487
     488auto ModuleParser::parseCode() -> PartialResult
    626489{
    627490    uint32_t count;
    628     if (!parseVarUInt32(count)
    629         || count == std::numeric_limits<uint32_t>::max()
    630         || count != m_functionLocationInBinary.size())
    631         return false;
     491    WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Code section's count");
     492    WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Code section's count is too big ", count);
     493    WASM_PARSER_FAIL_IF(count != m_result.functionLocationInBinary.size(), "Code section count ", count, " exceeds the declared number of functions ", m_result.functionLocationInBinary.size());
    632494
    633495    for (uint32_t i = 0; i < count; ++i) {
    634496        uint32_t functionSize;
    635         if (!parseVarUInt32(functionSize)
    636             || functionSize > length()
    637             || functionSize > length() - m_offset)
    638             return false;
    639 
    640         m_functionLocationInBinary[i].start = m_offset;
    641         m_functionLocationInBinary[i].end = m_offset + functionSize;
    642         m_offset = m_functionLocationInBinary[i].end;
    643     }
    644 
    645     return true;
    646 }
    647 
    648 bool ModuleParser::parseInitExpr(uint8_t& opcode, uint64_t& bitsOrImportNumber)
    649 {
    650     if (!parseUInt8(opcode))
    651         return false;
     497        WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSize), "can't get ", i, "th Code function's size");
     498        WASM_PARSER_FAIL_IF(functionSize > length(), "Code function's size ", functionSize, " exceeds the module's size ", length());
     499        WASM_PARSER_FAIL_IF(functionSize > length() - m_offset, "Code function's size ", functionSize, " exceeds the module's remaining size", length() - m_offset);
     500
     501        m_result.functionLocationInBinary[i].start = m_offset;
     502        m_result.functionLocationInBinary[i].end = m_offset + functionSize;
     503        m_offset = m_result.functionLocationInBinary[i].end;
     504    }
     505
     506    return { };
     507}
     508
     509auto ModuleParser::parseInitExpr(uint8_t& opcode, uint64_t& bitsOrImportNumber) -> PartialResult
     510{
     511    WASM_PARSER_FAIL_IF(!parseUInt8(opcode), "can't get init_expr's opcode");
    652512
    653513    switch (opcode) {
    654514    case I32Const: {
    655515        int32_t constant;
    656         if (!parseVarInt32(constant))
    657             return false;
     516        WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't get constant value for init_expr's i32.const");
    658517        bitsOrImportNumber = static_cast<uint64_t>(constant);
    659518        break;
     
    662521    case I64Const: {
    663522        int64_t constant;
    664         if (!parseVarInt64(constant))
    665             return false;
     523        WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't get constant value for init_expr's i64.const");
    666524        bitsOrImportNumber = constant;
    667525        break;
     
    670528    case F32Const: {
    671529        uint32_t constant;
    672         if (!parseUInt32(constant))
    673             return false;
     530        WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't get constant value for init_expr's f32.const");
    674531        bitsOrImportNumber = constant;
    675532        break;
     
    678535    case F64Const: {
    679536        uint64_t constant;
    680         if (!parseUInt64(constant))
    681             return false;
     537        WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't get constant value for init_expr's f64.const");
    682538        bitsOrImportNumber = constant;
    683539        break;
     
    686542    case GetGlobal: {
    687543        uint32_t index;
    688         if (!parseVarUInt32(index))
    689             return false;
    690 
    691         if (index >= m_module->imports.size())
    692             return false;
    693         const Import& import = m_module->imports[index];
    694         if (m_module->imports[index].kind != External::Global
    695             || import.kindIndex >= m_module->firstInternalGlobal)
    696             return false;
    697 
    698         ASSERT(m_module->globals[import.kindIndex].mutability == Global::Immutable);
     544        WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index");
     545        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());
     546        const Import& import = m_result.module->imports[index];
     547        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");
     548        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);
     549
     550        ASSERT(m_result.module->globals[import.kindIndex].mutability == Global::Immutable);
    699551
    700552        bitsOrImportNumber = index;
     
    703555
    704556    default:
    705         return false;
     557        WASM_PARSER_FAIL_IF(false, "unknown init_expr opcode ", opcode);
    706558    }
    707559
    708560    uint8_t endOpcode;
    709     if (!parseUInt8(endOpcode) || endOpcode != OpType::End)
    710         return false;
    711 
    712     return true;
    713 }
    714 
    715 bool ModuleParser::parseGlobalType(Global& global)
     561    WASM_PARSER_FAIL_IF(!parseUInt8(endOpcode), "can't get init_expr's end opcode");
     562    WASM_PARSER_FAIL_IF(endOpcode != OpType::End, "init_expr should end with end, ended with ", endOpcode);
     563
     564    return { };
     565}
     566
     567auto ModuleParser::parseGlobalType(Global& global) -> PartialResult
    716568{
    717569    uint8_t mutability;
    718     if (!parseValueType(global.type) || !parseVarUInt1(mutability))
    719         return false;
     570    WASM_PARSER_FAIL_IF(!parseValueType(global.type), "can't get Global's value type");
     571    WASM_PARSER_FAIL_IF(!parseVarUInt1(mutability), "can't get Global type's mutability");
    720572    global.mutability = static_cast<Global::Mutability>(mutability);
    721     return true;
    722 }
    723 
    724 bool ModuleParser::parseData()
     573    return { };
     574}
     575
     576auto ModuleParser::parseData() -> PartialResult
    725577{
    726578    uint32_t segmentCount;
    727     if (!m_module->memory)
    728         return false;
    729     if (!parseVarUInt32(segmentCount)
    730         || segmentCount == std::numeric_limits<uint32_t>::max()
    731         || !m_module->data.tryReserveCapacity(segmentCount))
    732         return false;
    733     if (verbose)
    734         dataLogLn("  segments: ", segmentCount);
     579    WASM_PARSER_FAIL_IF(!m_result.module->memory, "Data section cannot exist without a Memory section or Import");
     580    WASM_PARSER_FAIL_IF(!parseVarUInt32(segmentCount), "can't get Data section's count");
     581    WASM_PARSER_FAIL_IF(segmentCount == std::numeric_limits<uint32_t>::max(), "Data section's count is too big ", segmentCount);
     582    WASM_PARSER_FAIL_IF(!m_result.module->data.tryReserveCapacity(segmentCount), "can't allocate enough memory for Data section's ", segmentCount, " segments");
    735583
    736584    for (uint32_t segmentNumber = 0; segmentNumber < segmentCount; ++segmentNumber) {
    737         if (verbose)
    738             dataLogLn("  segment #", segmentNumber);
    739585        uint32_t index;
    740586        uint64_t offset;
    741587        uint8_t initOpcode;
    742588        uint32_t dataByteLength;
    743         if (!parseVarUInt32(index)
    744             || index)
    745             return false;
    746 
    747         if (!parseInitExpr(initOpcode, offset))
    748             return false;
    749 
    750         if (initOpcode != OpType::I32Const)
    751             return false;
    752 
    753         if (verbose)
    754             dataLogLn("    offset: ", offset);
    755 
    756         if (!parseVarUInt32(dataByteLength)
    757             || dataByteLength == std::numeric_limits<uint32_t>::max())
    758             return false;
    759         if (verbose)
    760             dataLogLn("    data bytes: ", dataByteLength);
     589
     590        WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get ", segmentNumber, "th Data segment's index");
     591        WASM_PARSER_FAIL_IF(index, segmentNumber, "th Data segment has non-zero index ", index);
     592        WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, offset));
     593        WASM_PARSER_FAIL_IF(initOpcode != OpType::I32Const, segmentNumber, "th Data segment has opcode ", initOpcode, " expected i32.const");
     594        WASM_PARSER_FAIL_IF(!parseVarUInt32(dataByteLength), "can't get ", segmentNumber, "th Data segment's data byte length");
     595        WASM_PARSER_FAIL_IF(dataByteLength == std::numeric_limits<uint32_t>::max(), segmentNumber, "th Data segment's data byte length is too big ", dataByteLength);
    761596
    762597        Segment* segment = Segment::make(offset, dataByteLength);
    763         if (!segment)
    764             return false;
    765         m_module->data.uncheckedAppend(Segment::makePtr(segment));
     598        WASM_PARSER_FAIL_IF(!segment, "can't allocate enough memory for ", segmentNumber, "th Data segment of size ", dataByteLength);
     599        m_result.module->data.uncheckedAppend(Segment::makePtr(segment));
    766600        for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) {
    767601            uint8_t byte;
    768             if (!parseUInt8(byte))
    769                 return false;
     602            WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", dataByte, "th data byte from ", segmentNumber, "th Data segment");
    770603            segment->byte(dataByte) = byte;
    771             if (verbose)
    772                 dataLogLn("    [", dataByte, "] = ", segment->byte(dataByte));
    773         }
    774     }
    775     return true;
     604        }
     605    }
     606    return { };
    776607}
    777608
  • trunk/Source/JavaScriptCore/wasm/WasmModuleParser.h

    r209830 r209880  
    3535namespace JSC { namespace Wasm {
    3636
    37 class ModuleParser : public Parser {
     37struct ModuleParserResult {
     38    std::unique_ptr<ModuleInformation> module;
     39    FunctionIndexSpace functionIndexSpace;
     40    Vector<FunctionLocationInBinary> functionLocationInBinary;
     41};
     42
     43class ModuleParser : public Parser<ModuleParserResult> {
    3844public:
    3945
     
    4854    }
    4955
    50     bool WARN_UNUSED_RETURN parse();
    51     bool WARN_UNUSED_RETURN failed() const { return m_failed; }
    52     const String& errorMessage() const
    53     {
    54         RELEASE_ASSERT(failed());
    55         return m_errorMessage;
    56     }
    57 
    58     std::unique_ptr<ModuleInformation>& moduleInformation()
    59     {
    60         RELEASE_ASSERT(!failed());
    61         return m_module;
    62     }
    63 
    64     FunctionIndexSpace& functionIndexSpace()
    65     {
    66         RELEASE_ASSERT(!failed());
    67         return m_functionIndexSpace;
    68     }
    69 
    70     Vector<FunctionLocationInBinary>& functionLocationInBinary()
    71     {
    72         RELEASE_ASSERT(!failed());
    73         return m_functionLocationInBinary;
    74     }
     56    Result WARN_UNUSED_RETURN parse();
    7557
    7658private:
    77     bool parseGlobalType(Global&);
    7859
    79 #define WASM_SECTION_DECLARE_PARSER(NAME, ID, DESCRIPTION) bool WARN_UNUSED_RETURN parse ## NAME();
     60#define WASM_SECTION_DECLARE_PARSER(NAME, ID, DESCRIPTION) PartialResult WARN_UNUSED_RETURN parse ## NAME();
    8061    FOR_EACH_WASM_SECTION(WASM_SECTION_DECLARE_PARSER)
    8162#undef WASM_SECTION_DECLARE_PARSER
    8263
    83     bool WARN_UNUSED_RETURN parseMemoryHelper(bool isImport);
    84     bool WARN_UNUSED_RETURN parseTableHelper(bool isImport);
    85     bool WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum);
    86     bool WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&);
     64    PartialResult WARN_UNUSED_RETURN parseGlobalType(Global&);
     65    PartialResult WARN_UNUSED_RETURN parseMemoryHelper(bool isImport);
     66    PartialResult WARN_UNUSED_RETURN parseTableHelper(bool isImport);
     67    PartialResult WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum);
     68    PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&);
    8769
    8870    VM* m_vm;
    89     std::unique_ptr<ModuleInformation> m_module;
    90     FunctionIndexSpace m_functionIndexSpace;
    91     Vector<FunctionLocationInBinary> m_functionLocationInBinary;
    92     bool m_failed { true };
     71    ModuleParserResult m_result;
    9372    bool m_hasTable { false };
    94     String m_errorMessage;
    9573};
    9674
  • trunk/Source/JavaScriptCore/wasm/WasmParser.h

    r209830 r209880  
    3333#include "WasmOps.h"
    3434#include "WasmSections.h"
     35#include <type_traits>
     36#include <wtf/Expected.h>
    3537#include <wtf/LEBDecoder.h>
    3638#include <wtf/StdLibExtras.h>
     
    3941namespace JSC { namespace Wasm {
    4042
     43namespace FailureHelper {
     44// 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.
     45static inline auto makeString(const char *failure) { return ASCIILiteral(failure); }
     46template <typename Int, typename = typename std::enable_if<std::is_integral<Int>::value>::type>
     47static inline auto makeString(Int failure) { return String::number(failure); }
     48}
     49
     50template<typename SuccessType>
    4151class Parser {
     52public:
     53    typedef String ErrorType;
     54    typedef UnexpectedType<ErrorType> UnexpectedResult;
     55    typedef Expected<void, ErrorType> PartialResult;
     56    typedef Expected<SuccessType, ErrorType> Result;
     57
    4258protected:
    4359    Parser(const uint8_t*, size_t);
     
    6177    bool WARN_UNUSED_RETURN parseResultType(Type&);
    6278    bool WARN_UNUSED_RETURN parseValueType(Type&);
    63     bool WARN_UNUSED_RETURN parseExternalKind(External::Kind&);
     79    bool WARN_UNUSED_RETURN parseExternalKind(ExternalKind&);
    6480
    6581    const uint8_t* source() const { return m_source; }
     
    6783
    6884    size_t m_offset = 0;
     85
     86    template <typename ...Args>
     87    NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const
     88    {
     89        using namespace FailureHelper; // See ADL comment in namespace above.
     90        return UnexpectedResult(makeString(ASCIILiteral("WebAssembly.Module doesn't parse at byte "), String::number(m_offset), ASCIILiteral(" / "), String::number(m_sourceLength), ASCIILiteral(": "), makeString(args)...));
     91    }
     92#define WASM_PARSER_FAIL_IF(condition, ...) do { \
     93    if (UNLIKELY(condition))                     \
     94        return fail(__VA_ARGS__);                \
     95    } while (0)
     96
     97#define WASM_FAIL_IF_HELPER_FAILS(helper) do {   \
     98        auto helperResult = helper;              \
     99        if (UNLIKELY(!helperResult))             \
     100            return helperResult.getUnexpected(); \
     101    } while (0)
    69102
    70103private:
     
    73106};
    74107
    75 ALWAYS_INLINE Parser::Parser(const uint8_t* sourceBuffer, size_t sourceLength)
     108template<typename SuccessType>
     109ALWAYS_INLINE Parser<SuccessType>::Parser(const uint8_t* sourceBuffer, size_t sourceLength)
    76110    : m_source(sourceBuffer)
    77111    , m_sourceLength(sourceLength)
     
    79113}
    80114
    81 ALWAYS_INLINE bool Parser::consumeCharacter(char c)
     115template<typename SuccessType>
     116ALWAYS_INLINE bool Parser<SuccessType>::consumeCharacter(char c)
    82117{
    83118    if (m_offset >= length())
     
    90125}
    91126
    92 ALWAYS_INLINE bool Parser::consumeString(const char* str)
     127template<typename SuccessType>
     128ALWAYS_INLINE bool Parser<SuccessType>::consumeString(const char* str)
    93129{
    94130    unsigned start = m_offset;
     
    104140}
    105141
    106 ALWAYS_INLINE bool Parser::consumeUTF8String(String& result, size_t stringLength)
     142template<typename SuccessType>
     143ALWAYS_INLINE bool Parser<SuccessType>::consumeUTF8String(String& result, size_t stringLength)
    107144{
    108145    if (stringLength == 0) {
     
    119156}
    120157
    121 ALWAYS_INLINE bool Parser::parseVarUInt32(uint32_t& result)
     158template<typename SuccessType>
     159ALWAYS_INLINE bool Parser<SuccessType>::parseVarUInt32(uint32_t& result)
    122160{
    123161    return WTF::LEBDecoder::decodeUInt32(m_source, m_sourceLength, m_offset, result);
    124162}
    125163
    126 ALWAYS_INLINE bool Parser::parseVarUInt64(uint64_t& result)
     164template<typename SuccessType>
     165ALWAYS_INLINE bool Parser<SuccessType>::parseVarUInt64(uint64_t& result)
    127166{
    128167    return WTF::LEBDecoder::decodeUInt64(m_source, m_sourceLength, m_offset, result);
    129168}
    130169
    131 ALWAYS_INLINE bool Parser::parseVarInt32(int32_t& result)
     170template<typename SuccessType>
     171ALWAYS_INLINE bool Parser<SuccessType>::parseVarInt32(int32_t& result)
    132172{
    133173    return WTF::LEBDecoder::decodeInt32(m_source, m_sourceLength, m_offset, result);
    134174}
    135175
    136 ALWAYS_INLINE bool Parser::parseVarInt64(int64_t& result)
     176template<typename SuccessType>
     177ALWAYS_INLINE bool Parser<SuccessType>::parseVarInt64(int64_t& result)
    137178{
    138179    return WTF::LEBDecoder::decodeInt64(m_source, m_sourceLength, m_offset, result);
    139180}
    140181
    141 ALWAYS_INLINE bool Parser::parseUInt32(uint32_t& result)
     182template<typename SuccessType>
     183ALWAYS_INLINE bool Parser<SuccessType>::parseUInt32(uint32_t& result)
    142184{
    143185    if (length() < 4 || m_offset > length() - 4)
     
    148190}
    149191
    150 ALWAYS_INLINE bool Parser::parseUInt64(uint64_t& result)
     192template<typename SuccessType>
     193ALWAYS_INLINE bool Parser<SuccessType>::parseUInt64(uint64_t& result)
    151194{
    152195    if (length() < 8 || m_offset > length() - 8)
     
    157200}
    158201
    159 ALWAYS_INLINE bool Parser::parseUInt8(uint8_t& result)
     202template<typename SuccessType>
     203ALWAYS_INLINE bool Parser<SuccessType>::parseUInt8(uint8_t& result)
    160204{
    161205    if (m_offset >= length())
     
    165209}
    166210
    167 ALWAYS_INLINE bool Parser::parseInt7(int8_t& result)
     211template<typename SuccessType>
     212ALWAYS_INLINE bool Parser<SuccessType>::parseInt7(int8_t& result)
    168213{
    169214    if (m_offset >= length())
     
    174219}
    175220
    176 ALWAYS_INLINE bool Parser::parseUInt7(uint8_t& result)
     221template<typename SuccessType>
     222ALWAYS_INLINE bool Parser<SuccessType>::parseUInt7(uint8_t& result)
    177223{
    178224    if (m_offset >= length())
     
    182228}
    183229
    184 ALWAYS_INLINE bool Parser::parseVarUInt1(uint8_t& result)
     230template<typename SuccessType>
     231ALWAYS_INLINE bool Parser<SuccessType>::parseVarUInt1(uint8_t& result)
    185232{
    186233    uint32_t temp;
     
    191238}
    192239
    193 ALWAYS_INLINE bool Parser::parseResultType(Type& result)
     240template<typename SuccessType>
     241ALWAYS_INLINE bool Parser<SuccessType>::parseResultType(Type& result)
    194242{
    195243    int8_t value;
     
    202250}
    203251
    204 ALWAYS_INLINE bool Parser::parseValueType(Type& result)
     252template<typename SuccessType>
     253ALWAYS_INLINE bool Parser<SuccessType>::parseValueType(Type& result)
    205254{
    206255    return parseResultType(result) && isValueType(result);
    207256}
    208    
    209 ALWAYS_INLINE bool Parser::parseExternalKind(External::Kind& result)
     257
     258template<typename SuccessType>
     259ALWAYS_INLINE bool Parser<SuccessType>::parseExternalKind(ExternalKind& result)
    210260{
    211261    uint8_t value;
    212262    if (!parseUInt7(value))
    213263        return false;
    214     if (!External::isValid(value))
    215         return false;
    216     result = static_cast<External::Kind>(value);
     264    if (!isValidExternalKind(value))
     265        return false;
     266    result = static_cast<ExternalKind>(value);
    217267    return true;
    218268}
  • trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp

    r209696 r209880  
    6161void Plan::run()
    6262{
    63     if (verbose)
    64         dataLogLn("Starting plan.");
    6563    {
    6664        ModuleParser moduleParser(m_vm, m_source, m_sourceLength);
    67         if (!moduleParser.parse()) {
    68             if (verbose)
    69                 dataLogLn("Parsing module failed: ", moduleParser.errorMessage());
    70             m_errorMessage = moduleParser.errorMessage();
    71             return;
     65        auto parseResult = moduleParser.parse();
     66        if (!parseResult) {
     67            m_errorMessage = parseResult.error();
     68            return; // FIXME return an Expected.
    7269        }
    73         m_moduleInformation = WTFMove(moduleParser.moduleInformation());
    74         m_functionLocationInBinary = WTFMove(moduleParser.functionLocationInBinary());
    75         m_functionIndexSpace.size = moduleParser.functionIndexSpace().size();
    76         m_functionIndexSpace.buffer = moduleParser.functionIndexSpace().releaseBuffer();
     70        m_moduleInformation = WTFMove(parseResult->module);
     71        m_functionLocationInBinary = WTFMove(parseResult->functionLocationInBinary);
     72        m_functionIndexSpace.size = parseResult->functionIndexSpace.size();
     73        m_functionIndexSpace.buffer = parseResult->functionIndexSpace.releaseBuffer();
    7774    }
    78     if (verbose)
    79         dataLogLn("Parsed module.");
    8075
    8176    auto tryReserveCapacity = [this] (auto& vector, size_t size, const char* what) {
     
    9893    for (unsigned importIndex = 0; importIndex < m_moduleInformation->imports.size(); ++importIndex) {
    9994        Import* import = &m_moduleInformation->imports[importIndex];
    100         if (import->kind != External::Function)
     95        if (import->kind != ExternalKind::Function)
    10196            continue;
    10297        unsigned importFunctionIndex = m_wasmToJSStubs.size();
     
    118113        ASSERT(m_functionIndexSpace.buffer.get()[functionIndexSpace].signature == signature);
    119114
    120         String error = validateFunction(functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation);
    121         if (!error.isNull()) {
     115        auto validateResult = validateFunction(functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation);
     116        if (!validateResult) {
    122117            if (verbose) {
    123118                for (unsigned i = 0; i < functionLength; ++i)
     
    125120                dataLogLn();
    126121            }
    127             m_errorMessage = error;
     122            m_errorMessage = validateResult.error(); // FIXME make this an Expected.
    128123            return;
    129124        }
    130125
    131126        unlinkedWasmToWasmCalls.uncheckedAppend(Vector<UnlinkedWasmToWasmCall>());
    132         m_wasmInternalFunctions.uncheckedAppend(parseAndCompile(*m_vm, functionStart, functionLength, signature, unlinkedWasmToWasmCalls.at(functionIndex), m_functionIndexSpace, *m_moduleInformation));
     127        auto parseAndCompileResult = parseAndCompile(*m_vm, functionStart, functionLength, signature, unlinkedWasmToWasmCalls.at(functionIndex), m_functionIndexSpace, *m_moduleInformation);
     128        if (UNLIKELY(!parseAndCompileResult)) {
     129            m_errorMessage = parseAndCompileResult.error();
     130            return; // FIXME make this an Expected.
     131        }
     132        m_wasmInternalFunctions.uncheckedAppend(WTFMove(*parseAndCompileResult));
    133133        m_functionIndexSpace.buffer.get()[functionIndexSpace].code = m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation->code().executableAddress();
    134134    }
  • trunk/Source/JavaScriptCore/wasm/WasmSections.h

    r208401 r209880  
    4343    macro(Data,    11, "Data segments")
    4444
    45 struct Sections {
    46     enum Section : uint8_t {
     45enum class Section : uint8_t {
    4746#define DEFINE_WASM_SECTION_ENUM(NAME, ID, DESCRIPTION) NAME = ID,
    48         FOR_EACH_WASM_SECTION(DEFINE_WASM_SECTION_ENUM)
     47    FOR_EACH_WASM_SECTION(DEFINE_WASM_SECTION_ENUM)
    4948#undef DEFINE_WASM_SECTION_ENUM
    50         Unknown
    51     };
    52     static bool validateOrder(Section previous, Section next)
    53     {
    54         if (previous == Unknown)
    55             return true;
    56         return previous < next;
     49    Unknown
     50};
     51
     52template<typename Int>
     53static inline bool isValidSection(Int section)
     54{
     55    switch (section) {
     56#define VALIDATE_SECTION(NAME, ID, DESCRIPTION) case static_cast<Int>(Section::NAME): return true;
     57        FOR_EACH_WASM_SECTION(VALIDATE_SECTION)
     58#undef VALIDATE_SECTION
     59    default:
     60        return false;
    5761    }
    58 };
     62}
     63
     64static inline bool validateOrder(Section previous, Section next)
     65{
     66    if (previous == Section::Unknown)
     67        return true;
     68    return static_cast<uint8_t>(previous) < static_cast<uint8_t>(next);
     69}
     70
     71static inline const char* makeString(Section section)
     72{
     73    switch (section) {
     74#define STRINGIFY_SECTION_NAME(NAME, ID, DESCRIPTION) case Section::NAME: return #NAME;
     75        FOR_EACH_WASM_SECTION(STRINGIFY_SECTION_NAME)
     76#undef STRINGIFY_SECTION_NAME
     77    default:
     78        RELEASE_ASSERT_NOT_REACHED();
     79        return "?";
     80    }
     81}
    5982
    6083} } // namespace JSC::Wasm
  • trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp

    r209850 r209880  
    7272        Type m_signature;
    7373    };
     74    typedef String ErrorType;
     75    typedef UnexpectedType<ErrorType> UnexpectedResult;
     76    typedef Expected<void, ErrorType> Result;
    7477    typedef Type ExpressionType;
    7578    typedef ControlData ControlType;
     
    7982    static const ExpressionType emptyExpression = Void;
    8083
    81     bool WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
    82     bool WARN_UNUSED_RETURN addLocal(Type, uint32_t);
     84    template <typename ...Args>
     85    NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const
     86    {
     87        using namespace FailureHelper; // See ADL comment in WasmParser.h.
     88        return UnexpectedResult(makeString(ASCIILiteral("WebAssembly.Module doesn't validate: "), makeString(args)...));
     89    }
     90#define WASM_VALIDATOR_FAIL_IF(condition, ...) do { \
     91        if (UNLIKELY(condition))                    \
     92        return fail(__VA_ARGS__);                   \
     93    } while (0)
     94
     95    Result WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
     96    Result WARN_UNUSED_RETURN addLocal(Type, uint32_t);
    8397    ExpressionType addConstant(Type type, uint64_t) { return type; }
    8498
    8599    // Locals
    86     bool WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
    87     bool WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
     100    Result WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
     101    Result WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
    88102
    89103    // Globals
    90     bool WARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result);
    91     bool WARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value);
     104    Result WARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result);
     105    Result WARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value);
    92106
    93107    // Memory
    94     bool WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
    95     bool WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
     108    Result WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
     109    Result WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
    96110
    97111    // Basic operators
    98112    template<OpType>
    99     bool WARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result);
     113    Result WARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result);
    100114    template<OpType>
    101     bool WARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result);
    102     bool WARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result);
     115    Result WARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result);
     116    Result WARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result);
    103117
    104118    // Control flow
    105119    ControlData WARN_UNUSED_RETURN addBlock(Type signature);
    106120    ControlData WARN_UNUSED_RETURN addLoop(Type signature);
    107     bool WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);
    108     bool WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);
    109     bool WARN_UNUSED_RETURN addElseToUnreachable(ControlData&);
    110 
    111     bool WARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues);
    112     bool WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& expressionStack);
    113     bool WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack);
    114     bool WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);
    115     bool WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);
    116 
    117     void addUnreachable() { }
     121    Result WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);
     122    Result WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);
     123    Result WARN_UNUSED_RETURN addElseToUnreachable(ControlData&);
     124
     125    Result WARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues);
     126    Result WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& expressionStack);
     127    Result WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack);
     128    Result WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);
     129    Result WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);
     130
     131    Result WARN_UNUSED_RETURN addUnreachable() { return { }; }
    118132
    119133    // Calls
    120     bool WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature*, const Vector<ExpressionType>& args, ExpressionType& result);
    121     bool WARN_UNUSED_RETURN addCallIndirect(const Signature*, const Vector<ExpressionType>& args, ExpressionType& result);
    122 
    123     void dump(const Vector<ControlEntry>& controlStack, const ExpressionList& expressionStack);
     134    Result WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature*, const Vector<ExpressionType>& args, ExpressionType& result);
     135    Result WARN_UNUSED_RETURN addCallIndirect(const Signature*, const Vector<ExpressionType>& args, ExpressionType& result);
    124136
    125137    bool hasMemory() const { return !!m_module.memory; }
    126138
    127     void setErrorMessage(String&& message) { ASSERT(m_errorMessage.isNull()); m_errorMessage = WTFMove(message); }
    128     String errorMessage() const { return m_errorMessage; }
    129139    Validate(ExpressionType returnType, const ModuleInformation& module)
    130140        : m_returnType(returnType)
     
    133143    }
    134144
     145    void dump(const Vector<ControlEntry>&, const ExpressionList&);
     146
    135147private:
    136     bool unify(Type, Type);
    137     bool unify(const ExpressionList&, const ControlData&);
    138 
    139     bool checkBranchTarget(ControlData& target, const ExpressionList& expressionStack);
     148    Result unify(Type, Type);
     149    Result unify(const ExpressionList&, const ControlData&);
     150
     151    Result checkBranchTarget(ControlData& target, const ExpressionList& expressionStack);
    140152
    141153    ExpressionType m_returnType;
    142154    Vector<Type> m_locals;
    143     String m_errorMessage;
    144155    const ModuleInformation& m_module;
    145156};
    146157
    147 bool Validate::addArguments(const Vector<Type>& args)
    148 {
    149     for (Type arg : args) {
    150         if (!addLocal(arg, 1))
    151             return false;
    152     }
    153     return true;
    154 }
    155 
    156 bool Validate::addLocal(Type type, uint32_t count)
    157 {
    158     if (!m_locals.tryReserveCapacity(m_locals.size() + count))
    159         return false;
     158auto Validate::addArguments(const Vector<Type>& args) -> Result
     159{
     160    for (Type arg : args)
     161        WASM_FAIL_IF_HELPER_FAILS(addLocal(arg, 1));
     162    return { };
     163}
     164
     165auto Validate::addLocal(Type type, uint32_t count) -> Result
     166{
     167    size_t size = m_locals.size() + count;
     168    WASM_VALIDATOR_FAIL_IF(!m_locals.tryReserveCapacity(size), "can't allocate memory for ", size, " locals");
    160169
    161170    for (uint32_t i = 0; i < count; ++i)
    162171        m_locals.uncheckedAppend(type);
    163     return true;
    164 }
    165 
    166 bool Validate::getLocal(uint32_t index, ExpressionType& result)
    167 {
    168     if (index < m_locals.size()) {
    169         result = m_locals[index];
    170         return true;
    171     }
    172     m_errorMessage = ASCIILiteral("Attempt to use unknown local.");
    173     return false;
    174 }
    175 
    176 bool Validate::setLocal(uint32_t index, ExpressionType value)
     172    return { };
     173}
     174
     175auto Validate::getLocal(uint32_t index, ExpressionType& result) -> Result
     176{
     177    WASM_VALIDATOR_FAIL_IF(index >= m_locals.size(), "attempt to use unknown local ", index, " last one is ", m_locals.size());
     178    result = m_locals[index];
     179    return { };
     180}
     181
     182auto Validate::setLocal(uint32_t index, ExpressionType value) -> Result
    177183{
    178184    ExpressionType localType;
    179     if (!getLocal(index, localType))
    180         return false;
    181 
    182     if (localType == value)
    183         return true;
    184 
    185     m_errorMessage = makeString("Attempt to set local with type: ", toString(localType), " with a variable of type: ", toString(value));
    186     return false;
    187 }
    188 
    189 bool Validate::getGlobal(uint32_t index, ExpressionType& result)
    190 {
    191     if (index < m_module.globals.size()) {
    192         result = m_module.globals[index].type;
    193         ASSERT(isValueType(result));
    194         return true;
    195     }
    196     m_errorMessage = ASCIILiteral("Attempt to use unknown global.");
    197     return false;
    198 }
    199 
    200 bool Validate::setGlobal(uint32_t index, ExpressionType value)
    201 {
    202     if (index >= m_module.globals.size()) {
    203         m_errorMessage = ASCIILiteral("Attempt to use unknown global.");
    204         return false;
    205     }
    206 
    207     if (m_module.globals[index].mutability == Global::Immutable) {
    208         m_errorMessage = ASCIILiteral("Attempt to store to immutable global.");
    209         return false;
    210     }
     185    WASM_FAIL_IF_HELPER_FAILS(getLocal(index, localType));
     186    WASM_VALIDATOR_FAIL_IF(localType != value, "set_local to type ", value, " expected ", localType);
     187    return { };
     188}
     189
     190auto Validate::getGlobal(uint32_t index, ExpressionType& result) -> Result
     191{
     192    WASM_VALIDATOR_FAIL_IF(index >= m_module.globals.size(), "get_global ", index, " of unknown global, limit is ", m_module.globals.size());
     193    result = m_module.globals[index].type;
     194    ASSERT(isValueType(result));
     195    return { };
     196}
     197
     198auto Validate::setGlobal(uint32_t index, ExpressionType value) -> Result
     199{
     200    WASM_VALIDATOR_FAIL_IF(index >= m_module.globals.size(), "set_global ", index, " of unknown global, limit is ", m_module.globals.size());
     201    WASM_VALIDATOR_FAIL_IF(m_module.globals[index].mutability == Global::Immutable, "set_global ", index, " is immutable");
    211202
    212203    ExpressionType globalType = m_module.globals[index].type;
    213204    ASSERT(isValueType(globalType));
    214     if (globalType == value)
    215         return true;
    216 
    217     m_errorMessage = makeString("Attempt to set global with type: ", toString(globalType), " with a variable of type: ", toString(value));
    218     return false;
     205    WASM_VALIDATOR_FAIL_IF(globalType != value, "set_global ", index, " with type ", globalType, " with a variable of type ", value);
     206    return { };
    219207}
    220208
     
    229217}
    230218
    231 bool Validate::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result)
    232 {
    233     if (condition != I32) {
    234         m_errorMessage = makeString("Attempting to use ", toString(condition), " as the condition for select");
    235         return false;
    236     }
    237 
    238     if (nonZero != zero) {
    239         m_errorMessage = makeString("Result types of select don't match. Got: ", toString(nonZero), " and ", toString(zero));
    240         return false;
    241     }
    242 
     219auto Validate::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result) -> Result
     220{
     221    WASM_VALIDATOR_FAIL_IF(condition != I32, "select condition must be i32, got ", condition);
     222    WASM_VALIDATOR_FAIL_IF(nonZero != zero, "select result types must match, got ", nonZero, " and ", zero);
    243223    result = zero;
    244     return true;
    245 }
    246 
    247 bool Validate::addIf(ExpressionType condition, Type signature, ControlType& result)
    248 {
    249     if (condition != I32) {
    250         m_errorMessage = makeString("Attempting to use ", toString(condition), " as the condition for an if block");
    251         return false;
    252     }
     224    return { };
     225}
     226
     227auto Validate::addIf(ExpressionType condition, Type signature, ControlType& result) -> Result
     228{
     229    WASM_VALIDATOR_FAIL_IF(condition != I32, "if condition must be i32, got ", condition);
    253230    result = ControlData(BlockType::If, signature);
    254     return true;
    255 }
    256 
    257 bool Validate::addElse(ControlType& current, const ExpressionList& values)
    258 {
    259     if (!unify(values, current)) {
    260         ASSERT(errorMessage());
    261         return false;
    262     }
    263 
     231    return { };
     232}
     233
     234auto Validate::addElse(ControlType& current, const ExpressionList& values) -> Result
     235{
     236    WASM_FAIL_IF_HELPER_FAILS(unify(values, current));
    264237    return addElseToUnreachable(current);
    265238}
    266239
    267 bool Validate::addElseToUnreachable(ControlType& current)
    268 {
    269     if (current.type() != BlockType::If) {
    270         m_errorMessage = makeString("Attempting to add else block to something other than an if");
    271         return false;
    272     }
    273 
     240auto Validate::addElseToUnreachable(ControlType& current) -> Result
     241{
     242    WASM_VALIDATOR_FAIL_IF(current.type() != BlockType::If, "else block isn't associated to an if");
    274243    current = ControlData(BlockType::Block, current.signature());
    275     return true;
    276 }
    277 
    278 bool Validate::addReturn(const ExpressionList& returnValues)
     244    return { };
     245}
     246
     247auto Validate::addReturn(const ExpressionList& returnValues) -> Result
    279248{
    280249    if (m_returnType == Void)
    281         return true;
     250        return { };
    282251    ASSERT(returnValues.size() == 1);
    283 
    284     if (m_returnType == returnValues[0])
    285         return true;
    286 
    287     m_errorMessage = makeString("Attempting to add return with type: ", toString(returnValues[0]), " but function expects return with type: ", toString(m_returnType));
    288     return false;
    289 }
    290 
    291 bool Validate::checkBranchTarget(ControlType& target, const ExpressionList& expressionStack)
     252    WASM_VALIDATOR_FAIL_IF(m_returnType != returnValues[0], "return type ", returnValues[0], " doesn't match function's return type ", m_returnType);
     253    return { };
     254}
     255
     256auto Validate::checkBranchTarget(ControlType& target, const ExpressionList& expressionStack) -> Result
    292257    {
    293258        if (target.type() == BlockType::Loop)
    294             return true;
     259            return { };
    295260
    296261        if (target.signature() == Void)
    297             return true;
    298 
    299         if (!expressionStack.size()) {
    300             m_errorMessage = makeString("Attempting to branch to block with expected type: ", toString(target.signature()), " but the stack was empty");
    301             return false;
    302         }
    303 
    304         if (target.signature() == expressionStack.last())
    305             return true;
    306 
    307         m_errorMessage = makeString("Attempting to branch to block with expected type: ", toString(target.signature()), " but stack has type: ", toString(target.signature()));
    308         return false;
     262            return { };
     263
     264        WASM_VALIDATOR_FAIL_IF(expressionStack.isEmpty(), "branch to block on empty expression stack");
     265        WASM_VALIDATOR_FAIL_IF(target.signature() != expressionStack.last(), "branch's stack type doesn't match block's type");
     266
     267        return { };
    309268    }
    310269
    311 bool Validate::addBranch(ControlType& target, ExpressionType condition, const ExpressionList& stack)
     270auto Validate::addBranch(ControlType& target, ExpressionType condition, const ExpressionList& stack) -> Result
    312271{
    313272    // Void means this is an unconditional branch.
    314     if (condition != Void && condition != I32) {
    315         m_errorMessage = makeString("Attempting to add a conditional branch with condition type: ", toString(condition), " but expected i32.");
    316         return false;
    317     }
    318 
     273    WASM_VALIDATOR_FAIL_IF(condition != Void && condition != I32, "conditional branch with non-i32 condition ", condition);
    319274    return checkBranchTarget(target, stack);
    320275}
    321276
    322 bool Validate::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack)
    323 {
    324     if (condition != I32) {
    325         m_errorMessage = makeString("Attempting to add a br_table with condition type: ", toString(condition), " but expected i32.");
    326         return false;
    327     }
    328 
    329     for (auto target : targets) {
    330         if (defaultTarget.signature() != target->signature()) {
    331             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()));
    332             return false;
    333         }
    334     }
     277auto Validate::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack) -> Result
     278{
     279    WASM_VALIDATOR_FAIL_IF(condition != I32, "br_table with non-i32 condition ", condition);
     280
     281    for (auto target : targets)
     282        WASM_VALIDATOR_FAIL_IF(defaultTarget.signature() != target->signature(), "br_table target type mismatch");
    335283
    336284    return checkBranchTarget(defaultTarget, expressionStack);
    337285}
    338286
    339 bool Validate::endBlock(ControlEntry& entry, ExpressionList& stack)
     287auto Validate::endBlock(ControlEntry& entry, ExpressionList& stack) -> Result
    340288{
    341289    ControlData& block = entry.controlData;
    342290    if (block.signature() == Void)
    343         return true;
    344 
    345     if (!stack.size()) {
    346         m_errorMessage = makeString("Block fallthough expected type: ", toString(block.signature()), " but the stack was empty");
    347         return false;
    348     }
    349 
    350     if (block.signature() == stack.last()) {
    351         entry.enclosedExpressionStack.append(block.signature());
    352         return true;
    353     }
    354 
    355     m_errorMessage = makeString("Block fallthrough has expected type: ", toString(block.signature()), " but produced type: ", toString(block.signature()));
    356     return false;
    357 }
    358 
    359 bool Validate::addEndToUnreachable(ControlEntry& entry)
     291        return { };
     292
     293    WASM_VALIDATOR_FAIL_IF(stack.isEmpty(), "typed block falls through on empty stack");
     294    WASM_VALIDATOR_FAIL_IF(block.signature() != stack.last(), "block fallthrough doesn't match its declared type");
     295
     296    entry.enclosedExpressionStack.append(block.signature());
     297    return { };
     298}
     299
     300auto Validate::addEndToUnreachable(ControlEntry& entry) -> Result
    360301{
    361302    if (entry.controlData.signature() != Void)
    362303        entry.enclosedExpressionStack.append(entry.controlData.signature());
    363     return true;
    364 }
    365 
    366 bool Validate::addCall(unsigned, const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result)
    367 {
    368     if (signature->arguments.size() != args.size()) {
    369         StringBuilder builder;
    370         builder.append("Arity mismatch in call, expected: ");
    371         builder.appendNumber(signature->arguments.size());
    372         builder.append(" but got: ");
    373         builder.appendNumber(args.size());
    374         m_errorMessage = builder.toString();
    375         return false;
    376     }
    377 
    378     for (unsigned i = 0; i < args.size(); ++i) {
    379         if (args[i] != signature->arguments[i]) {
    380             m_errorMessage = makeString("Expected argument type: ", toString(signature->arguments[i]), " does not match passed argument type: ", toString(args[i]));
    381             return false;
    382         }
    383     }
     304    return { };
     305}
     306
     307auto Validate::addCall(unsigned, const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
     308{
     309    WASM_VALIDATOR_FAIL_IF(signature->arguments.size() != args.size(), "arity mismatch in call, got ", args.size(), " arguments, expected ", signature->arguments.size());
     310
     311    for (unsigned i = 0; i < args.size(); ++i)
     312        WASM_VALIDATOR_FAIL_IF(args[i] != signature->arguments[i], "argument type mismatch in call, got ", args[i], ", expected ", signature->arguments[i]);
    384313
    385314    result = signature->returnType;
    386     return true;
    387 }
    388 
    389 bool Validate::addCallIndirect(const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result)
     315    return { };
     316}
     317
     318auto Validate::addCallIndirect(const Signature* signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
    390319{
    391320    const auto argumentCount = signature->arguments.size();
    392     if (argumentCount != args.size() - 1) {
    393         StringBuilder builder;
    394         builder.append("Arity mismatch in call_indirect, expected: ");
    395         builder.appendNumber(signature->arguments.size());
    396         builder.append(" but got: ");
    397         builder.appendNumber(args.size());
    398         m_errorMessage = builder.toString();
    399         return false;
    400     }
    401 
    402     for (unsigned i = 0; i < argumentCount; ++i) {
    403         if (args[i] != signature->arguments[i]) {
    404             m_errorMessage = makeString("Expected argument type: ", toString(signature->arguments[i]), " does not match passed argument type: ", toString(args[i]));
    405             return false;
    406         }
    407     }
    408 
    409     if (args.last() != I32) {
    410         m_errorMessage = makeString("Expected call_indirect target index to have type: i32 but got type: ", toString(args.last()));
    411         return false;
    412     }
    413    
     321    WASM_VALIDATOR_FAIL_IF(argumentCount != args.size() - 1, "arity mismatch in call_indirect, got ", args.size() - 1, " arguments, expected ", argumentCount);
     322
     323    for (unsigned i = 0; i < argumentCount; ++i)
     324        WASM_VALIDATOR_FAIL_IF(args[i] != signature->arguments[i], "argument type mismatch in call_indirect, got ", args[i], ", expected ", signature->arguments[i]);
     325
     326    WASM_VALIDATOR_FAIL_IF(args.last() != I32, "non-i32 call_indirect index ", args.last());
     327
    414328    result = signature->returnType;
    415     return true;
    416 }
    417 
    418 bool Validate::unify(const ExpressionList& values, const ControlType& block)
     329    return { };
     330}
     331
     332auto Validate::unify(const ExpressionList& values, const ControlType& block) -> Result
    419333{
    420334    ASSERT(values.size() <= 1);
    421335    if (block.signature() == Void)
    422         return true;
    423 
    424     if (!values.size()) {
    425         m_errorMessage = makeString("Block has non-void signature but has no stack entries on exit");
    426         return false;
    427     }
    428 
    429     if (values[0] == block.signature())
    430         return true;
    431 
    432     m_errorMessage = makeString("Expected control flow to return value with type: ", toString(block.signature()), " but got value with type: ", toString(values[0]));
    433     return false;
     336        return { };
     337
     338    WASM_VALIDATOR_FAIL_IF(values.isEmpty(), "non-void block ends with an empty stack");
     339    WASM_VALIDATOR_FAIL_IF(values[0] != block.signature(), "control flow returns with unexpected type");
     340
     341    return { };
    434342}
    435343
     
    440348}
    441349
    442 String validateFunction(const uint8_t* source, size_t length, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& module)
     350Expected<void, String> validateFunction(const uint8_t* source, size_t length, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& module)
    443351{
    444352    Validate context(signature->returnType, module);
    445353    FunctionParser<Validate> validator(context, source, length, signature, functionIndexSpace, module);
    446 
    447     if (!validator.parse()) {
    448         // FIXME: add better location information here. see: https://bugs.webkit.org/show_bug.cgi?id=164288
    449         // FIXME: We should never not have an error message if we return false.
    450         // see: https://bugs.webkit.org/show_bug.cgi?id=164354
    451         if (context.errorMessage().isNull())
    452             return "Unknown error";
    453         return context.errorMessage();
    454     }
    455 
    456     return String();
     354    WASM_FAIL_IF_HELPER_FAILS(validator.parse());
     355    return { };
    457356}
    458357
  • trunk/Source/JavaScriptCore/wasm/WasmValidate.h

    r209652 r209880  
    2929
    3030#include "WasmFormat.h"
     31#include <wtf/Expected.h>
    3132
    3233namespace JSC { namespace Wasm {
    3334
    34 String validateFunction(const uint8_t*, size_t, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);
     35Expected<void, String> validateFunction(const uint8_t*, size_t, const Signature*, const ImmutableFunctionIndexSpace&, const ModuleInformation&);
    3536
    3637} } // namespace JSC::Wasm
  • trunk/Source/JavaScriptCore/wasm/generateWasmB3IRGeneratorInlinesHeader.py

    r209301 r209880  
    190190    args.append("ExpressionType& result")
    191191    return """
    192 template<> bool B3IRGenerator::addOp<OpType::""" + wasm.toCpp(op["name"]) + ">(" + ", ".join(args) + """)
     192template<> auto B3IRGenerator::addOp<OpType::""" + wasm.toCpp(op["name"]) + ">(" + ", ".join(args) + """) -> PartialResult
    193193{
    194194""" + generateB3Code(opcode, b3op) + """;
    195     return true;
     195    return { };
    196196}
    197197"""
  • trunk/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py

    r209830 r209880  
    152152
    153153#define CREATE_CASE(name, id, b3type, inc) case name: return #name;
    154 inline const char* toString(Type type)
     154inline const char* makeString(Type type)
    155155{
    156156    switch (type) {
  • trunk/Source/JavaScriptCore/wasm/generateWasmValidateInlinesHeader.py

    r209630 r209880  
    6161    op = opcodes[name]
    6262    return """
    63 template<> bool Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType value, ExpressionType& result)
     63template<> auto Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType value, ExpressionType& result) -> Result
    6464{
    65     if (value != """ + cppType(op["parameter"][0]) + """) {
    66         m_errorMessage = makeString(\"""" + name + """ expects the value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(value));
    67         return false;
    68     }
     65    if (UNLIKELY(value != """ + cppType(op["parameter"][0]) + """))
     66        return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ value type mismatch");
    6967
    7068    result = """ + cppType(op["return"][0]) + """;
    71     return true;
     69    return { };
    7270}
    7371"""
     
    7775    op = opcodes[name]
    7876    return """
    79 template<> bool Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType left, ExpressionType right, ExpressionType& result)
     77template<> auto Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType left, ExpressionType right, ExpressionType& result) -> Result
    8078{
    81     if (left != """ + cppType(op["parameter"][0]) + """) {
    82         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));
    83         return false;
    84     }
     79    if (UNLIKELY(left != """ + cppType(op["parameter"][0]) + """))
     80        return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ left value type mismatch");
    8581
    86     if (right != """ + cppType(op["parameter"][1]) + """) {
    87         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));
    88         return false;
    89     }
     82    if (UNLIKELY(right != """ + cppType(op["parameter"][1]) + """))
     83        return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ right value type mismatch");
    9084
    9185    result = """ + cppType(op["return"][0]) + """;
    92     return true;
     86    return { };
    9387}
    9488"""
     
    9892    return """
    9993    case LoadOpType::""" + toCpp(name) + """: {
    100         if (pointer != """ + cppType(op["parameter"][0]) + """) {
    101             m_errorMessage = makeString(\"""" + name + """ expects the pointer to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(pointer));
    102             return false;
    103         }
     94        if (UNLIKELY(pointer != """ + cppType(op["parameter"][0]) + """))
     95            return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ pointer type mismatch");
    10496
    10597        result = """ + cppType(op["return"][0]) + """;
    106         return true;
     98        return { };
    10799    }"""
    108100
     
    112104    return """
    113105    case StoreOpType::""" + toCpp(name) + """: {
    114         if (pointer != """ + cppType(op["parameter"][0]) + """) {
    115             m_errorMessage = makeString(\"""" + name + """ expects the pointer to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(pointer));
    116             return false;
    117         }
     106        if (UNLIKELY(pointer != """ + cppType(op["parameter"][0]) + """))
     107            return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ pointer type mismatch");
    118108
    119         if (value != """ + cppType(op["parameter"][1]) + """) {
    120             m_errorMessage = makeString(\"""" + name + """ expects the value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(value));
    121             return false;
    122         }
     109        if (UNLIKELY(value != """ + cppType(op["parameter"][1]) + """))
     110            return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ value type mismatch");
    123111
    124         return true;
     112        return { };
    125113    }"""
    126114
     
    142130""" + unarySpecializations + binarySpecializations + """
    143131
    144 bool Validate::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t)
     132auto Validate::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t) -> Result
    145133{
    146     if (!hasMemory())
    147         return false;
     134    if (UNLIKELY(!hasMemory()))
     135        return UnexpectedType<Result::ErrorType>("validation failed: load instruction without memory");
    148136
    149137    switch (op) {
     
    152140}
    153141
    154 bool Validate::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t)
     142auto Validate::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t) -> Result
    155143{
    156     if (!hasMemory())
    157         return false;
     144    if (UNLIKELY(!hasMemory()))
     145        return UnexpectedType<Result::ErrorType>("validation failed: store instruction without memory");
    158146
    159147    switch (op) {
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp

    r209850 r209880  
    107107
    108108        switch (import.kind) {
    109         case Wasm::External::Function: {
     109        case Wasm::ExternalKind::Function: {
    110110            // 4. If i is a function import:
    111111            // i. If IsCallable(v) is false, throw a TypeError.
     
    130130            break;
    131131        }
    132         case Wasm::External::Table: {
     132        case Wasm::ExternalKind::Table: {
    133133            RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure.
    134134            // 7. Otherwise (i is a table import):
     
    161161            break;
    162162        }
    163         case Wasm::External::Memory: {
     163        case Wasm::ExternalKind::Memory: {
    164164            // 6. If i is a memory import:
    165165            RELEASE_ASSERT(!hasMemoryImport); // This should be guaranteed by a validation failure.
     
    193193            break;
    194194        }
    195         case Wasm::External::Global: {
     195        case Wasm::ExternalKind::Global: {
    196196            // 5. If i is a global import:
    197197            // i. If i is not an immutable global, throw a TypeError.
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

    r209874 r209880  
    106106        JSValue exportedValue;
    107107        switch (exp.kind) {
    108         case Wasm::External::Function: {
     108        case Wasm::ExternalKind::Function: {
    109109            // 1. If e is a closure c:
    110110            //   i. If there is an Exported Function Exotic Object func in funcs whose func.[[Closure]] equals c, then return func.
     
    127127            break;
    128128        }
    129         case Wasm::External::Table: {
     129        case Wasm::ExternalKind::Table: {
    130130            // This should be guaranteed by module verification.
    131131            RELEASE_ASSERT(instance->table());
     
    135135            break;
    136136        }
    137         case Wasm::External::Memory: {
     137        case Wasm::ExternalKind::Memory: {
    138138            // This should be guaranteed by module verification.
    139139            RELEASE_ASSERT(instance->memory());
     
    143143            break;
    144144        }
    145         case Wasm::External::Global: {
     145        case Wasm::ExternalKind::Global: {
    146146            // Assert: the global is immutable by MVP validation constraint.
    147147            const Wasm::Global& global = moduleInformation.globals[exp.kindIndex];
Note: See TracChangeset for help on using the changeset viewer.