Changeset 246571 in webkit


Ignore:
Timestamp:
Jun 18, 2019 3:01:02 PM (5 years ago)
Author:
Justin Michaud
Message:

[WASM-References] Add support for multiple tables
https://bugs.webkit.org/show_bug.cgi?id=198760

Reviewed by Saam Barati.

JSTests:

  • wasm/Builder.js:
  • wasm/js-api/call-indirect.js:

(const.oneTable):
(const.multiTable):
(multiTable):
(multiTable.Polyphic2Import):
(multiTable.VirtualImport):
(const.wasmModuleWhichImportJS): Deleted.
(const.makeTable): Deleted.
(): Deleted.
(Polyphic2Import): Deleted.
(VirtualImport): Deleted.

  • wasm/js-api/table.js:

(new.WebAssembly.Module):
(assert.throws):
(assertBadTableImport):
(assert.truthy):
(assert.throws.new.WebAssembly.Module.builder.WebAssembly): Deleted.

  • wasm/references/anyref_table.js:
  • wasm/references/anyref_table_import.js:

(makeImport):
(string_appeared_here.fullGC.assert.eq.1.exports.get_tbl.makeImport):
(string_appeared_here.fullGC.assert.eq.1.exports.get_tbl):

  • wasm/references/multitable.js: Added.

(assert.throws.1.exports.set_tbl0):
(assert.throws):
(assert.eq):

  • wasm/references/validation.js:

(assert.throws.new.WebAssembly.Module.bin):
(assert.throws):

  • wasm/spec-tests/imports.wast.js:
  • wasm/wasm.json:
  • wasm/Builder.js:
  • wasm/js-api/call-indirect.js:

(const.oneTable):
(const.multiTable):
(multiTable):
(multiTable.Polyphic2Import):
(multiTable.VirtualImport):
(const.wasmModuleWhichImportJS): Deleted.
(const.makeTable): Deleted.
(): Deleted.
(Polyphic2Import): Deleted.
(VirtualImport): Deleted.

  • wasm/js-api/table.js:

(new.WebAssembly.Module):
(assert.throws):
(assertBadTableImport):
(assert.truthy):
(assert.throws.new.WebAssembly.Module.builder.WebAssembly): Deleted.

  • wasm/references/anyref_table.js:
  • wasm/references/anyref_table_import.js:

(makeImport):
(string_appeared_here.fullGC.assert.eq.1.exports.get_tbl.makeImport):
(string_appeared_here.fullGC.assert.eq.1.exports.get_tbl):

  • wasm/references/func_ref.js:

(GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.fun): Deleted.
(GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.assert.throws): Deleted.
(GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly): Deleted.

  • wasm/references/multitable.js: Added.

(assert.throws.1.exports.set_tbl0):
(assert.throws):
(assert.eq):
(string_appeared_here.tableInsanity):
(I32Const.0.GetLocal.0.TableSet.1.End.End.WebAssembly.):
(I32Const.0.GetLocal.0.TableSet.1.End.End.WebAssembly):

  • wasm/references/validation.js:

(assert.throws.new.WebAssembly.Module.bin):
(assert.throws):

  • wasm/spec-tests/imports.wast.js:
  • wasm/wasm.json:

Source/JavaScriptCore:

Support multiple wasm tables. We turn tableInformation into a tables array, and update all of the
existing users to give a table index. The array of Tables in Wasm::Instance is hung off the tail
to make it easier to use from jit code.

  • wasm/WasmAirIRGenerator.cpp:

(JSC::Wasm::AirIRGenerator::AirIRGenerator):
(JSC::Wasm::AirIRGenerator::addTableGet):
(JSC::Wasm::AirIRGenerator::addTableSet):
(JSC::Wasm::AirIRGenerator::addCallIndirect):

  • wasm/WasmB3IRGenerator.cpp:

(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::B3IRGenerator::addTableGet):
(JSC::Wasm::B3IRGenerator::addTableSet):
(JSC::Wasm::B3IRGenerator::addCallIndirect):

  • wasm/WasmExceptionType.h:
  • wasm/WasmFormat.h:

(JSC::Wasm::Element::Element):

  • wasm/WasmFunctionParser.h:

(JSC::Wasm::FunctionParser<Context>::parseExpression):
(JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):

  • wasm/WasmInstance.cpp:

(JSC::Wasm::Instance::Instance):
(JSC::Wasm::Instance::create):
(JSC::Wasm::Instance::extraMemoryAllocated const):
(JSC::Wasm::Instance::table):
(JSC::Wasm::Instance::setTable):

  • wasm/WasmInstance.h:

(JSC::Wasm::Instance::updateCachedMemory):
(JSC::Wasm::Instance::offsetOfGlobals):
(JSC::Wasm::Instance::offsetOfTablePtr):
(JSC::Wasm::Instance::allocationSize):
(JSC::Wasm::Instance::table): Deleted.
(JSC::Wasm::Instance::setTable): Deleted.
(JSC::Wasm::Instance::offsetOfTable): Deleted.

  • wasm/WasmModuleInformation.h:

(JSC::Wasm::ModuleInformation::tableCount const):

  • wasm/WasmSectionParser.cpp:

(JSC::Wasm::SectionParser::parseImport):
(JSC::Wasm::SectionParser::parseTableHelper):
(JSC::Wasm::SectionParser::parseTable):
(JSC::Wasm::SectionParser::parseElement):

  • wasm/WasmTable.h:

(JSC::Wasm::Table::owner const):

  • wasm/WasmValidate.cpp:

(JSC::Wasm::Validate::addTableGet):
(JSC::Wasm::Validate::addTableSet):
(JSC::Wasm::Validate::addCallIndirect):

  • wasm/js/JSWebAssemblyInstance.cpp:

(JSC::JSWebAssemblyInstance::JSWebAssemblyInstance):
(JSC::JSWebAssemblyInstance::visitChildren):

  • wasm/js/JSWebAssemblyInstance.h:
  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::link):
(JSC::WebAssemblyModuleRecord::evaluate):

  • wasm/wasm.json:
