Skip to content
Permalink
Browse files
[WASM-References] Add support for active mods in element section
https://bugs.webkit.org/show_bug.cgi?id=219192

Patch by Dmitry Bezhetskov <dbezhetskov@igalia.com> on 2020-12-02
Reviewed by Yusuke Suzuki.

JSTests:

Fix builder dsl to produce the right element section.
It produces correct wasm code for the previous spec and for the ref-types spec because the core spec is binary compatible with the ref-types.
https://webassembly.github.io/reference-types/core/binary/modules.html#element-section.
Added basic tests for the element section.

* wasm/Builder.js:
(export.default.Builder.prototype._registerSectionBuilders.const.section.in.WASM.description.section.switch.section.case.string_appeared_here.this.section):
* wasm/Builder_WebAssemblyBinary.js:
(const.emitters.Element):
* wasm/references-spec-tests/ref_null.js:
(module):
* wasm/references/element_active_mod.js: Added.
(module):
(basicTest):
(refNullExternInElemsSection):
* wasm/references/element_parsing.js:
* wasm/references/multitable.js:

Source/JavaScriptCore:

Adjust wasm parser to parse new form of element section.
https://webassembly.github.io/reference-types/core/binary/modules.html#element-section.

* wasm/WasmEntryPlan.cpp:
(JSC::Wasm::EntryPlan::prepare):
* wasm/WasmFormat.h:
(JSC::Wasm::Element::Element):
(JSC::Wasm::Element::active const):
* wasm/WasmSectionParser.cpp:
(JSC::Wasm::SectionParser::parseElement):
(JSC::Wasm::SectionParser::validateElementTableIdx):
(JSC::Wasm::SectionParser::parseI32InitExpr):
(JSC::Wasm::SectionParser::parseElemKind):
(JSC::Wasm::SectionParser::parseIndexCountForElemSection):
(JSC::Wasm::SectionParser::parseFuncIdxFromRefExpForElemSection):
(JSC::Wasm::SectionParser::parseFuncIdxForElemSection):
* wasm/WasmSectionParser.h:
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::evaluate):

Canonical link: https://commits.webkit.org/232035@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@270344 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
dbezhetskov authored and webkit-commit-queue committed Dec 2, 2020
1 parent eaa09ac commit 741831a3e6268130ffae963e8e9ef32501bed77d
Showing 13 changed files with 383 additions and 51 deletions.
@@ -1,3 +1,29 @@
2020-12-02 Dmitry Bezhetskov <dbezhetskov@igalia.com>

[WASM-References] Add support for active mods in element section
https://bugs.webkit.org/show_bug.cgi?id=219192

Reviewed by Yusuke Suzuki.

Fix builder dsl to produce the right element section.
It produces correct wasm code for the previous spec and for the ref-types spec because the core spec is binary compatible with the ref-types.
https://webassembly.github.io/reference-types/core/binary/modules.html#element-section.
Added basic tests for the element section.


* wasm/Builder.js:
(export.default.Builder.prototype._registerSectionBuilders.const.section.in.WASM.description.section.switch.section.case.string_appeared_here.this.section):
* wasm/Builder_WebAssemblyBinary.js:
(const.emitters.Element):
* wasm/references-spec-tests/ref_null.js:
(module):
* wasm/references/element_active_mod.js: Added.
(module):
(basicTest):
(refNullExternInElemsSection):
* wasm/references/element_parsing.js:
* wasm/references/multitable.js:

2020-11-30 Sergey Rubanov <chi187@gmail.com>

