[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):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@270344 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog
index 2e545ed..6b3e5fc 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -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
diff --git a/JSTests/wasm/Builder.js b/JSTests/wasm/Builder.js
index b4d72b1..32ffe6b 100644
--- a/JSTests/wasm/Builder.js
+++ b/JSTests/wasm/Builder.js
@@ -594,8 +594,8 @@
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);
}
};
diff --git a/JSTests/wasm/Builder_WebAssemblyBinary.js b/JSTests/wasm/Builder_WebAssemblyBinary.js
index b0f4387..358bb48 100644
--- a/JSTests/wasm/Builder_WebAssemblyBinary.js
+++ b/JSTests/wasm/Builder_WebAssemblyBinary.js
@@ -197,10 +197,13 @@
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 @@
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);
diff --git a/JSTests/wasm/references-spec-tests/ref_null.js b/JSTests/wasm/references-spec-tests/ref_null.js
index 9dda7af..5325aba 100644
--- a/JSTests/wasm/references-spec-tests/ref_null.js
+++ b/JSTests/wasm/references-spec-tests/ref_null.js
@@ -62,7 +62,7 @@
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);
}
diff --git a/JSTests/wasm/references/element_active_mod.js b/JSTests/wasm/references/element_active_mod.js
new file mode 100644
index 0000000..c170840
--- /dev/null
+++ b/JSTests/wasm/references/element_active_mod.js
@@ -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();
diff --git a/JSTests/wasm/references/element_parsing.js b/JSTests/wasm/references/element_parsing.js
index 93be1fd..01f8902 100644
--- a/JSTests/wasm/references/element_parsing.js
+++ b/JSTests/wasm/references/element_parsing.js
@@ -23,4 +23,4 @@
// + "\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)')");
diff --git a/JSTests/wasm/references/multitable.js b/JSTests/wasm/references/multitable.js
index 48a8560..1007015 100644
--- a/JSTests/wasm/references/multitable.js
+++ b/JSTests/wasm/references/multitable.js
@@ -304,7 +304,7 @@
.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()
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 1d1731e..45c4937 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -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
diff --git a/Source/JavaScriptCore/wasm/WasmEntryPlan.cpp b/Source/JavaScriptCore/wasm/WasmEntryPlan.cpp
index 0a9cf05..943c4da 100644
--- a/Source/JavaScriptCore/wasm/WasmEntryPlan.cpp
+++ b/Source/JavaScriptCore/wasm/WasmEntryPlan.cpp
@@ -143,9 +143,9 @@
}
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);
}
}
diff --git a/Source/JavaScriptCore/wasm/WasmFormat.h b/Source/JavaScriptCore/wasm/WasmFormat.h
index 1fcfdf2..1c7ec47 100644
--- a/Source/JavaScriptCore/wasm/WasmFormat.h
+++ b/Source/JavaScriptCore/wasm/WasmFormat.h
@@ -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 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;
};
diff --git a/Source/JavaScriptCore/wasm/WasmSectionParser.cpp b/Source/JavaScriptCore/wasm/WasmSectionParser.cpp
index f653e29..d5ad3d0 100644
--- a/Source/JavaScriptCore/wasm/WasmSectionParser.cpp
+++ b/Source/JavaScriptCore/wasm/WasmSectionParser.cpp
@@ -384,41 +384,145 @@
WASM_PARSER_FAIL_IF(elementCount > maxTableEntries, "Element section's count is too big ", elementCount, " maximum ", maxTableEntries);
WASM_PARSER_FAIL_IF(!m_info->elements.tryReserveCapacity(elementCount), "can't allocate memory for ", elementCount, " Elements");
for (unsigned elementNum = 0; elementNum < elementCount; ++elementNum) {
- uint32_t tableIndex;
- uint64_t initExprBits;
- uint8_t initOpcode;
- uint32_t indexCount;
+ uint8_t elementFlags;
+ WASM_PARSER_FAIL_IF(!parseUInt8(elementFlags), "can't get ", elementNum, "th Element reserved byte, which should be element flags");
- uint8_t magic;
- WASM_PARSER_FAIL_IF(!parseUInt8(magic) || (magic && magic != 2), "can't get ", elementNum, "th Element reserved byte, which should be either 0x00 or 0x02 followed by a table index");
+ switch (elementFlags) {
+ case 0x00: {
+ constexpr uint32_t tableIndex = 0;
+ WASM_FAIL_IF_HELPER_FAILS(validateElementTableIdx(tableIndex));
- if (magic == 2)
- WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index");
- else
- tableIndex = 0;
-
- WASM_PARSER_FAIL_IF(tableIndex >= m_info->tableCount(), "Element section for Table ", tableIndex, " exceeds available Table ", m_info->tableCount());
- WASM_PARSER_FAIL_IF(m_info->tables[tableIndex].type() != TableElementType::Funcref, "Table ", tableIndex, " must have type 'funcref' to have an element section");
- Type initExprType;
- WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType));
- WASM_PARSER_FAIL_IF(initExprType != I32, "Element init_expr must produce an i32");
- WASM_PARSER_FAIL_IF(!parseVarUInt32(indexCount), "can't get ", elementNum, "th index count for Element section");
- WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount);
+ Optional<I32InitExpr> initExpr;
+ WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr));
- ASSERT(!!m_info->tables[tableIndex]);
+ uint32_t indexCount;
+ WASM_FAIL_IF_HELPER_FAILS(parseIndexCountForElementSection(indexCount, elementNum));
+ ASSERT(!!m_info->tables[tableIndex]);
- Element element(tableIndex, makeI32InitExpr(initOpcode, initExprBits));
- WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
+ Element element(Element::Kind::Active, TableElementType::Funcref, tableIndex, WTFMove(initExpr));
+ WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
- for (unsigned index = 0; index < indexCount; ++index) {
- uint32_t functionIndex;
- WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index");
- WASM_PARSER_FAIL_IF(functionIndex >= m_info->functionIndexSpaceSize(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_info->functionIndexSpaceSize());
+ for (uint32_t index = 0; index < indexCount; ++index) {
+ uint32_t funcIdx;
+ WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxForElementSection(funcIdx, elementNum, index));
+ element.functionIndices.uncheckedAppend(funcIdx);
+ }
- element.functionIndices.uncheckedAppend(functionIndex);
+ m_info->elements.uncheckedAppend(WTFMove(element));
+ break;
}
+ case 0x01: {
+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+ WASM_PARSER_FAIL_IF(true, "unsupported ", elementNum, "th Element reserved byte");
+ // Add support for passive element segments and table.init.
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=219297
+ break;
+ }
+ case 0x02: {
+ uint32_t tableIndex;
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index");
+ WASM_FAIL_IF_HELPER_FAILS(validateElementTableIdx(tableIndex));
- m_info->elements.uncheckedAppend(WTFMove(element));
+ Optional<I32InitExpr> initExpr;
+ WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr));
+
+ uint8_t elementKind;
+ WASM_FAIL_IF_HELPER_FAILS(parseElementKind(elementKind));
+
+ uint32_t indexCount;
+ WASM_FAIL_IF_HELPER_FAILS(parseIndexCountForElementSection(indexCount, elementNum));
+ ASSERT(!!m_info->tables[tableIndex]);
+
+ Element element(Element::Kind::Active, TableElementType::Funcref, tableIndex, WTFMove(initExpr));
+ WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
+
+ for (unsigned index = 0; index < indexCount; ++index) {
+ uint32_t funcIdx;
+ WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxForElementSection(funcIdx, elementNum, index));
+ element.functionIndices.uncheckedAppend(funcIdx);
+ }
+
+ m_info->elements.uncheckedAppend(WTFMove(element));
+ break;
+ }
+ case 0x03: {
+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+ WASM_PARSER_FAIL_IF(true, "unsupported ", elementNum, "th Element reserved byte");
+ // Add support for declarative element segments.
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=219385
+ break;
+ }
+ case 0x04: {
+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+ constexpr uint32_t tableIndex = 0;
+ WASM_FAIL_IF_HELPER_FAILS(validateElementTableIdx(tableIndex));
+
+ Optional<I32InitExpr> initExpr;
+ WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr));
+
+ uint32_t indexCount;
+ WASM_FAIL_IF_HELPER_FAILS(parseIndexCountForElementSection(indexCount, elementNum));
+ ASSERT(!!m_info->tables[tableIndex]);
+
+ Element element(Element::Kind::Active, TableElementType::Funcref, tableIndex, WTFMove(initExpr));
+ WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
+
+ for (unsigned index = 0; index < indexCount; ++index) {
+ uint32_t funcIdx;
+ WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxFromRefExpForElementSection(funcIdx, elementNum, index));
+ element.functionIndices.uncheckedAppend(funcIdx);
+ }
+
+ m_info->elements.uncheckedAppend(WTFMove(element));
+ break;
+ }
+ case 0x05: {
+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+ WASM_PARSER_FAIL_IF(true, "unsupported ", elementNum, "th Element reserved byte");
+ // Add support for passive element segments and table.init.
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=219297
+ break;
+ }
+ case 0x06: {
+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+
+ uint32_t tableIndex;
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index");
+ WASM_FAIL_IF_HELPER_FAILS(validateElementTableIdx(tableIndex));
+
+ Optional<I32InitExpr> initExpr;
+ WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr));
+
+ Type refType;
+ WASM_PARSER_FAIL_IF(!parseRefType(refType), "can't parse reftype in elem section");
+ WASM_PARSER_FAIL_IF(refType != Funcref, "reftype in element section should be funcref");
+
+ uint32_t indexCount;
+ WASM_FAIL_IF_HELPER_FAILS(parseIndexCountForElementSection(indexCount, elementNum));
+ ASSERT(!!m_info->tables[tableIndex]);
+
+ Element element(Element::Kind::Active, TableElementType::Funcref, tableIndex, WTFMove(initExpr));
+ WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
+
+ for (unsigned index = 0; index < indexCount; ++index) {
+ uint32_t funcIdx;
+ WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxFromRefExpForElementSection(funcIdx, elementNum, index));
+ element.functionIndices.uncheckedAppend(funcIdx);
+ }
+
+ m_info->elements.uncheckedAppend(WTFMove(element));
+ break;
+ }
+ case 0x07: {
+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+ WASM_PARSER_FAIL_IF(true, "unsupported ", elementNum, "th Element reserved byte");
+ // Add support for declarative element segments.
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=219385
+ break;
+ }
+ default:
+ WASM_PARSER_FAIL_IF(true, "can't get ", elementNum, "th Element reserved byte");
+ }
}
return { };
@@ -510,6 +614,80 @@
return { };
}
+auto SectionParser::validateElementTableIdx(uint32_t tableIndex) -> PartialResult
+{
+ WASM_PARSER_FAIL_IF(tableIndex >= m_info->tableCount(), "Element section for Table ", tableIndex, " exceeds available Table ", m_info->tableCount());
+ WASM_PARSER_FAIL_IF(m_info->tables[tableIndex].type() != TableElementType::Funcref, "Table ", tableIndex, " must have type 'funcref' to have an element section");
+
+ return { };
+}
+
+auto SectionParser::parseI32InitExpr(Optional<I32InitExpr>& initExpr) -> PartialResult
+{
+ uint8_t initOpcode;
+ uint64_t initExprBits;
+ Type initExprType;
+ WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType));
+ WASM_PARSER_FAIL_IF(initExprType != I32, "Element init_expr must produce an i32");
+ initExpr = makeI32InitExpr(initOpcode, initExprBits);
+
+ return { };
+}
+
+auto SectionParser::parseElementKind(uint8_t& resultElementKind) -> PartialResult
+{
+ uint8_t elementKind;
+ WASM_PARSER_FAIL_IF(!parseUInt8(elementKind), "can't get element kind");
+ WASM_PARSER_FAIL_IF(!!elementKind, "element kind must be zero");
+ resultElementKind = elementKind;
+
+ return { };
+}
+
+auto SectionParser::parseIndexCountForElementSection(uint32_t& resultIndexCount, const unsigned elementNum) -> PartialResult
+{
+ uint32_t indexCount;
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(indexCount), "can't get ", elementNum, "th index count for Element section");
+ WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount);
+ resultIndexCount = indexCount;
+
+ return { };
+}
+
+auto SectionParser::parseFuncIdxFromRefExpForElementSection(uint32_t& funcIdx, const unsigned elementNum, const unsigned index) -> PartialResult
+{
+ uint8_t opcode;
+ WASM_PARSER_FAIL_IF(!parseUInt8(opcode), "can't get opcode for exp in element section's ", elementNum, "th element's ", index, "th index");
+ WASM_PARSER_FAIL_IF((opcode != RefFunc) && (opcode != RefNull), "opcode for exp in element section's should be either ref.func or ref.null ", elementNum, "th element's ", index, "th index");
+
+ if (opcode == RefFunc) {
+ uint32_t functionIndex;
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index");
+ WASM_PARSER_FAIL_IF(functionIndex >= m_info->functionIndexSpaceSize(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_info->functionIndexSpaceSize());
+ funcIdx = functionIndex;
+ } else {
+ Type typeOfNull;
+ WASM_PARSER_FAIL_IF(!parseRefType(typeOfNull), "ref.null type must be a func type in elem section");
+ WASM_PARSER_FAIL_IF(typeOfNull != Funcref, "ref.null extern is forbidden in element section's, ", elementNum, "th element's ", index, "th index");
+ funcIdx = Element::nullFuncIndex;
+ }
+
+ WASM_PARSER_FAIL_IF(!parseUInt8(opcode), "can't get opcode for exp end in element section's ", elementNum, "th element's ", index, "th index");
+ WASM_PARSER_FAIL_IF(opcode != End, "malformed expr in element section's", elementNum, "th element's ", index, "th index");
+
+ return { };
+}
+
+auto SectionParser::parseFuncIdxForElementSection(uint32_t& funcIdx, const unsigned elementNum, const unsigned index) -> PartialResult
+{
+ uint32_t functionIndex;
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index");
+ WASM_PARSER_FAIL_IF(functionIndex >= m_info->functionIndexSpaceSize(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_info->functionIndexSpaceSize());
+ funcIdx = functionIndex;
+
+ return { };
+}
+
auto SectionParser::parseGlobalType(GlobalInformation& global) -> PartialResult
{
uint8_t mutability;
diff --git a/Source/JavaScriptCore/wasm/WasmSectionParser.h b/Source/JavaScriptCore/wasm/WasmSectionParser.h
index 86b980a..03a7eec 100644
--- a/Source/JavaScriptCore/wasm/WasmSectionParser.h
+++ b/Source/JavaScriptCore/wasm/WasmSectionParser.h
@@ -67,6 +67,13 @@
PartialResult WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, Optional<uint32_t>& maximum, bool& isShared, LimitsType);
PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&, Type& initExprType);
+ PartialResult WARN_UNUSED_RETURN validateElementTableIdx(uint32_t);
+ PartialResult WARN_UNUSED_RETURN parseI32InitExpr(Optional<I32InitExpr>&);
+ PartialResult WARN_UNUSED_RETURN parseElementKind(uint8_t& elementKind);
+ PartialResult WARN_UNUSED_RETURN parseIndexCountForElementSection(uint32_t&, const unsigned);
+ PartialResult WARN_UNUSED_RETURN parseFuncIdxFromRefExpForElementSection(uint32_t&, const unsigned, const unsigned);
+ PartialResult WARN_UNUSED_RETURN parseFuncIdxForElementSection(uint32_t&, const unsigned, const unsigned);
+
size_t m_offsetInSource;
Ref<ModuleInformation> m_info;
};
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp
index 2064a46..e83b829 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp
@@ -555,9 +555,13 @@
if (!element.functionIndices.size())
continue;
- uint32_t elementIndex = element.offset.isGlobalImport()
- ? static_cast<uint32_t>(m_instance->instance().loadI32Global(element.offset.globalImportIndex()))
- : element.offset.constValue();
+ if (!element.isActive())
+ continue;
+
+ const auto& offset = *element.offsetIfActive;
+ const uint32_t elementIndex = offset.isGlobalImport()
+ ? static_cast<uint32_t>(m_instance->instance().loadI32Global(offset.globalImportIndex()))
+ : offset.constValue();
fn(element, element.tableIndex, elementIndex);
@@ -604,13 +608,19 @@
if (UNLIKELY(exception))
return exception.value();
- forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex, uint32_t elementIndex) {
+ forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex, uint32_t startElementIndex) {
for (uint32_t i = 0; i < element.functionIndices.size(); ++i) {
+ const uint32_t elementIndex = startElementIndex + i;
+ const uint32_t functionIndex = element.functionIndices[i];
+ if (Wasm::Element::isNullFuncIndex(functionIndex)) {
+ m_instance->table(tableIndex)->clear(elementIndex);
+ continue;
+ }
+
// FIXME: This essentially means we're exporting an import.
// We need a story here. We need to create a WebAssemblyFunction
// for the import.
// https://bugs.webkit.org/show_bug.cgi?id=165510
- uint32_t functionIndex = element.functionIndices[i];
Wasm::SignatureIndex signatureIndex = module.signatureIndexFromFunctionIndexSpace(functionIndex);
if (functionIndex < codeBlock->functionImportCount()) {
JSObject* functionImport = m_instance->instance().importFunction<WriteBarrier<JSObject>>(functionIndex)->get();
@@ -621,13 +631,11 @@
// the only type this could be is WebAssemblyFunction.
RELEASE_ASSERT(wasmFunction);
m_instance->table(tableIndex)->set(elementIndex, wasmFunction);
- ++elementIndex;
continue;
}
m_instance->table(tableIndex)->set(elementIndex,
WebAssemblyWrapperFunction::create(vm, globalObject, globalObject->webAssemblyWrapperFunctionStructure(), functionImport, functionIndex, m_instance.get(), signatureIndex));
- ++elementIndex;
continue;
}
@@ -640,9 +648,7 @@
// https://bugs.webkit.org/show_bug.cgi?id=165825
WebAssemblyFunction* function = WebAssemblyFunction::create(
vm, globalObject, globalObject->webAssemblyFunctionStructure(), signature.argumentCount(), String(), m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
-
m_instance->table(tableIndex)->set(elementIndex, function);
- ++elementIndex;
}
});