Location:
trunk
Files:
1 added
26 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r246567 r246571  
     12019-06-18  Justin Michaud  <justin_michaud@apple.com>
     2
     3        [WASM-References] Add support for multiple tables
     4        https://bugs.webkit.org/show_bug.cgi?id=198760
     5
     6        Reviewed by Saam Barati.
     7
     8        * wasm/Builder.js:
     9        * wasm/js-api/call-indirect.js:
     10        (const.oneTable):
     11        (const.multiTable):
     12        (multiTable):
     13        (multiTable.Polyphic2Import):
     14        (multiTable.VirtualImport):
     15        (const.wasmModuleWhichImportJS): Deleted.
     16        (const.makeTable): Deleted.
     17        (): Deleted.
     18        (Polyphic2Import): Deleted.
     19        (VirtualImport): Deleted.
     20        * wasm/js-api/table.js:
     21        (new.WebAssembly.Module):
     22        (assert.throws):
     23        (assertBadTableImport):
     24        (assert.truthy):
     25        (assert.throws.new.WebAssembly.Module.builder.WebAssembly): Deleted.
     26        * wasm/references/anyref_table.js:
     27        * wasm/references/anyref_table_import.js:
     28        (makeImport):
     29        (string_appeared_here.fullGC.assert.eq.1.exports.get_tbl.makeImport):
     30        (string_appeared_here.fullGC.assert.eq.1.exports.get_tbl):
     31        * wasm/references/multitable.js: Added.
     32        (assert.throws.1.exports.set_tbl0):
     33        (assert.throws):
     34        (assert.eq):
     35        * wasm/references/validation.js:
     36        (assert.throws.new.WebAssembly.Module.bin):
     37        (assert.throws):
     38        * wasm/spec-tests/imports.wast.js:
     39        * wasm/wasm.json:
     40
     41        * wasm/Builder.js:
     42        * wasm/js-api/call-indirect.js:
     43        (const.oneTable):
     44        (const.multiTable):
     45        (multiTable):
     46        (multiTable.Polyphic2Import):
     47        (multiTable.VirtualImport):
     48        (const.wasmModuleWhichImportJS): Deleted.
     49        (const.makeTable): Deleted.
     50        (): Deleted.
     51        (Polyphic2Import): Deleted.
     52        (VirtualImport): Deleted.
     53        * wasm/js-api/table.js:
     54        (new.WebAssembly.Module):
     55        (assert.throws):
     56        (assertBadTableImport):
     57        (assert.truthy):
     58        (assert.throws.new.WebAssembly.Module.builder.WebAssembly): Deleted.
     59        * wasm/references/anyref_table.js:
     60        * wasm/references/anyref_table_import.js:
     61        (makeImport):
     62        (string_appeared_here.fullGC.assert.eq.1.exports.get_tbl.makeImport):
     63        (string_appeared_here.fullGC.assert.eq.1.exports.get_tbl):
     64        * wasm/references/func_ref.js:
     65        (GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.fun): Deleted.
     66        (GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.assert.throws): Deleted.
     67        (GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly): Deleted.
     68        * wasm/references/multitable.js: Added.
     69        (assert.throws.1.exports.set_tbl0):
     70        (assert.throws):
     71        (assert.eq):
     72        (string_appeared_here.tableInsanity):
     73        (I32Const.0.GetLocal.0.TableSet.1.End.End.WebAssembly.):
     74        (I32Const.0.GetLocal.0.TableSet.1.End.End.WebAssembly):
     75        * wasm/references/validation.js:
     76        (assert.throws.new.WebAssembly.Module.bin):
     77        (assert.throws):
     78        * wasm/spec-tests/imports.wast.js:
     79        * wasm/wasm.json:
     80
    1812019-06-18  Alexey Shvayka  <shvaikalesh@gmail.com>
    282
  • trunk/JSTests/wasm/Builder.js

    r246504 r246571  
    307307        case "target_table": break; // improve checking https://bugs.webkit.org/show_bug.cgi?id=163421
    308308        case "reserved": break; // improve checking https://bugs.webkit.org/show_bug.cgi?id=163421
     309        case "table_index": break; // improve checking https://bugs.webkit.org/show_bug.cgi?id=163421
    309310        default: throw new Error(`Implementation problem: unhandled immediate "${expect.name}" on "${op}"`);
    310311        }
  • trunk/JSTests/wasm/js-api/call-indirect.js

    r209771 r246571  
    22import Builder from '../Builder.js';
    33
    4 const wasmModuleWhichImportJS = () => {
     4const oneTable = () => {
    55    const builder = (new Builder())
    66        .Type().End()
     
    3232};
    3333
     34const multiTable = () => {
     35    const builder = (new Builder())
     36        .Type().End()
     37        .Import()
     38            .Function("imp", "func", { params: ["i32"] })
     39            .Table("imp", "table0", { initial: 0, maximum: 0, element: "anyfunc"})
     40            .Table("imp", "table", { initial: 1, maximum: 1, element: "anyfunc"})
     41        .End()
     42        .Function().End()
     43        .Export()
     44            .Function("changeCounter")
     45            .Function("callFunc")
     46        .End()
     47        .Code()
     48            .Function("changeCounter", { params: ["i32", "i32"] })
     49                .I32Const(42)
     50                .GetLocal(0)
     51                .I32Add()
     52                .GetLocal(1)
     53                .CallIndirect(0, 1) // Calls table[0](param[0] + 42).
     54            .End()
     55            .Function("callFunc", { params: ["i32"] })
     56                .GetLocal(0)
     57                .Call(0) // Calls func(param[0] + 42)
     58            .End()
     59        .End();
     60    const bin = builder.WebAssembly().get();
     61    const module = new WebAssembly.Module(bin);
     62    return module;
     63};
     64
     65for (const wasmModuleWhichImportJS of [oneTable, multiTable]) {
     66
    3467const makeTable = () => {
    3568    return new WebAssembly.Table({initial: 1, maximum: 1, element: "anyfunc"});
     
    4174    const table = makeTable();
    4275    const module = wasmModuleWhichImportJS();
    43     const instance = new WebAssembly.Instance(module, { imp: { func: counterSetter, table} });
     76    const instance = new WebAssembly.Instance(module, { imp: { func: counterSetter, table, table0: new WebAssembly.Table({initial: 0, maximum: 0, element: "anyfunc"}) } });
    4477    table.set(0, instance.exports.callFunc);
    4578    for (let i = 0; i < 4096; ++i) {
     
    5891
    5992    const tableA = makeTable();
    60     const instanceA = new WebAssembly.Instance(module, { imp: { func: counterASetter, table: tableA} });
     93    const instanceA = new WebAssembly.Instance(module, { imp: { func: counterASetter, table: tableA, table0: new WebAssembly.Table({initial: 0, maximum: 0, element: "anyfunc"}) } });
    6194    tableA.set(0, instanceA.exports.callFunc);
    6295
    6396    const tableB = makeTable();
    64     const instanceB = new WebAssembly.Instance(module, { imp: { func: counterBSetter, table: tableB} });
     97    const instanceB = new WebAssembly.Instance(module, { imp: { func: counterBSetter, table: tableB, table0: new WebAssembly.Table({initial: 0, maximum: 0, element: "anyfunc"}) } });
    6598    tableB.set(0, instanceB.exports.callFunc);
    6699    for (let i = 0; i < 2048; ++i) {
     
    94127    for (let i = 0; i < num; ++i) {
    95128        let table = makeTable();
    96         instances[i] = new WebAssembly.Instance(module, { imp: { func: counterSetters[i], table} });
     129        instances[i] = new WebAssembly.Instance(module, { imp: { func: counterSetters[i], table, table0: new WebAssembly.Table({initial: 0, maximum: 0, element: "anyfunc"}) } });
    97130        table.set(0, instances[i].exports.callFunc);
    98131    }
     
    105138    }
    106139})();
     140
     141}
  • trunk/JSTests/wasm/js-api/table.js

    r246139 r246571  
    1414        .Code()
    1515        .End();
    16     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 34: Cannot have more than one Table for now");
     16    new WebAssembly.Module(builder.WebAssembly().get())
    1717}
    1818
     
    3939        .Code()
    4040        .End();
    41     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 17: Table count of 2 is invalid, at most 1 is allowed for now (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
     41    new WebAssembly.Module(builder.WebAssembly().get())
    4242}
    4343
     
    7474            .End()
    7575        .End();
    76     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 6: call_indirect's 'reserved' varuint1 must be 0x0, in function at index 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
     76    assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 6: call_indirect's table index 1 invalid, limit is 1, in function at index 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
     77}
     78
     79{
     80    const builder = new Builder()
     81        .Type().End()
     82        .Function().End()
     83        .Table()
     84            .Table({initial:20, element:"anyfunc"})
     85            .Table({initial:20, element:"anyfunc"})
     86        .End()
     87        .Export()
     88            .Function("foo")
     89        .End()
     90        .Code()
     91            .Function("foo", {params: ["i32"]})
     92                .GetLocal(0)
     93                .GetLocal(0)
     94                .CallIndirect(0, 1)
     95            .End()
     96        .End();
     97    new WebAssembly.Module(builder.WebAssembly().get())
    7798}
    7899
     
    187208        .Code()
    188209        .End();
    189     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 39: Cannot have more than one Table for now");
     210    new WebAssembly.Module(builder.WebAssembly().get())
    190211}
    191212
     
    321342    assert.truthy(instance.exports.table instanceof WebAssembly.Table);
    322343}
     344
     345{
     346    const builder = new Builder()
     347        .Type().End()
     348        .Function().End()
     349        .Table()
     350            .Table({initial: 0, maximum: 1, element: "anyfunc"})
     351            .Table({initial: 20, maximum: 30, element: "anyfunc"})
     352        .End()
     353        .Export()
     354            .Table("table0", 0)
     355            .Table("table", 1)
     356            .Table("table2", 1)
     357        .End()
     358        .Code().End();
     359
     360    const module = new WebAssembly.Module(builder.WebAssembly().get());
     361    const instance = new WebAssembly.Instance(module);
     362    assert.eq(instance.exports.table, instance.exports.table2);
     363    assert.eq(instance.exports.table.length, 20);
     364    assert.eq(instance.exports.table0.length, 0);
     365    assert.truthy(instance.exports.table instanceof WebAssembly.Table);
     366}
  • trunk/JSTests/wasm/references/anyref_table.js

    r246516 r246571  
    1919          .I32Const(0)
    2020          .GetLocal(0)
    21           .TableSet()
     21          .TableSet(0)
    2222        .End()
    2323
    2424        .Function("get_tbl", { params: [], ret: "anyref" })
    2525          .I32Const(0)
    26           .TableGet()
     26          .TableGet(0)
    2727        .End()
    2828
  • trunk/JSTests/wasm/references/anyref_table_import.js

    r246139 r246571  
    2323              .I32Const(0)
    2424              .GetLocal(0)
    25               .TableSet()
     25              .TableSet(0)
    2626            .End()
    2727
    2828            .Function("get_tbl", { params: [], ret: "anyref" })
    2929              .I32Const(0)
    30               .TableGet()
     30              .TableGet(0)
    3131            .End()
    3232
     
    8989              .I32Const(0)
    9090              .GetLocal(0)
    91               .TableSet()
     91              .TableSet(0)
    9292            .End()
    9393
    9494            .Function("get_tbl", { params: [], ret: "anyref" })
    9595              .I32Const(0)
    96               .TableGet()
     96              .TableGet(0)
    9797            .End()
    9898
     
    128128              .I32Const(0)
    129129              .GetLocal(0)
    130               .TableSet()
     130              .TableSet(0)
    131131            .End()
    132132
    133133            .Function("get_tbl", { params: [], ret: "anyref" })
    134134              .I32Const(0)
    135               .TableGet()
     135              .TableGet(0)
    136136            .End()
    137137
  • trunk/JSTests/wasm/references/func_ref.js

    r246504 r246571  
    258258      .GetLocal(0)
    259259      .I32Const(0)
    260       .TableSet()
     260      .TableSet(0)
    261261    .End()
    262262  .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't validate: table.set value to type I32 expected Anyfunc, in function at index 0 (evaluating 'new WebAssembly.Module')");
     
    268268      .Function().End()
    269269      .Table()
     270            .Table({initial: 0, element: "anyref"})
    270271            .Table({initial: 1, element: "anyfunc"})
    271272      .End()
     
    292293            .I32Const(0)
    293294            .GetGlobal(0)
    294             .TableSet()
     295            .TableSet(1)
    295296
    296297            .GetLocal(0)
    297298            .I32Const(0)
    298             .CallIndirect(2,0)
     299            .CallIndirect(2,1)
    299300        .End()
    300301
     
    329330      .Function().End()
    330331      .Table()
     332            .Table({initial: 0, element: "anyref"})
    331333            .Table({initial: 1, element: "anyfunc"})
    332334      .End()
     
    339341          .I32Const(0)
    340342          .GetLocal(0)
    341           .TableSet()
     343          .TableSet(1)
    342344        .End()
    343345
    344346        .Function("get", { params: [], ret: "anyfunc" })
    345347            .I32Const(0)
    346             .TableGet()
     348            .TableGet(1)
    347349        .End()
    348350      .End().WebAssembly().get()));
     
    406408          .I32Const(0)
    407409          .RefFunc(0)
    408           .TableSet()
     410          .TableSet(0)
    409411          .I32Const(0)
    410412          .CallIndirect(0, 0)
     
    415417          .I32Const(0)
    416418          .RefFunc(0)
    417           .TableSet()
     419          .TableSet(0)
    418420          .I32Const(0)
    419421          .CallIndirect(0, 0)
  • trunk/JSTests/wasm/references/validation.js

    r246504 r246571  
    2525    const builder = (new Builder())
    2626      .Type().End()
     27      .Import()
     28            .Table("imp", "tbl", {initial: 2, element: "anyfunc"})
     29      .End()
    2730      .Function().End()
    2831      .Export()
     
    3336            .I32Const(0)
    3437            .I32Const(0)
    35             .TableSet()
     38            .TableSet(0)
    3639        .End()
    3740      .End();
     
    4043    bin.trim();
    4144
    42     assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: table.set value to type I32 expected Anyref, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
     45    assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: table.set value to type I32 expected Anyfunc, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
    4346}
    4447
     
    5760            .I32Const(0)
    5861            .GetLocal(0)
    59             .TableSet()
     62            .TableSet(0)
    6063        .End()
    6164      .End();
     
    8083        .Function("j", { params: [], ret: "anyref" })
    8184            .I32Const(0)
    82             .TableGet()
     85            .TableGet(0)
    8386        .End()
    8487      .End();
  • trunk/JSTests/wasm/spec-tests/imports.wast.js

    r218216 r246571  
    189189assert_trap(() => call($14, "call", [100]));
    190190
    191 // imports.wast:293
    192 assert_invalid("\x00\x61\x73\x6d\x01\x00\x00\x00\x02\x8d\x80\x80\x80\x00\x02\x00\x00\x01\x70\x00\x0a\x00\x00\x01\x70\x00\x0a");
    193 
    194 // imports.wast:297
    195 assert_invalid("\x00\x61\x73\x6d\x01\x00\x00\x00\x02\x87\x80\x80\x80\x00\x01\x00\x00\x01\x70\x00\x0a\x04\x84\x80\x80\x80\x00\x01\x70\x00\x0a");
    196 
    197 // imports.wast:301
    198 assert_invalid("\x00\x61\x73\x6d\x01\x00\x00\x00\x04\x87\x80\x80\x80\x00\x02\x70\x00\x0a\x70\x00\x0a");
    199 
    200191// imports.wast:306
    201192let $15 = instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x02\x97\x80\x80\x80\x00\x01\x04\x74\x65\x73\x74\x0c\x74\x61\x62\x6c\x65\x2d\x31\x30\x2d\x69\x6e\x66\x01\x70\x00\x0a");
  • trunk/JSTests/wasm/wasm.json

    r246504 r246571  
    6868        "get_global":          { "category": "special",    "value":  35, "return": ["any"],      "parameter": [],                       "immediate": [{"name": "global_index",   "type": "varuint32"}],                                            "description": "read a global variable" },
    6969        "set_global":          { "category": "special",    "value":  36, "return": [],           "parameter": ["any"],                  "immediate": [{"name": "global_index",   "type": "varuint32"}],                                            "description": "write a global variable" },
    70         "table.get":           { "category": "special",    "value":  37, "return": ["anyref"],   "parameter": ["i32"],                  "immediate": [],                                                                                           "description": "get a table value" },
    71         "table.set":           { "category": "special",    "value":  38, "return": [],           "parameter": ["i32", "anyref"],        "immediate": [],                                                                                           "description": "set a table value" },
     70        "table.get":           { "category": "special",    "value":  37, "return": ["anyref"],   "parameter": ["i32"],                  "immediate": [{"name": "table_index",    "type": "varuint32"}],                                            "description": "get a table value" },
     71        "table.set":           { "category": "special",    "value":  38, "return": [],           "parameter": ["i32", "anyref"],        "immediate": [{"name": "table_index",    "type": "varuint32"}],                                            "description": "set a table value" },
    7272        "call":                { "category": "call",       "value":  16, "return": ["call"],     "parameter": ["call"],                 "immediate": [{"name": "function_index", "type": "varuint32"}],                                            "description": "call a function by its index" },
    73         "call_indirect":       { "category": "call",       "value":  17, "return": ["call"],     "parameter": ["call"],                 "immediate": [{"name": "type_index",     "type": "varuint32"}, {"name": "reserved", "type": "varuint1"}],  "description": "call a function indirect with an expected signature" },
     73        "call_indirect":       { "category": "call",       "value":  17, "return": ["call"],     "parameter": ["call"],                 "immediate": [{"name": "type_index",     "type": "varuint32"}, {"name": "table_index","type": "varuint32"}],"description": "call a function indirect with an expected signature" },
    7474        "i32.load8_s":         { "category": "memory",     "value":  44, "return": ["i32"],      "parameter": ["addr"],                 "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset",   "type": "varuint32"}], "description": "load from memory" },
    7575        "i32.load8_u":         { "category": "memory",     "value":  45, "return": ["i32"],      "parameter": ["addr"],                 "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset",   "type": "varuint32"}], "description": "load from memory" },
  • trunk/Source/JavaScriptCore/ChangeLog

    r246567 r246571  
     12019-06-18  Justin Michaud  <justin_michaud@apple.com>
     2
     3        [WASM-References] Add support for multiple tables
     4        https://bugs.webkit.org/show_bug.cgi?id=198760
     5
     6        Reviewed by Saam Barati.
     7
     8        Support multiple wasm tables. We turn tableInformation into a tables array, and update all of the
     9        existing users to give a table index. The array of Tables in Wasm::Instance is hung off the tail
     10        to make it easier to use from jit code.
     11
     12        * wasm/WasmAirIRGenerator.cpp:
     13        (JSC::Wasm::AirIRGenerator::AirIRGenerator):
     14        (JSC::Wasm::AirIRGenerator::addTableGet):
     15        (JSC::Wasm::AirIRGenerator::addTableSet):
     16        (JSC::Wasm::AirIRGenerator::addCallIndirect):
     17        * wasm/WasmB3IRGenerator.cpp:
     18        (JSC::Wasm::B3IRGenerator::B3IRGenerator):
     19        (JSC::Wasm::B3IRGenerator::addTableGet):
     20        (JSC::Wasm::B3IRGenerator::addTableSet):
     21        (JSC::Wasm::B3IRGenerator::addCallIndirect):
     22        * wasm/WasmExceptionType.h:
     23        * wasm/WasmFormat.h:
     24        (JSC::Wasm::Element::Element):
     25        * wasm/WasmFunctionParser.h:
     26        (JSC::Wasm::FunctionParser<Context>::parseExpression):
     27        (JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
     28        * wasm/WasmInstance.cpp:
     29        (JSC::Wasm::Instance::Instance):
     30        (JSC::Wasm::Instance::create):
     31        (JSC::Wasm::Instance::extraMemoryAllocated const):
     32        (JSC::Wasm::Instance::table):
     33        (JSC::Wasm::Instance::setTable):
     34        * wasm/WasmInstance.h:
     35        (JSC::Wasm::Instance::updateCachedMemory):
     36        (JSC::Wasm::Instance::offsetOfGlobals):
     37        (JSC::Wasm::Instance::offsetOfTablePtr):
     38        (JSC::Wasm::Instance::allocationSize):
     39        (JSC::Wasm::Instance::table): Deleted.
     40        (JSC::Wasm::Instance::setTable): Deleted.
     41        (JSC::Wasm::Instance::offsetOfTable): Deleted.
     42        * wasm/WasmModuleInformation.h:
     43        (JSC::Wasm::ModuleInformation::tableCount const):
     44        * wasm/WasmSectionParser.cpp:
     45        (JSC::Wasm::SectionParser::parseImport):
     46        (JSC::Wasm::SectionParser::parseTableHelper):
     47        (JSC::Wasm::SectionParser::parseTable):
     48        (JSC::Wasm::SectionParser::parseElement):
     49        * wasm/WasmTable.h:
     50        (JSC::Wasm::Table::owner const):
     51        * wasm/WasmValidate.cpp:
     52        (JSC::Wasm::Validate::addTableGet):
     53        (JSC::Wasm::Validate::addTableSet):
     54        (JSC::Wasm::Validate::addCallIndirect):
     55        * wasm/js/JSWebAssemblyInstance.cpp:
     56        (JSC::JSWebAssemblyInstance::JSWebAssemblyInstance):
     57        (JSC::JSWebAssemblyInstance::visitChildren):
     58        * wasm/js/JSWebAssemblyInstance.h:
     59        * wasm/js/WebAssemblyModuleRecord.cpp:
     60        (JSC::WebAssemblyModuleRecord::link):
     61        (JSC::WebAssemblyModuleRecord::evaluate):
     62        * wasm/wasm.json:
     63
    1642019-06-18  Alexey Shvayka  <shvaikalesh@gmail.com>
    265
  • trunk/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp

    r246504 r246571  
    238238
    239239    // Tables
    240     PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& index, ExpressionType& result);
    241     PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& index, ExpressionType& value);
     240    PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType& index, ExpressionType& result);
     241    PartialResult WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType& index, ExpressionType& value);
    242242
    243243    // Locals
     
    278278    // Calls
    279279    PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, ExpressionType& result);
    280     PartialResult WARN_UNUSED_RETURN addCallIndirect(const Signature&, Vector<ExpressionType>& args, ExpressionType& result);
     280    PartialResult WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, Vector<ExpressionType>& args, ExpressionType& result);
    281281    PartialResult WARN_UNUSED_RETURN addUnreachable();
    282282
     
    627627
    628628    uint32_t m_maxNumJSCallArguments { 0 };
     629    unsigned m_numImportFunctions;
    629630
    630631    B3::PatchpointSpecial* m_patchpointSpecial { nullptr };
     
    682683    , m_code(m_proc.code())
    683684    , m_unlinkedWasmToWasmCalls(unlinkedWasmToWasmCalls)
     685    , m_numImportFunctions(info.importFunctionCount())
    684686{
    685687    m_currentBlock = m_code.addBlock();
     
    969971}
    970972
    971 auto AirIRGenerator::addTableGet(ExpressionType& index, ExpressionType& result) -> PartialResult
     973auto AirIRGenerator::addTableGet(unsigned tableIndex, ExpressionType& index, ExpressionType& result) -> PartialResult
    972974{
    973975    // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
     
    976978    result = tmpForType(Type::Anyref);
    977979
    978     emitCCall(&getWasmTableElement, result, instanceValue(), index);
     980    emitCCall(&getWasmTableElement, result, instanceValue(), addConstant(Type::I32, tableIndex), index);
    979981    emitCheck([&] {
    980982        return Inst(BranchTest32, nullptr, Arg::resCond(MacroAssembler::Zero), result, result);
     
    986988}
    987989
    988 auto AirIRGenerator::addTableSet(ExpressionType& index, ExpressionType& value) -> PartialResult
     990auto AirIRGenerator::addTableSet(unsigned tableIndex, ExpressionType& index, ExpressionType& value) -> PartialResult
    989991{
    990992    // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
     
    994996
    995997    auto shouldThrow = g32();
    996     emitCCall(&setWasmTableElement, shouldThrow, instanceValue(), index, value);
     998    emitCCall(&setWasmTableElement, shouldThrow, instanceValue(), addConstant(Type::I32, tableIndex), index, value);
    997999
    9981000    emitCheck([&] {
     
    18941896}
    18951897
    1896 auto AirIRGenerator::addCallIndirect(const Signature& signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
     1898auto AirIRGenerator::addCallIndirect(unsigned tableIndex, const Signature& signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
    18971899{
    18981900    ExpressionType calleeIndex = args.takeLast();
    18991901    ASSERT(signature.argumentCount() == args.size());
    1900     ASSERT(m_info.tableInformation.type() == TableElementType::Funcref);
     1902    ASSERT(m_info.tableCount() > tableIndex);
     1903    ASSERT(m_info.tables[tableIndex].type() == TableElementType::Funcref);
    19011904
    19021905    m_makesCalls = true;
     
    19131916    ExpressionType callableFunctionBufferLength = g64();
    19141917    {
    1915         RELEASE_ASSERT(Arg::isValidAddrForm(Instance::offsetOfTable(), B3::Width64));
    19161918        RELEASE_ASSERT(Arg::isValidAddrForm(FuncRefTable::offsetOfFunctions(), B3::Width64));
    19171919        RELEASE_ASSERT(Arg::isValidAddrForm(FuncRefTable::offsetOfInstances(), B3::Width64));
    19181920        RELEASE_ASSERT(Arg::isValidAddrForm(FuncRefTable::offsetOfLength(), B3::Width64));
    19191921
    1920         append(Move, Arg::addr(instanceValue(), Instance::offsetOfTable()), callableFunctionBufferLength);
     1922        if (UNLIKELY(!Arg::isValidAddrForm(Instance::offsetOfTablePtr(m_numImportFunctions, tableIndex), B3::Width64))) {
     1923            append(Move, Arg::bigImm(Instance::offsetOfTablePtr(m_numImportFunctions, tableIndex)), callableFunctionBufferLength);
     1924            append(Add64, instanceValue(), callableFunctionBufferLength);
     1925            append(Move, Arg::addr(callableFunctionBufferLength), callableFunctionBufferLength);
     1926        } else
     1927            append(Move, Arg::addr(instanceValue(), Instance::offsetOfTablePtr(m_numImportFunctions, tableIndex)), callableFunctionBufferLength);
    19211928        append(Move, Arg::addr(callableFunctionBufferLength, FuncRefTable::offsetOfFunctions()), callableFunctionBuffer);
    19221929        append(Move, Arg::addr(callableFunctionBufferLength, FuncRefTable::offsetOfInstances()), instancesBuffer);
  • trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

    r246504 r246571  
    191191
    192192    // Tables
    193     PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& index, ExpressionType& result);
    194     PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& index, ExpressionType& value);
     193    PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType& index, ExpressionType& result);
     194    PartialResult WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType& index, ExpressionType& value);
    195195
    196196    // Locals
     
    231231    // Calls
    232232    PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, ExpressionType& result);
    233     PartialResult WARN_UNUSED_RETURN addCallIndirect(const Signature&, Vector<ExpressionType>& args, ExpressionType& result);
     233    PartialResult WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, Vector<ExpressionType>& args, ExpressionType& result);
    234234    PartialResult WARN_UNUSED_RETURN addUnreachable();
    235235
     
    293293
    294294    uint32_t m_maxNumJSCallArguments { 0 };
     295    unsigned m_numImportFunctions;
    295296};
    296297
     
    344345    , m_unlinkedWasmToWasmCalls(unlinkedWasmToWasmCalls)
    345346    , m_constantInsertionValues(m_proc)
     347    , m_numImportFunctions(info.importFunctionCount())
    346348{
    347349    m_currentBlock = m_proc.addBlock();
     
    567569}
    568570
    569 auto B3IRGenerator::addTableGet(ExpressionType& index, ExpressionType& result) -> PartialResult
     571auto B3IRGenerator::addTableGet(unsigned tableIndex, ExpressionType& index, ExpressionType& result) -> PartialResult
    570572{
    571573    // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
    572574    result = m_currentBlock->appendNew<CCallValue>(m_proc, toB3Type(Anyref), origin(),
    573575        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&getWasmTableElement, B3CCallPtrTag)),
    574         instanceValue(), index);
     576        instanceValue(), m_currentBlock->appendNew<Const32Value>(m_proc, origin(), tableIndex), index);
    575577
    576578    {
     
    586588}
    587589
    588 auto B3IRGenerator::addTableSet(ExpressionType& index, ExpressionType& value) -> PartialResult
     590auto B3IRGenerator::addTableSet(unsigned tableIndex, ExpressionType& index, ExpressionType& value) -> PartialResult
    589591{
    590592    // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
    591593    auto shouldThrow = m_currentBlock->appendNew<CCallValue>(m_proc, B3::Int32, origin(),
    592594        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&setWasmTableElement, B3CCallPtrTag)),
    593         instanceValue(), index, value);
     595        instanceValue(), m_currentBlock->appendNew<Const32Value>(m_proc, origin(), tableIndex), index, value);
    594596
    595597    {
     
    12991301}
    13001302
    1301 auto B3IRGenerator::addCallIndirect(const Signature& signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
     1303auto B3IRGenerator::addCallIndirect(unsigned tableIndex, const Signature& signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
    13021304{
    13031305    ExpressionType calleeIndex = args.takeLast();
     
    13161318    {
    13171319        ExpressionType table = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
    1318             instanceValue(), safeCast<int32_t>(Instance::offsetOfTable()));
     1320            instanceValue(), safeCast<int32_t>(Instance::offsetOfTablePtr(m_numImportFunctions, tableIndex)));
    13191321        callableFunctionBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
    13201322            table, safeCast<int32_t>(FuncRefTable::offsetOfFunctions()));
  • trunk/Source/JavaScriptCore/wasm/WasmFormat.h

    r246504 r246571  
    214214
    215215struct Element {
    216     Element(I32InitExpr offset)
    217         : offset(offset)
     216    Element(uint32_t tableIndex, I32InitExpr offset)
     217        : tableIndex(tableIndex)
     218        , offset(offset)
    218219    { }
    219220
     221    uint32_t tableIndex;
    220222    I32InitExpr offset;
    221223    Vector<uint32_t> functionIndices;
  • trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h

    r246504 r246571  
    284284    case TableGet: {
    285285        WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
     286        unsigned tableIndex;
     287        WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index");
    286288        ExpressionType result, index;
    287289        WASM_TRY_POP_EXPRESSION_STACK_INTO(index, "table.get");
    288         WASM_TRY_ADD_TO_CONTEXT(addTableGet(index, result));
     290        WASM_TRY_ADD_TO_CONTEXT(addTableGet(tableIndex, index, result));
    289291        m_expressionStack.append(result);
    290292        return { };
     
    293295    case TableSet: {
    294296        WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
     297        unsigned tableIndex;
     298        WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index");
    295299        ExpressionType val, index;
    296300        WASM_TRY_POP_EXPRESSION_STACK_INTO(val, "table.set");
    297301        WASM_TRY_POP_EXPRESSION_STACK_INTO(index, "table.set");
    298         WASM_TRY_ADD_TO_CONTEXT(addTableSet(index, val));
     302        WASM_TRY_ADD_TO_CONTEXT(addTableSet(tableIndex, index, val));
    299303        return { };
    300304    }
     
    397401    case CallIndirect: {
    398402        uint32_t signatureIndex;
    399         uint8_t reserved;
    400         WASM_PARSER_FAIL_IF(!m_info.tableInformation, "call_indirect is only valid when a table is defined or imported");
     403        uint32_t tableIndex;
     404        WASM_PARSER_FAIL_IF(!m_info.tableCount(), "call_indirect is only valid when a table is defined or imported");
    401405        WASM_PARSER_FAIL_IF(!parseVarUInt32(signatureIndex), "can't get call_indirect's signature index");
    402         WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't get call_indirect's reserved byte");
    403         WASM_PARSER_FAIL_IF(reserved, "call_indirect's 'reserved' varuint1 must be 0x0");
     406        WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get call_indirect's table index");
     407        WASM_PARSER_FAIL_IF(tableIndex >= m_info.tableCount(), "call_indirect's table index ", tableIndex, " invalid, limit is ", m_info.tableCount());
    404408        WASM_PARSER_FAIL_IF(m_info.usedSignatures.size() <= signatureIndex, "call_indirect's signature index ", signatureIndex, " exceeds known signatures ", m_info.usedSignatures.size());
    405         WASM_PARSER_FAIL_IF(m_info.tableInformation.type() != TableElementType::Funcref, "call_indirect is only valid when a table has type anyfunc");
     409        WASM_PARSER_FAIL_IF(m_info.tables[tableIndex].type() != TableElementType::Funcref, "call_indirect is only valid when a table has type anyfunc");
    406410
    407411        const Signature& calleeSignature = m_info.usedSignatures[signatureIndex].get();
     
    417421
    418422        ExpressionType result = Context::emptyExpression();
    419         WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(calleeSignature, args, result));
     423        WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(tableIndex, calleeSignature, args, result));
    420424
    421425        if (result != Context::emptyExpression())
     
    632636    case CallIndirect: {
    633637        uint32_t unused;
    634         uint8_t unused2;
     638        uint32_t unused2;
    635639        WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get call_indirect's signature index in unreachable context");
    636         WASM_PARSER_FAIL_IF(!parseVarUInt1(unused2), "can't get call_indirect's reserved byte in unreachable context");
     640        WASM_PARSER_FAIL_IF(!parseVarUInt32(unused2), "can't get call_indirect's reserved byte in unreachable context");
    637641        return { };
    638642    }
     
    686690
    687691    case TableGet:
    688     case TableSet:
     692    case TableSet: {
     693        unsigned tableIndex;
     694        WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index");
     695        FALLTHROUGH;
     696    }
    689697    case RefIsNull:
    690698    case RefNull: {
  • trunk/Source/JavaScriptCore/wasm/WasmInstance.cpp

    r246504 r246571  
    6262            m_globalsToMark.set(i);
    6363    }
     64    memset(bitwise_cast<char*>(this) + offsetOfTablePtr(m_numImportFunctions, 0), 0, m_module->moduleInformation().tableCount() * sizeof(Table*));
    6465}
    6566
    6667Ref<Instance> Instance::create(Context* context, Ref<Module>&& module, EntryFrame** pointerToTopEntryFrame, void** pointerToActualStackLimit, StoreTopCallFrameCallback&& storeTopCallFrame)
    6768{
    68     return adoptRef(*new (NotNull, fastMalloc(allocationSize(module->moduleInformation().importFunctionCount()))) Instance(context, WTFMove(module), pointerToTopEntryFrame, pointerToActualStackLimit, WTFMove(storeTopCallFrame)));
     69    return adoptRef(*new (NotNull, fastMalloc(allocationSize(module->moduleInformation().importFunctionCount(), module->moduleInformation().tableCount()))) Instance(context, WTFMove(module), pointerToTopEntryFrame, pointerToActualStackLimit, WTFMove(storeTopCallFrame)));
    6970}
    7071
     
    7374size_t Instance::extraMemoryAllocated() const
    7475{
    75     return globalMemoryByteSize(m_module.get()) + allocationSize(m_numImportFunctions);
     76    return globalMemoryByteSize(m_module.get()) + allocationSize(m_numImportFunctions, m_module->moduleInformation().tableCount());
    7677}
    7778
     
    100101}
    101102
    102 EncodedJSValue getWasmTableElement(Instance* instance, int32_t signedIndex)
     103Table* Instance::table(unsigned i)
    103104{
     105    RELEASE_ASSERT(i < m_module->moduleInformation().tableCount());
     106    return *bitwise_cast<Table**>(bitwise_cast<char*>(this) + offsetOfTablePtr(m_numImportFunctions, i));
     107}
     108
     109void Instance::setTable(unsigned i, Ref<Table>&& table)
     110{
     111    RELEASE_ASSERT(i < m_module->moduleInformation().tableCount());
     112    ASSERT(!this->table(i));
     113    *bitwise_cast<Table**>(bitwise_cast<char*>(this) + offsetOfTablePtr(m_numImportFunctions, i)) = &table.leakRef();
     114}
     115
     116EncodedJSValue getWasmTableElement(Instance* instance, unsigned tableIndex, int32_t signedIndex)
     117{
     118    ASSERT(tableIndex < instance->module().moduleInformation().tableCount());
    104119    if (signedIndex < 0)
    105120        return 0;
    106121
    107122    uint32_t index = signedIndex;
    108     if (index >= instance->table()->length())
     123    if (index >= instance->table(tableIndex)->length())
    109124        return 0;
    110125
    111     return JSValue::encode(instance->table()->get(index));
     126    return JSValue::encode(instance->table(tableIndex)->get(index));
    112127}
    113128
    114 bool setWasmTableElement(Instance* instance, int32_t signedIndex, EncodedJSValue encValue)
     129bool setWasmTableElement(Instance* instance, unsigned tableIndex, int32_t signedIndex, EncodedJSValue encValue)
    115130{
     131    ASSERT(tableIndex < instance->module().moduleInformation().tableCount());
    116132    if (signedIndex < 0)
    117133        return false;
    118134
    119135    uint32_t index = signedIndex;
    120     if (index >= instance->table()->length())
     136    if (index >= instance->table(tableIndex)->length())
    121137        return false;
    122138
    123139    JSValue value = JSValue::decode(encValue);
    124     if (instance->table()->type() == Wasm::TableElementType::Anyref)
    125         instance->table()->set(index, value);
    126     else if (instance->table()->type() == Wasm::TableElementType::Funcref) {
     140    if (instance->table(tableIndex)->type() == Wasm::TableElementType::Anyref)
     141        instance->table(tableIndex)->set(index, value);
     142    else if (instance->table(tableIndex)->type() == Wasm::TableElementType::Funcref) {
    127143        WebAssemblyFunction* wasmFunction;
    128144        WebAssemblyWrapperFunction* wasmWrapperFunction;
     
    131147            ASSERT(!!wasmFunction || !!wasmWrapperFunction);
    132148            if (wasmFunction)
    133                 instance->table()->asFuncrefTable()->setFunction(index, jsCast<JSObject*>(value), wasmFunction->importableFunction(), &wasmFunction->instance()->instance());
     149                instance->table(tableIndex)->asFuncrefTable()->setFunction(index, jsCast<JSObject*>(value), wasmFunction->importableFunction(), &wasmFunction->instance()->instance());
    134150            else
    135                 instance->table()->asFuncrefTable()->setFunction(index, jsCast<JSObject*>(value), wasmWrapperFunction->importableFunction(), &wasmWrapperFunction->instance()->instance());
     151                instance->table(tableIndex)->asFuncrefTable()->setFunction(index, jsCast<JSObject*>(value), wasmWrapperFunction->importableFunction(), &wasmWrapperFunction->instance()->instance());
    136152        } else if (value.isNull())
    137             instance->table()->clear(index);
     153            instance->table(tableIndex)->clear(index);
    138154        else
    139155            ASSERT_NOT_REACHED();
  • trunk/Source/JavaScriptCore/wasm/WasmInstance.h

    r246504 r246571  
    4242class Instance;
    4343
    44 EncodedJSValue getWasmTableElement(Instance*, int32_t);
    45 bool setWasmTableElement(Instance*, int32_t, EncodedJSValue encValue);
     44EncodedJSValue getWasmTableElement(Instance*, unsigned, int32_t);
     45bool setWasmTableElement(Instance*, unsigned, int32_t, EncodedJSValue encValue);
    4646EncodedJSValue doWasmRefFunc(Instance*, uint32_t);
    4747
     
    7171    CodeBlock* codeBlock() { return m_codeBlock.get(); }
    7272    Memory* memory() { return m_memory.get(); }
    73     Table* table() { return m_table.get(); }
     73    Table* table(unsigned);
     74    void setTable(unsigned, Ref<Table>&&);
    7475
    7576    void* cachedMemory() const { return m_cachedMemory.getMayBeNull(cachedMemorySize()); }
     
    8990        }
    9091    }
    91     void setTable(Ref<Table>&& table) { m_table = WTFMove(table); }
    9292
    9393    int32_t loadI32Global(unsigned i) const { return m_globals.get()[i].primitive; }
     
    104104    static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(Instance, m_memory); }
    105105    static ptrdiff_t offsetOfGlobals() { return OBJECT_OFFSETOF(Instance, m_globals); }
    106     static ptrdiff_t offsetOfTable() { return OBJECT_OFFSETOF(Instance, m_table); }
    107106    static ptrdiff_t offsetOfCachedMemory() { return OBJECT_OFFSETOF(Instance, m_cachedMemory); }
    108107    static ptrdiff_t offsetOfCachedMemorySize() { return OBJECT_OFFSETOF(Instance, m_cachedMemorySize); }
     
    123122
    124123    // Tail accessors.
    125     static size_t offsetOfTail() { return WTF::roundUpToMultipleOf<sizeof(uint64_t)>(sizeof(Instance)); }
     124    static constexpr size_t offsetOfTail() { return WTF::roundUpToMultipleOf<sizeof(uint64_t)>(sizeof(Instance)); }
    126125    struct ImportFunctionInfo {
    127126        // Target instance and entrypoint are only set for wasm->wasm calls, and are otherwise nullptr. The embedder-specific logic occurs through import function.
     
    143142    template<typename T> T* importFunction(unsigned importFunctionNum) { return reinterpret_cast<T*>(&importFunctionInfo(importFunctionNum)->importFunction); }
    144143
     144    static_assert(sizeof(ImportFunctionInfo) == WTF::roundUpToMultipleOf<sizeof(uint64_t)>(sizeof(ImportFunctionInfo)), "We rely on this for the alignment to be correct");
     145    static constexpr size_t offsetOfTablePtr(unsigned numImportFunctions, unsigned i) { return offsetOfTail() + sizeof(ImportFunctionInfo) * numImportFunctions + sizeof(Table*) * i; }
     146
    145147    void storeTopCallFrame(void* callFrame)
    146148    {
     
    151153    Instance(Context*, Ref<Module>&&, EntryFrame**, void**, StoreTopCallFrameCallback&&);
    152154   
    153     static size_t allocationSize(Checked<size_t> numImportFunctions)
     155    static size_t allocationSize(Checked<size_t> numImportFunctions, Checked<size_t> numTables)
    154156    {
    155         return (offsetOfTail() + sizeof(ImportFunctionInfo) * numImportFunctions).unsafeGet();
     157        return (offsetOfTail() + sizeof(ImportFunctionInfo) * numImportFunctions + sizeof(Table*) * numTables).unsafeGet();
    156158    }
    157159    void* m_owner { nullptr }; // In a JS embedding, this is a JSWebAssemblyInstance*.
     
    162164    RefPtr<CodeBlock> m_codeBlock;
    163165    RefPtr<Memory> m_memory;
    164     RefPtr<Table> m_table;
    165166
    166167    union GlobalValue {
  • trunk/Source/JavaScriptCore/wasm/WasmLimits.h

    r224122 r246571  
    5252
    5353constexpr size_t maxTableEntries = 10000000;
     54constexpr unsigned maxTables = 1000000;
    5455
    5556} } // namespace JSC::Wasm
  • trunk/Source/JavaScriptCore/wasm/WasmModuleInformation.h

    r246504 r246571  
    6666    // If we need to remove this limitation, we would have MemoryInformation and TableInformation in the Vectors.
    6767    uint32_t memoryCount() const { return memory ? 1 : 0; }
    68     uint32_t tableCount() const { return tableInformation ? 1 : 0; }
     68    uint32_t tableCount() const { return tables.size(); }
    6969
    7070    const BitVector& referencedFunctions() const { return m_referencedFunctions; }
     
    8484    Vector<Segment::Ptr> data;
    8585    Vector<Element> elements;
    86     TableInformation tableInformation;
     86    Vector<TableInformation> tables;
    8787    Vector<Global> globals;
    8888    unsigned firstInternalGlobal { 0 };
  • trunk/Source/JavaScriptCore/wasm/WasmSectionParser.cpp

    r246516 r246571  
    120120        case ExternalKind::Table: {
    121121            bool isImport = true;
     122            kindIndex = m_info->tables.size();
    122123            PartialResult result = parseTableHelper(isImport);
    123124            if (UNLIKELY(!result))
     
    194195auto SectionParser::parseTableHelper(bool isImport) -> PartialResult
    195196{
    196     WASM_PARSER_FAIL_IF(m_info->tableCount() > 0, "Cannot have more than one Table for now");
     197    WASM_PARSER_FAIL_IF(m_info->tableCount() >= maxTables, "Table count of ", m_info->tableCount(), " is too big, maximum ", maxTables);
    197198
    198199    int8_t type;
     
    210211
    211212    TableElementType tableType = type == Wasm::Anyfunc ? TableElementType::Funcref : TableElementType::Anyref;
    212     m_info->tableInformation = TableInformation(initial, maximum, isImport, tableType);
     213    m_info->tables.append(TableInformation(initial, maximum, isImport, tableType));
    213214
    214215    return { };
     
    219220    uint32_t count;
    220221    WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Table's count");
    221     WASM_PARSER_FAIL_IF(count > 1, "Table count of ", count, " is invalid, at most 1 is allowed for now");
    222 
    223     if (!count)
    224         return { };
    225 
    226     bool isImport = false;
    227     PartialResult result = parseTableHelper(isImport);
    228     if (UNLIKELY(!result))
    229         return makeUnexpected(WTFMove(result.error()));
     222
     223    for (unsigned i = 0; i < count; ++i) {
     224        bool isImport = false;
     225        PartialResult result = parseTableHelper(isImport);
     226        if (UNLIKELY(!result))
     227            return makeUnexpected(WTFMove(result.error()));
     228    }
    230229
    231230    return { };
     
    380379        WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index");
    381380        WASM_PARSER_FAIL_IF(tableIndex >= m_info->tableCount(), "Element section for Table ", tableIndex, " exceeds available Table ", m_info->tableCount());
    382         WASM_PARSER_FAIL_IF(m_info->tableInformation.type() != TableElementType::Funcref, "Table ", tableIndex, " must have type 'anyfunc' to have an element section");
     381        WASM_PARSER_FAIL_IF(m_info->tables[tableIndex].type() != TableElementType::Funcref, "Table ", tableIndex, " must have type 'anyfunc' to have an element section");
    383382        Type initExprType;
    384383        WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType));
     
    387386        WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount);
    388387
    389         ASSERT(!!m_info->tableInformation);
    390 
    391         Element element(makeI32InitExpr(initOpcode, initExprBits));
     388        ASSERT(!!m_info->tables[tableIndex]);
     389
     390        Element element(tableIndex, makeI32InitExpr(initOpcode, initExprBits));
    392391        WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
    393392
  • trunk/Source/JavaScriptCore/wasm/WasmTable.h

    r246487 r246571  
    5858    uint32_t mask() const { return m_mask; }
    5959
     60    template<typename T> T* owner() const { return reinterpret_cast<T*>(m_owner); }
    6061    void setOwner(JSObject* owner)
    6162    {
  • trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp

    r246504 r246571  
    107107
    108108    // Tables
    109     Result WARN_UNUSED_RETURN addTableGet(ExpressionType& index, ExpressionType& result);
    110     Result WARN_UNUSED_RETURN addTableSet(ExpressionType& index, ExpressionType& value);
     109    Result WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType& index, ExpressionType& result);
     110    Result WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType& index, ExpressionType& value);
    111111
    112112    // Locals
     
    149149    // Calls
    150150    Result WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature&, const Vector<ExpressionType>& args, ExpressionType& result);
    151     Result WARN_UNUSED_RETURN addCallIndirect(const Signature&, const Vector<ExpressionType>& args, ExpressionType& result);
     151    Result WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, const Vector<ExpressionType>& args, ExpressionType& result);
    152152
    153153    ALWAYS_INLINE void didKill(ExpressionType) { }
     
    179179}
    180180
    181 auto Validate::addTableGet(ExpressionType& index, ExpressionType& result) -> Result
    182 {
    183     result = m_module.tableInformation.wasmType();
     181auto Validate::addTableGet(unsigned tableIndex, ExpressionType& index, ExpressionType& result) -> Result
     182{
     183    WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
     184    result = m_module.tables[tableIndex].wasmType();
    184185    WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.get index to type ", index, " expected ", Type::I32);
    185186
     
    187188}
    188189
    189 auto Validate::addTableSet(ExpressionType& index, ExpressionType& value) -> Result
    190 {
    191     auto type = m_module.tableInformation.wasmType();
     190auto Validate::addTableSet(unsigned tableIndex, ExpressionType& index, ExpressionType& value) -> Result
     191{
     192    WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
     193    auto type = m_module.tables[tableIndex].wasmType();
    192194    WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.set index to type ", index, " expected ", Type::I32);
    193195    WASM_VALIDATOR_FAIL_IF(!isSubtype(value, type), "table.set value to type ", value, " expected ", type);
    194     WASM_VALIDATOR_FAIL_IF(m_module.tableInformation.type() != TableElementType::Anyref
    195         && m_module.tableInformation.type() != TableElementType::Funcref, "table.set expects the table to have type anyref or anyfunc");
     196    RELEASE_ASSERT(m_module.tables[tableIndex].type() == TableElementType::Anyref || m_module.tables[tableIndex].type() == TableElementType::Funcref);
    196197
    197198    return { };
     
    380381}
    381382
    382 auto Validate::addCallIndirect(const Signature& signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
    383 {
    384     WASM_VALIDATOR_FAIL_IF(m_module.tableInformation.type() != TableElementType::Funcref, "Table must have type Anyfunc to call");
     383auto Validate::addCallIndirect(unsigned tableIndex, const Signature& signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
     384{
     385    RELEASE_ASSERT(tableIndex < m_module.tableCount());
     386    RELEASE_ASSERT(m_module.tables[tableIndex].type() == TableElementType::Funcref);
    385387    const auto argumentCount = signature.argumentCount();
    386388    WASM_VALIDATOR_FAIL_IF(argumentCount != args.size() - 1, "arity mismatch in call_indirect, got ", args.size() - 1, " arguments, expected ", argumentCount);
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp

    r246504 r246571  
    5454    , m_instance(WTFMove(instance))
    5555    , m_vm(&vm)
     56    , m_tables(m_instance->module().moduleInformation().tableCount())
    5657{
    5758    for (unsigned i = 0; i < this->instance().numImportFunctions(); ++i)
     
    8687    visitor.append(thisObject->m_moduleNamespaceObject);
    8788    visitor.append(thisObject->m_memory);
    88     visitor.append(thisObject->m_table);
     89    for (unsigned i = 0; i < thisObject->instance().module().moduleInformation().tableCount(); ++i)
     90        visitor.append(thisObject->m_tables[i]);
    8991    visitor.append(thisObject->m_callee);
    9092    visitor.reportExtraMemoryVisited(thisObject->m_instance->extraMemoryAllocated());
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h

    r245765 r246571  
    7272    Wasm::MemoryMode memoryMode() { return memory()->memory().mode(); }
    7373
    74     JSWebAssemblyTable* table() { return m_table.get(); }
    75     void setTable(VM& vm, JSWebAssemblyTable* value) {
    76         ASSERT(!table());
    77         m_table.set(vm, this, value);
    78         instance().setTable(makeRef(*table()->table()));
     74    JSWebAssemblyTable* table(unsigned i) { return m_tables[i].get(); }
     75    void setTable(VM& vm, uint32_t index, JSWebAssemblyTable* value)
     76    {
     77        ASSERT(index < m_tables.size());
     78        ASSERT(!table(index));
     79        m_tables[index].set(vm, this, value);
     80        instance().setTable(index, makeRef(*table(index)->table()));
    7981    }
    8082
     
    99101    WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
    100102    WriteBarrier<JSWebAssemblyMemory> m_memory;
    101     WriteBarrier<JSWebAssemblyTable> m_table;
     103    Vector<WriteBarrier<JSWebAssemblyTable>> m_tables;
    102104    WriteBarrier<WebAssemblyToJSCallee> m_callee;
    103105};
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

    r246504 r246571  
    114114    };
    115115
    116     bool hasTableImport = false;
    117 
    118116    for (const auto& import : moduleInformation.imports) {
    119117        // Validation and linking other than Wasm::ExternalKind::Function is already done in JSWebAssemblyInstance.
     
    265263
    266264        case Wasm::ExternalKind::Table: {
    267             RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure.
    268265            // 7. Otherwise (i is a table import):
    269             hasTableImport = true;
    270266            JSWebAssemblyTable* table = jsDynamicCast<JSWebAssemblyTable*>(vm, value);
    271267            // i. If v is not a WebAssembly.Table object, throw a WebAssembly.LinkError.
     
    273269                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "is not an instance of WebAssembly.Table")));
    274270
    275             uint32_t expectedInitial = moduleInformation.tableInformation.initial();
     271            uint32_t expectedInitial = moduleInformation.tables[import.kindIndex].initial();
    276272            uint32_t actualInitial = table->length();
    277273            if (actualInitial < expectedInitial)
    278274                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "provided an 'initial' that is too small")));
    279275
    280             if (Optional<uint32_t> expectedMaximum = moduleInformation.tableInformation.maximum()) {
     276            if (Optional<uint32_t> expectedMaximum = moduleInformation.tables[import.kindIndex].maximum()) {
    281277                Optional<uint32_t> actualMaximum = table->maximum();
    282278                if (!actualMaximum)
     
    286282            }
    287283
    288             auto expectedType = moduleInformation.tableInformation.type();
     284            auto expectedType = moduleInformation.tables[import.kindIndex].type();
    289285            auto actualType = table->table()->type();
    290286            if (expectedType != actualType)
     
    293289            // ii. Append v to tables.
    294290            // iii. Append v.[[Table]] to imports.
    295             m_instance->setTable(vm, table);
     291            m_instance->setTable(vm, import.kindIndex, table);
    296292            RETURN_IF_EXCEPTION(scope, void());
    297293            break;
     
    303299    }
    304300
    305     {
    306         if (!!moduleInformation.tableInformation && moduleInformation.tableInformation.isImport()) {
     301    for (unsigned i = 0; i < moduleInformation.tableCount(); ++i) {
     302        if (moduleInformation.tables[i].isImport()) {
    307303            // We should either have a Table import or we should have thrown an exception.
    308             RELEASE_ASSERT(hasTableImport);
    309         }
    310 
    311         if (!!moduleInformation.tableInformation && !hasTableImport) {
    312             RELEASE_ASSERT(!moduleInformation.tableInformation.isImport());
     304            RELEASE_ASSERT(m_instance->table(i));
     305        }
     306
     307        if (!m_instance->table(i)) {
     308            RELEASE_ASSERT(!moduleInformation.tables[i].isImport());
    313309            // We create a Table when it's a Table definition.
    314             RefPtr<Wasm::Table> wasmTable = Wasm::Table::tryCreate(moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum(), moduleInformation.tableInformation.type());
     310            RefPtr<Wasm::Table> wasmTable = Wasm::Table::tryCreate(moduleInformation.tables[i].initial(), moduleInformation.tables[i].maximum(), moduleInformation.tables[i].type());
    315311            if (!wasmTable)
    316312                return exception(createJSWebAssemblyLinkError(exec, vm, "couldn't create Table"));
     
    320316            scope.assertNoException();
    321317            ASSERT(table);
    322             m_instance->setTable(vm, table);
     318            m_instance->setTable(vm, i, table);
    323319            RETURN_IF_EXCEPTION(scope, void());
    324320        }
     
    398394        case Wasm::ExternalKind::Table: {
    399395            // This should be guaranteed by module verification.
    400             RELEASE_ASSERT(m_instance->table());
    401             ASSERT(exp.kindIndex == 0);
    402 
    403             exportedValue = m_instance->table();
     396            RELEASE_ASSERT(m_instance->table(exp.kindIndex));
     397            exportedValue = m_instance->table(exp.kindIndex);
    404398            break;
    405399        }
     
    487481    Wasm::CodeBlock* codeBlock = m_instance->instance().codeBlock();
    488482    const Wasm::ModuleInformation& moduleInformation = module.moduleInformation();
    489     JSWebAssemblyTable* table = m_instance->table();
    490483
    491484    const Vector<Wasm::Segment::Ptr>& data = moduleInformation.data;
     
    499492            // imported wasn't compatible. However, those should error out before
    500493            // getting here.
    501             ASSERT(!!table);
     494            ASSERT(!!m_instance->table(element.tableIndex));
    502495
    503496            if (!element.functionIndices.size())
    504497                continue;
    505498
    506             uint32_t tableIndex = element.offset.isGlobalImport()
     499            uint32_t elementIndex = element.offset.isGlobalImport()
    507500                ? static_cast<uint32_t>(m_instance->instance().loadI32Global(element.offset.globalImportIndex()))
    508501                : element.offset.constValue();
    509502
    510             fn(element, tableIndex);
     503            fn(element, element.tableIndex, elementIndex);
    511504
    512505            if (exception)
     
    532525
    533526    // Validation of all element ranges comes before all Table and Memory initialization.
    534     forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex) {
    535         uint64_t lastWrittenIndex = static_cast<uint64_t>(tableIndex) + static_cast<uint64_t>(element.functionIndices.size()) - 1;
    536         if (UNLIKELY(lastWrittenIndex >= table->length()))
     527    forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex, uint32_t elementIndex) {
     528        uint64_t lastWrittenIndex = static_cast<uint64_t>(elementIndex) + static_cast<uint64_t>(element.functionIndices.size()) - 1;
     529        if (UNLIKELY(lastWrittenIndex >= m_instance->table(tableIndex)->length()))
    537530            exception = JSValue(throwException(exec, scope, createJSWebAssemblyLinkError(exec, vm, "Element is trying to set an out of bounds table index"_s)));
    538531    });
     
    553546
    554547    JSGlobalObject* globalObject = m_instance->globalObject(vm);
    555     forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex) {
     548    forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex, uint32_t elementIndex) {
    556549        for (uint32_t i = 0; i < element.functionIndices.size(); ++i) {
    557550            // FIXME: This essentially means we're exporting an import.
     
    569562                    // the only type this could be is WebAssemblyFunction.
    570563                    RELEASE_ASSERT(wasmFunction);
    571                     table->set(tableIndex, wasmFunction);
    572                     ++tableIndex;
     564                    m_instance->table(tableIndex)->set(elementIndex, wasmFunction);
     565                    ++elementIndex;
    573566                    continue;
    574567                }
    575568
    576                 table->set(tableIndex,
     569                m_instance->table(tableIndex)->set(elementIndex,
    577570                    WebAssemblyWrapperFunction::create(vm, globalObject, globalObject->webAssemblyWrapperFunctionStructure(), functionImport, functionIndex, m_instance.get(), signatureIndex));
    578                 ++tableIndex;
     571                ++elementIndex;
    579572                continue;
    580573            }
     
    590583                vm, globalObject, globalObject->webAssemblyFunctionStructure(), signature.argumentCount(), String(), m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
    591584
    592             table->set(tableIndex, function);
    593             ++tableIndex;
     585            m_instance->table(tableIndex)->set(elementIndex, function);
     586            ++elementIndex;
    594587        }
    595588    });
  • trunk/Source/JavaScriptCore/wasm/wasm.json

    r246504 r246571  
    6868        "get_global":          { "category": "special",    "value":  35, "return": ["any"],      "parameter": [],                       "immediate": [{"name": "global_index",   "type": "varuint32"}],                                            "description": "read a global variable" },
    6969        "set_global":          { "category": "special",    "value":  36, "return": [],           "parameter": ["any"],                  "immediate": [{"name": "global_index",   "type": "varuint32"}],                                            "description": "write a global variable" },
    70         "table.get":           { "category": "special",    "value":  37, "return": ["anyref"],   "parameter": ["i32"],                  "immediate": [],                                                                                           "description": "get a table value" },
    71         "table.set":           { "category": "special",    "value":  38, "return": [],           "parameter": ["i32", "anyref"],        "immediate": [],                                                                                           "description": "set a table value" },
     70        "table.get":           { "category": "special",    "value":  37, "return": ["anyref"],   "parameter": ["i32"],                  "immediate": [{"name": "table_index",    "type": "varuint32"}],                                            "description": "get a table value" },
     71        "table.set":           { "category": "special",    "value":  38, "return": [],           "parameter": ["i32", "anyref"],        "immediate": [{"name": "table_index",    "type": "varuint32"}],                                            "description": "set a table value" },
    7272        "call":                { "category": "call",       "value":  16, "return": ["call"],     "parameter": ["call"],                 "immediate": [{"name": "function_index", "type": "varuint32"}],                                            "description": "call a function by its index" },
    73         "call_indirect":       { "category": "call",       "value":  17, "return": ["call"],     "parameter": ["call"],                 "immediate": [{"name": "type_index",     "type": "varuint32"}, {"name": "reserved", "type": "varuint1"}],  "description": "call a function indirect with an expected signature" },
     73        "call_indirect":       { "category": "call",       "value":  17, "return": ["call"],     "parameter": ["call"],                 "immediate": [{"name": "type_index",     "type": "varuint32"}, {"name": "table_index","type": "varuint32"}],"description": "call a function indirect with an expected signature" },
    7474        "i32.load8_s":         { "category": "memory",     "value":  44, "return": ["i32"],      "parameter": ["addr"],                 "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset",   "type": "varuint32"}], "description": "load from memory" },
    7575        "i32.load8_u":         { "category": "memory",     "value":  45, "return": ["i32"],      "parameter": ["addr"],                 "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset",   "type": "varuint32"}], "description": "load from memory" },
Note: See TracChangeset for help on using the changeset viewer.