Add support for the Wasm i64 sign-extension-ops proposal
@@ -594,8 +594,8 @@ export default class Builder {
const s = this._addSection(section);
const elementBuilder = {
End: () => this,
Element: ({tableIndex = 0, offset, functionIndices}) => {
s.data.push({tableIndex, offset, functionIndices});
Element: ({tableIndex = 0, offset, elemkind = 0, functionIndices}) => {
s.data.push({tableIndex, offset, elemkind, functionIndices});
return _errorHandlingProxyFor(elementBuilder);
}
};
@@ -197,10 +197,13 @@ const emitters = {
Element: (section, bin) => {
const data = section.data;
put(bin, "varuint32", data.length);
for (const {tableIndex, offset, functionIndices} of data) {
if (tableIndex != 0)
put(bin, "uint8", 2);
put(bin, "varuint32", tableIndex);
for (const {tableIndex, offset, elemkind, functionIndices} of data) {
let flags = tableIndex == 0 ? 0 : 2;
put(bin, "uint8", flags);

if (flags == 2) {
put(bin, "varuint32", tableIndex);
}

let initExpr;
if (typeof offset === "number")
@@ -209,6 +212,10 @@ const emitters = {
initExpr = offset;
putInitExpr(bin, initExpr);

if (flags == 2) {
put(bin, "uint8", elemkind);
}

put(bin, "varuint32", functionIndices.length);
for (const functionIndex of functionIndices)
put(bin, "varuint32", functionIndex);
@@ -62,7 +62,7 @@ function module(bytes, valid = true) {
throw new Error("Wasm validate throws");
}
if (validated !== valid) {
//throw new Error("Wasm validate failure" + (valid ? "" : " expected"));
throw new Error("Wasm validate failure" + (valid ? "" : " expected"));
}
return new WebAssembly.Module(buffer);
}
@@ -0,0 +1,59 @@
//@ runWebAssemblySuite("--useWebAssemblyReferences=true")
import * as assert from '../assert.js';

function module(bytes, valid = true) {
let buffer = new ArrayBuffer(bytes.length);
let view = new Uint8Array(buffer);
for (let i = 0; i < bytes.length; ++i) {
view[i] = bytes.charCodeAt(i);
}
return new WebAssembly.Module(buffer);
}

function basicTest() {
/*
(module
(func $f (result i32)
(i32.const 37)
)
(func $g (result i32)
(i32.const 42)
)
(table $t1 10 funcref)
(table $t2 20 funcref)
(elem (i32.const 3) funcref (ref.func $g) (ref.null func) (ref.func $f) (ref.null func))
(elem (table $t2) (i32.const 7) funcref (ref.func $f) (ref.null func) (ref.func $g))
(func (export "get_tbl1") (param $idx i32) (result funcref)
(table.get $t1 (local.get $idx))
)
(func (export "get_tbl2") (param $idx i32) (result funcref)
(table.get $t2 (local.get $idx))
)
)
*/
let instance = new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x0a\x02\x60\x00\x01\x7f\x60\x01\x7f\x01\x70\x03\x05\x04\x00\x00\x01\x01\x04\x07\x02\x70\x00\x0a\x70\x00\x14\x07\x17\x02\x08\x67\x65\x74\x5f\x74\x62\x6c\x31\x00\x02\x08\x67\x65\x74\x5f\x74\x62\x6c\x32\x00\x03\x09\x22\x02\x04\x41\x03\x0b\x04\xd2\x01\x0b\xd0\x70\x0b\xd2\x00\x0b\xd0\x70\x0b\x06\x01\x41\x07\x0b\x70\x03\xd2\x00\x0b\xd0\x70\x0b\xd2\x01\x0b\x0a\x19\x04\x04\x00\x41\x25\x0b\x04\x00\x41\x2a\x0b\x06\x00\x20\x00\x25\x00\x0b\x06\x00\x20\x00\x25\x01\x0b"));

assert.eq(instance.exports.get_tbl1(3)(), 42);
assert.eq(instance.exports.get_tbl1(4), null);
assert.eq(instance.exports.get_tbl1(5)(), 37);
assert.eq(instance.exports.get_tbl1(6), null);

assert.eq(instance.exports.get_tbl2(7)(), 37);
assert.eq(instance.exports.get_tbl2(8), null);
assert.eq(instance.exports.get_tbl2(9)(), 42);
}

function refNullExternInElemsSection() {
/*
(module
(table $t 10 funcref)
(elem (i32.const 3) funcref (ref.null extern))
)
*/
assert.throws(() => module("\x00\x61\x73\x6d\x01\x00\x00\x00\x04\x04\x01\x70\x00\x0a\x09\x09\x01\x04\x41\x03\x0b\x01\xd0\x6f\x0b"),
WebAssembly.CompileError,
"WebAssembly.Module doesn't parse at byte 24: ref.null extern is forbidden in element section's, 0th element's 0th index (evaluating 'new WebAssembly.Module(buffer)')");
}

basicTest();
refNullExternInElemsSection();
@@ -23,4 +23,4 @@ assert.throws(() => module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x97\x80\x80\x80
// + "\x02"
+ "\x01"
+ "\x41\x01\x0b\x01\x02\x0a\xd4\x80\x80\x80\x00\x07\x85\x80\x80\x80\x00\x00\x20\x00\xd1\x0b\x85\x80\x80\x80\x00\x00\x20\x00\xd1\x0b\x82\x80\x80\x80\x00\x00\x0b\x88\x80\x80\x80\x00\x00\x41\x01\x20\x00\x26\x00\x0b\x8c\x80\x80\x80\x00\x00\x41\x01\xd0\x26\x00\x41\x01\xd0\x26\x01\x0b\x88\x80\x80\x80\x00\x00\x20\x00\x25\x00\x10\x00\x0b\x88\x80\x80\x80\x00\x00\x20\x00\x25\x01\x10\x01\x0b"),
Error, "WebAssembly.Module doesn't parse at byte 143: can't get 0th Element reserved byte, which should be either 0x00 or 0x02 followed by a table index (evaluating 'new WebAssembly.Module(buffer)')");
Error, "WebAssembly.Module doesn't parse at byte 143: unsupported 0th Element reserved byte (evaluating 'new WebAssembly.Module(buffer)')");
@@ -304,7 +304,7 @@ assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder
.Function("ret42", { params: [], ret: "i32" })
.I32Const(42)
.End()
.End().WebAssembly().get())), Error, "WebAssembly.Module doesn't parse at byte 41: Table 0 must have type 'funcref' to have an element section (evaluating 'new WebAssembly.Module')")
.End().WebAssembly().get())), Error, "WebAssembly.Module doesn't parse at byte 42: Table 0 must have type 'funcref' to have an element section (evaluating 'new WebAssembly.Module')")

assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
.Type().End()
@@ -1,3 +1,30 @@
2020-12-02 Dmitry Bezhetskov <dbezhetskov@igalia.com>

[WASM-References] Add support for active mods in element section
https://bugs.webkit.org/show_bug.cgi?id=219192

Reviewed by Yusuke Suzuki.

Adjust wasm parser to parse new form of element section.
https://webassembly.github.io/reference-types/core/binary/modules.html#element-section.

* wasm/WasmEntryPlan.cpp:
(JSC::Wasm::EntryPlan::prepare):
* wasm/WasmFormat.h:
(JSC::Wasm::Element::Element):
(JSC::Wasm::Element::active const):
* wasm/WasmSectionParser.cpp:
(JSC::Wasm::SectionParser::parseElement):
(JSC::Wasm::SectionParser::validateElementTableIdx):
(JSC::Wasm::SectionParser::parseI32InitExpr):
(JSC::Wasm::SectionParser::parseElemKind):
(JSC::Wasm::SectionParser::parseIndexCountForElemSection):
(JSC::Wasm::SectionParser::parseFuncIdxFromRefExpForElemSection):
(JSC::Wasm::SectionParser::parseFuncIdxForElemSection):
* wasm/WasmSectionParser.h:
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::evaluate):

2020-12-01 Sergey Rubanov <chi187@gmail.com>

Fix Aarch64 build failure
@@ -143,9 +143,9 @@ void EntryPlan::prepare()
}

for (const auto& element : m_moduleInformation->elements) {
for (const uint32_t elementIndex : element.functionIndices) {
if (elementIndex >= importFunctionCount)
m_exportedFunctionIndices.add(elementIndex - importFunctionCount);
for (const uint32_t functionIndex : element.functionIndices) {
if (!Element::isNullFuncIndex(functionIndex) && functionIndex >= importFunctionCount)
m_exportedFunctionIndices.add(functionIndex - importFunctionCount);
}
}

@@ -38,6 +38,7 @@
#include "WasmOps.h"
#include "WasmPageCount.h"
#include "WasmSignature.h"
#include <cstdint>
#include <limits>
#include <memory>
#include <wtf/Optional.h>
@@ -226,13 +227,34 @@ struct Segment {

struct Element {
WTF_MAKE_STRUCT_FAST_ALLOCATED;
Element(uint32_t tableIndex, I32InitExpr offset)
: tableIndex(tableIndex)
, offset(offset)

// nullFuncIndex represents the case when an element segment (of type funcref)
// contains a null element.
constexpr static uint32_t nullFuncIndex = UINT32_MAX;

enum class Kind : uint8_t {
Active,
Passive,
Declared,
};

Element(Element::Kind kind, TableElementType elementType, uint32_t tableIndex, Optional<I32InitExpr> initExpr)
: kind(kind)
, elementType(elementType)
, tableIndex(tableIndex)
, offsetIfActive(initExpr)
{ }

bool isActive() const { return kind == Kind::Active; }

static bool isNullFuncIndex(uint32_t idx) { return idx == nullFuncIndex; }

Kind kind;
TableElementType elementType;
uint32_t tableIndex;
I32InitExpr offset;
Optional<I32InitExpr> offsetIfActive;

// Index may be nullFuncIndex.
Vector<uint32_t> functionIndices;
};

0 comments on commit 741831a

Please sign in to comment.