WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-219297-20201126185637.patch (text/plain), 76.47 KB, created by
Dmitry
on 2020-11-26 03:56:39 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Dmitry
Created:
2020-11-26 03:56:39 PST
Size:
76.47 KB
patch
obsolete
>Subversion Revision: 270015 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 368551eaad5e5da24d5379302ce8fe93c84db7a5..baa1258962ffd7ffce889d007a8b3c5e7b54e91f 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,79 @@ >+2020-11-26 Dmitry Bezhetskov <dbezhetskov@igalia.com> >+ >+ [WASM-References] Add table.init >+ https://bugs.webkit.org/show_bug.cgi?id=219297 >+ >+ Reviewed by NOBODY (OOPS!). >+ Spec is here: https://webassembly.github.io/reference-types/core/exec/instructions.html. >+ Implemented in the same way as previously implemented table.* instructions. >+ >+ * bytecode/BytecodeList.rb: >+ * llint/WebAssembly.asm: >+ * wasm/WasmAirIRGenerator.cpp: >+ (JSC::Wasm::AirIRGenerator::addTableInit): >+ * wasm/WasmB3IRGenerator.cpp: >+ (JSC::Wasm::B3IRGenerator::addTableInit): >+ * wasm/WasmFormat.h: >+ (JSC::Wasm::Element::Element): >+ (JSC::Wasm::Element::length const): >+ (JSC::Wasm::Element::passive const): >+ * wasm/WasmFunctionParser.h: >+ (JSC::Wasm::FunctionParser<Context>::parseExpression): >+ * wasm/WasmInstance.cpp: >+ (JSC::Wasm::Instance::Instance): >+ (JSC::Wasm::Instance::elem const): >+ (JSC::Wasm::Instance::initElementSegment): >+ (JSC::Wasm::Instance::tableInit): >+ * wasm/WasmInstance.h: >+ (JSC::Wasm::Instance::isImportFunction const): >+ * wasm/WasmLLIntGenerator.cpp: >+ (JSC::Wasm::LLIntGenerator::addTableInit): >+ * wasm/WasmModuleInformation.h: >+ (JSC::Wasm::ModuleInformation::elementCount const): >+ * wasm/WasmOperations.cpp: >+ (JSC::Wasm::JSC_DEFINE_JIT_OPERATION): >+ * wasm/WasmOperations.h: >+ * wasm/WasmSectionParser.cpp: >+ (JSC::Wasm::SectionParser::parseElement): >+ * wasm/WasmSlowPaths.cpp: >+ (JSC::LLInt::WASM_SLOW_PATH_DECL): >+ * wasm/WasmSlowPaths.h: >+ * wasm/js/WebAssemblyModuleRecord.cpp: >+ (JSC::WebAssemblyModuleRecord::link): >+ (JSC::WebAssemblyModuleRecord::evaluate): >+ * wasm/wasm.json: >+ >+2020-11-19 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 NOBODY (OOPS!). >+ Adjust wasm parser to parse new form of element section. >+ Don't need to worry about previous forms because they are compatible. >+ >+ Add support for vec(exp) in element section: >+ https://webassembly.github.io/reference-types/core/binary/modules.html#element-section >+ Just transformed (ref.func idx) -> idx and (ref.null func) -> null. >+ For null values call table->clear to zero value. >+ >+ * 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-11-18 Dmitry Bezhetskov <dbezhetskov@igalia.com> > > [WASM-References] Remove subtyping rule for externref and funcref >diff --git a/Source/JavaScriptCore/bytecode/BytecodeList.rb b/Source/JavaScriptCore/bytecode/BytecodeList.rb >index 7463a321a194726790d7d452cc042b81e021cea6..1f4e31f2abe71e2ba919126a765044fae8edf287 100644 >--- a/Source/JavaScriptCore/bytecode/BytecodeList.rb >+++ b/Source/JavaScriptCore/bytecode/BytecodeList.rb >@@ -1587,6 +1587,15 @@ op :table_set, > tableIndex: unsigned, > } > >+op :table_init, >+ args: { >+ dstOffset: VirtualRegister, >+ srcOffset: VirtualRegister, >+ length: VirtualRegister, >+ elementIndex: unsigned, >+ tableIndex: unsigned, >+ } >+ > op :table_size, > args: { > dst: VirtualRegister, >diff --git a/Source/JavaScriptCore/llint/WebAssembly.asm b/Source/JavaScriptCore/llint/WebAssembly.asm >index 352c80765c0065d26c79e9893cc14ac7a7fdb545..241ff7463bb13a680097cf720233287c9e90c30c 100644 >--- a/Source/JavaScriptCore/llint/WebAssembly.asm >+++ b/Source/JavaScriptCore/llint/WebAssembly.asm >@@ -561,6 +561,7 @@ noWide(wasm_wide32) > slowWasmOp(ref_func) > slowWasmOp(table_get) > slowWasmOp(table_set) >+slowWasmOp(table_init) > slowWasmOp(table_size) > slowWasmOp(table_fill) > slowWasmOp(table_grow) >diff --git a/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp b/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp >index 9a85c6a8d152ba48d56cd0b0d85827e6e73ac970..c597025e9f38d72c0bfccd1ac0f55d8113b6269d 100644 >--- a/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp >+++ b/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp >@@ -259,6 +259,7 @@ public: > // Tables > PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType index, ExpressionType& result); > PartialResult WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType index, ExpressionType value); >+ PartialResult WARN_UNUSED_RETURN addTableInit(unsigned, unsigned, ExpressionType dstOffset, ExpressionType srcOffset, ExpressionType length); > PartialResult WARN_UNUSED_RETURN addTableSize(unsigned, ExpressionType& result); > PartialResult WARN_UNUSED_RETURN addTableGrow(unsigned, ExpressionType fill, ExpressionType delta, ExpressionType& result); > PartialResult WARN_UNUSED_RETURN addTableFill(unsigned, ExpressionType offset, ExpressionType fill, ExpressionType count); >@@ -1089,6 +1090,33 @@ auto AirIRGenerator::addTableSet(unsigned tableIndex, ExpressionType index, Expr > return { }; > } > >+auto AirIRGenerator::addTableInit(unsigned elementIndex, unsigned tableIndex, ExpressionType dstOffset, ExpressionType srcOffset, ExpressionType length) -> PartialResult >+{ >+ ASSERT(dstOffset.tmp()); >+ ASSERT(dstOffset.type() == Type::I32); >+ >+ ASSERT(srcOffset.tmp()); >+ ASSERT(srcOffset.type() == Type::I32); >+ >+ ASSERT(length.tmp()); >+ ASSERT(length.type() == Type::I32); >+ >+ auto result = tmpForType(Type::I32); >+ emitCCall( >+ &operationWasmTableInit, result, instanceValue(), >+ addConstant(Type::I32, elementIndex), >+ addConstant(Type::I32, tableIndex), >+ dstOffset, srcOffset, length); >+ >+ emitCheck([&] { >+ return Inst(BranchTest32, nullptr, Arg::resCond(MacroAssembler::Zero), result, result); >+ }, [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) { >+ this->emitThrowException(jit, ExceptionType::OutOfBoundsTableAccess); >+ }); >+ >+ return { }; >+} >+ > auto AirIRGenerator::addTableSize(unsigned tableIndex, ExpressionType& result) -> PartialResult > { > // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>. >diff --git a/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp b/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp >index d79ea71e4c0e8687c14cb60c2b452c7bcf6d9674..6b1007357d882807fb2808661f546c0dea55d891 100644 >--- a/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp >+++ b/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp >@@ -215,6 +215,7 @@ public: > // Tables > PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType index, ExpressionType& result); > PartialResult WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType index, ExpressionType value); >+ PartialResult WARN_UNUSED_RETURN addTableInit(unsigned, unsigned, ExpressionType dstOffset, ExpressionType srcOffset, ExpressionType length); > PartialResult WARN_UNUSED_RETURN addTableSize(unsigned, ExpressionType& result); > PartialResult WARN_UNUSED_RETURN addTableGrow(unsigned, ExpressionType fill, ExpressionType delta, ExpressionType& result); > PartialResult WARN_UNUSED_RETURN addTableFill(unsigned, ExpressionType offset, ExpressionType fill, ExpressionType count); >@@ -725,6 +726,28 @@ auto B3IRGenerator::addRefFunc(uint32_t index, ExpressionType& result) -> Partia > return { }; > } > >+auto B3IRGenerator::addTableInit(unsigned elementIndex, unsigned tableIndex, ExpressionType dstOffset, ExpressionType srcOffset, ExpressionType length) -> PartialResult >+{ >+ auto result = m_currentBlock->appendNew<CCallValue>( >+ m_proc, toB3Type(I32), origin(), >+ m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunction<OperationPtrTag>(operationWasmTableInit)), >+ instanceValue(), >+ m_currentBlock->appendNew<Const32Value>(m_proc, origin(), elementIndex), >+ m_currentBlock->appendNew<Const32Value>(m_proc, origin(), tableIndex), >+ dstOffset, srcOffset, length); >+ >+ { >+ CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(), >+ m_currentBlock->appendNew<Value>(m_proc, Equal, origin(), result, m_currentBlock->appendNew<Const32Value>(m_proc, origin(), 0))); >+ >+ check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) { >+ this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTableAccess); >+ }); >+ } >+ >+ return { }; >+} >+ > auto B3IRGenerator::addTableSize(unsigned tableIndex, ExpressionType& result) -> PartialResult > { > // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>. >diff --git a/Source/JavaScriptCore/wasm/WasmEntryPlan.cpp b/Source/JavaScriptCore/wasm/WasmEntryPlan.cpp >index 0a9cf0543a4fa9a8fb66def3b07129a634ac3753..624f3aa33fd8f204b8cce0256e22155bf788b5a8 100644 >--- a/Source/JavaScriptCore/wasm/WasmEntryPlan.cpp >+++ b/Source/JavaScriptCore/wasm/WasmEntryPlan.cpp >@@ -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 Optional<uint32_t>& elementIndex : element.functionIndices) { >+ if (elementIndex && *elementIndex >= importFunctionCount) >+ m_exportedFunctionIndices.add(*elementIndex - importFunctionCount); > } > } > >diff --git a/Source/JavaScriptCore/wasm/WasmFormat.h b/Source/JavaScriptCore/wasm/WasmFormat.h >index 1fcfdf2ba200c452b5fa36313da4a47534c475c6..161f329c9976a00356b87fa5e8b32ab5d118e89e 100644 >--- a/Source/JavaScriptCore/wasm/WasmFormat.h >+++ b/Source/JavaScriptCore/wasm/WasmFormat.h >@@ -226,14 +226,35 @@ struct Segment { > > struct Element { > WTF_MAKE_STRUCT_FAST_ALLOCATED; >- Element(uint32_t tableIndex, I32InitExpr offset) >- : tableIndex(tableIndex) >- , offset(offset) >+ enum class Kind { >+ Active, >+ Passive, >+ Declared, >+ }; >+ >+ Element(Element::Kind kind, TableElementType elemType, Optional<uint32_t> tableIndex, Optional<I32InitExpr> initExpr) >+ : kind(kind) >+ , elemType(elemType) >+ , tableIndexIfActive(tableIndex) >+ , offsetIfActive(initExpr) > { } > >- uint32_t tableIndex; >- I32InitExpr offset; >- Vector<uint32_t> functionIndices; >+ Element(Element::Kind kind, TableElementType elemType) >+ : Element(kind, elemType, Optional<uint32_t>(), Optional<I32InitExpr>()) >+ { } >+ >+ uint32_t length() const { return functionIndices.size(); } >+ >+ bool active() const { return kind == Kind::Active; } >+ bool passive() const { return kind == Kind::Passive; } >+ >+ Kind kind; >+ TableElementType elemType; >+ Optional<uint32_t> tableIndexIfActive; >+ Optional<I32InitExpr> offsetIfActive; >+ >+ // If there is no value then item represents ref.null. >+ Vector<Optional<uint32_t>> functionIndices; > }; > > class TableInformation { >diff --git a/Source/JavaScriptCore/wasm/WasmFunctionParser.h b/Source/JavaScriptCore/wasm/WasmFunctionParser.h >index 7a8417d503771934c273bb24ebcbb57f6434ed32..41380ff37bd6b987b94007f87ad9acd375541f82 100644 >--- a/Source/JavaScriptCore/wasm/WasmFunctionParser.h >+++ b/Source/JavaScriptCore/wasm/WasmFunctionParser.h >@@ -446,18 +446,46 @@ FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) > WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled"); > uint8_t extOp; > WASM_PARSER_FAIL_IF(!parseUInt8(extOp), "can't parse table extended opcode"); >- unsigned tableIndex; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index"); >- WASM_VALIDATOR_FAIL_IF(tableIndex >= m_info.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_info.tableCount()); > > switch (static_cast<ExtTableOpType>(extOp)) { >+ case ExtTableOpType::TableInit: { >+ unsigned elementIndex; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(elementIndex), "can't parse element index"); >+ WASM_VALIDATOR_FAIL_IF(elementIndex >= m_info.elementCount(), "element index ", elementIndex, " is invalid, limit is ", m_info.elementCount()); >+ >+ unsigned tableIndex; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse element index"); >+ WASM_VALIDATOR_FAIL_IF(tableIndex >= m_info.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_info.tableCount()); >+ >+ TypedExpression dstOffset; >+ TypedExpression srcOffset; >+ TypedExpression lenght; >+ WASM_TRY_POP_EXPRESSION_STACK_INTO(lenght, "table.init"); >+ WASM_TRY_POP_EXPRESSION_STACK_INTO(srcOffset, "table.init"); >+ WASM_TRY_POP_EXPRESSION_STACK_INTO(dstOffset, "table.init"); >+ >+ WASM_VALIDATOR_FAIL_IF(I32 != dstOffset.type(), "table.init dst_offset to type ", dstOffset.type(), " expected ", I32); >+ WASM_VALIDATOR_FAIL_IF(I32 != srcOffset.type(), "table.init src_offset to type ", srcOffset.type(), " expected ", I32); >+ WASM_VALIDATOR_FAIL_IF(I32 != lenght.type(), "table.init length to type ", lenght.type(), " expected ", I32); >+ >+ WASM_TRY_ADD_TO_CONTEXT(addTableInit(elementIndex, tableIndex, dstOffset, srcOffset, lenght)); >+ break; >+ } > case ExtTableOpType::TableSize: { >+ unsigned tableIndex; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index"); >+ WASM_VALIDATOR_FAIL_IF(tableIndex >= m_info.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_info.tableCount()); >+ > ExpressionType result; > WASM_TRY_ADD_TO_CONTEXT(addTableSize(tableIndex, result)); > m_expressionStack.constructAndAppend(I32, result); > break; > } > case ExtTableOpType::TableGrow: { >+ unsigned tableIndex; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index"); >+ WASM_VALIDATOR_FAIL_IF(tableIndex >= m_info.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_info.tableCount()); >+ > TypedExpression fill; > TypedExpression delta; > WASM_TRY_POP_EXPRESSION_STACK_INTO(delta, "table.grow"); >@@ -472,6 +500,10 @@ FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) > break; > } > case ExtTableOpType::TableFill: { >+ unsigned tableIndex; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index"); >+ WASM_VALIDATOR_FAIL_IF(tableIndex >= m_info.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_info.tableCount()); >+ > TypedExpression offset, fill, count; > WASM_TRY_POP_EXPRESSION_STACK_INTO(count, "table.fill"); > WASM_TRY_POP_EXPRESSION_STACK_INTO(fill, "table.fill"); >diff --git a/Source/JavaScriptCore/wasm/WasmInstance.cpp b/Source/JavaScriptCore/wasm/WasmInstance.cpp >index 2d67580b87e8b9a6034b45fe9eeebc473d05b9b1..0b07abebbe0f37cd317178a4150fe08b585d6071 100644 >--- a/Source/JavaScriptCore/wasm/WasmInstance.cpp >+++ b/Source/JavaScriptCore/wasm/WasmInstance.cpp >@@ -29,6 +29,7 @@ > #if ENABLE(WEBASSEMBLY) > > #include "JSCJSValueInlines.h" >+#include "JSWebAssemblyHelpers.h" > #include "JSWebAssemblyInstance.h" > #include "Register.h" > #include "WasmModuleInformation.h" >@@ -68,6 +69,12 @@ Instance::Instance(Context* context, Ref<Module>&& module, EntryFrame** pointerT > } > } > memset(bitwise_cast<char*>(this) + offsetOfTablePtr(m_numImportFunctions, 0), 0, m_module->moduleInformation().tableCount() * sizeof(Table*)); >+ m_passiveElements.resize(m_module->moduleInformation().elementCount()); >+ for (unsigned elementIdx = 0; elementIdx < m_passiveElements.size(); ++elementIdx) { >+ const auto& element = m_module->moduleInformation().elements[elementIdx]; >+ if (element.passive()) >+ m_passiveElements[elementIdx] = element; >+ } > } > > Ref<Instance> Instance::create(Context* context, Ref<Module>&& module, EntryFrame** pointerToTopEntryFrame, void** pointerToActualStackLimit, StoreTopCallFrameCallback&& storeTopCallFrame) >@@ -120,6 +127,95 @@ Table* Instance::table(unsigned i) > return *bitwise_cast<Table**>(bitwise_cast<char*>(this) + offsetOfTablePtr(m_numImportFunctions, i)); > } > >+const Element* Instance::elem(unsigned i) const >+{ >+ RELEASE_ASSERT(i < m_passiveElements.size()); >+ >+ if (m_passiveElements[i]) { >+ const Element& elem = *m_passiveElements[i]; >+ return &elem; >+ } >+ return nullptr; >+} >+ >+void Instance::initElementSegment(uint32_t tableIndex, const Element& segment, uint32_t dstOffset, uint32_t srcOffset, uint32_t length) >+{ >+ RELEASE_ASSERT(length <= segment.functionIndices.size()); >+ >+ for (uint32_t idx = 0; idx < length; ++idx) { >+ const auto srcIndex = srcOffset + idx; >+ const auto dstIndex = dstOffset + idx; >+ JSWebAssemblyInstance* jsInstance = owner<JSWebAssemblyInstance>(); >+ JSWebAssemblyTable* jsTable = jsInstance->table(tableIndex); >+ >+ if (!segment.functionIndices[srcIndex].hasValue()) { >+ jsTable->clear(dstIndex); >+ 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 >+ JSGlobalObject* globalObject = jsInstance->globalObject(); >+ VM& vm = globalObject->vm(); >+ uint32_t functionIndex = *segment.functionIndices[srcIndex]; >+ SignatureIndex signatureIndex = m_module->signatureIndexFromFunctionIndexSpace(functionIndex); >+ if (isImportFunction(functionIndex)) { >+ JSObject* functionImport = importFunction<WriteBarrier<JSObject>>(functionIndex)->get(); >+ if (isWebAssemblyHostFunction(vm, functionImport)) { >+ WebAssemblyFunction* wasmFunction = jsDynamicCast<WebAssemblyFunction*>(vm, functionImport); >+ // If we ever import a WebAssemblyWrapperFunction, we set the import as the unwrapped value. >+ // Because a WebAssemblyWrapperFunction can never wrap another WebAssemblyWrapperFunction, >+ // the only type this could be is WebAssemblyFunction. >+ RELEASE_ASSERT(wasmFunction); >+ jsTable->set(dstIndex, wasmFunction); >+ continue; >+ } >+ auto* wrapperFunction = WebAssemblyWrapperFunction::create( >+ vm, >+ globalObject, >+ globalObject->webAssemblyWrapperFunctionStructure(), >+ functionImport, >+ functionIndex, >+ jsInstance, >+ signatureIndex); >+ jsTable->set(dstIndex, wrapperFunction); >+ continue; >+ } >+ >+ Callee& embedderEntrypointCallee = codeBlock()->embedderEntrypointCalleeFromFunctionIndexSpace(functionIndex); >+ WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation = codeBlock()->entrypointLoadLocationFromFunctionIndexSpace(functionIndex); >+ const Signature& signature = SignatureInformation::get(signatureIndex); >+ // FIXME: Say we export local function "foo" at function index 0. >+ // What if we also set it to the table an Element w/ index 0. >+ // Does (new Instance(...)).exports.foo === table.get(0)? >+ // https://bugs.webkit.org/show_bug.cgi?id=165825 >+ WebAssemblyFunction* function = WebAssemblyFunction::create( >+ vm, >+ globalObject, >+ globalObject->webAssemblyFunctionStructure(), >+ signature.argumentCount(), >+ String(), >+ jsInstance, >+ embedderEntrypointCallee, >+ entrypointLoadLocation, >+ signatureIndex); >+ jsTable->set(dstIndex, function); >+ } >+} >+ >+void Instance::tableInit(uint32_t dstOffset, uint32_t srcOffset, uint32_t len, uint32_t elementIndex, uint32_t tableIndex) >+{ >+ RELEASE_ASSERT(elementIndex < m_module->moduleInformation().elementCount()); >+ RELEASE_ASSERT(tableIndex < m_module->moduleInformation().tableCount()); >+ >+ const auto& elementSegment = m_passiveElements[elementIndex]; >+ RELEASE_ASSERT(elementSegment); >+ RELEASE_ASSERT(elementSegment->passive()); >+ initElementSegment(tableIndex, *elementSegment, dstOffset, srcOffset, len); >+} >+ > void Instance::setTable(unsigned i, Ref<Table>&& table) > { > RELEASE_ASSERT(i < m_module->moduleInformation().tableCount()); >diff --git a/Source/JavaScriptCore/wasm/WasmInstance.h b/Source/JavaScriptCore/wasm/WasmInstance.h >index 9a9852c24220827b7ea0ee74defa4345c8810eeb..4bfa89cce88c3f1df5f52be860e2a92c7ea65348 100644 >--- a/Source/JavaScriptCore/wasm/WasmInstance.h >+++ b/Source/JavaScriptCore/wasm/WasmInstance.h >@@ -76,6 +76,16 @@ public: > Memory* memory() { return m_memory.get(); } > Table* table(unsigned); > void setTable(unsigned, Ref<Table>&&); >+ const Element* elem(unsigned) const; >+ >+ void initElementSegment(uint32_t tableIndex, const Element& segment, uint32_t dstOffset, uint32_t srcOffset, uint32_t length); >+ >+ bool isImportFunction(uint32_t functionIndex) const >+ { >+ return functionIndex < m_codeBlock->functionImportCount(); >+ } >+ >+ void tableInit(uint32_t dstOffset, uint32_t srcOffset, uint32_t len, uint32_t elementIndex, uint32_t tableIndex); > > void* cachedMemory() const { return m_cachedMemory.getMayBeNull(cachedBoundsCheckingSize()); } > size_t cachedBoundsCheckingSize() const { return m_cachedBoundsCheckingSize; } >@@ -216,6 +226,7 @@ private: > StoreTopCallFrameCallback m_storeTopCallFrame; > unsigned m_numImportFunctions { 0 }; > HashMap<uint32_t, Ref<Global>, IntHash<uint32_t>, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_linkedGlobals; >+ Vector<Optional<Element>> m_passiveElements; > }; > > } } // namespace JSC::Wasm >diff --git a/Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp b/Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp >index dfc919ef3101d0810ebc68fab092e4fa9c96e0a9..2aa4fc133a1ee33e78edcd8282373c7e6436a0fb 100644 >--- a/Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp >+++ b/Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp >@@ -191,6 +191,7 @@ public: > // Tables > PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType index, ExpressionType& result); > PartialResult WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType index, ExpressionType value); >+ PartialResult WARN_UNUSED_RETURN addTableInit(unsigned, unsigned, ExpressionType dstOffset, ExpressionType srcOffset, ExpressionType length); > PartialResult WARN_UNUSED_RETURN addTableSize(unsigned, ExpressionType& result); > PartialResult WARN_UNUSED_RETURN addTableGrow(unsigned, ExpressionType fill, ExpressionType delta, ExpressionType& result); > PartialResult WARN_UNUSED_RETURN addTableFill(unsigned, ExpressionType offset, ExpressionType fill, ExpressionType count); >@@ -1109,6 +1110,13 @@ auto LLIntGenerator::addTableSet(unsigned tableIndex, ExpressionType index, Expr > return { }; > } > >+auto LLIntGenerator::addTableInit(unsigned elementIndex, unsigned tableIndex, ExpressionType dstOffset, ExpressionType srcOffset, ExpressionType length) -> PartialResult >+{ >+ WasmTableInit::emit(this, dstOffset, srcOffset, length, elementIndex, tableIndex); >+ >+ return { }; >+} >+ > auto LLIntGenerator::addTableSize(unsigned tableIndex, ExpressionType& result) -> PartialResult > { > result = push(); >diff --git a/Source/JavaScriptCore/wasm/WasmModuleInformation.h b/Source/JavaScriptCore/wasm/WasmModuleInformation.h >index 9656ca8751a2d46047621435f23b74c01b15e9ea..41c0a4cfd53c09f3ea64992ffa56f5a669a758cd 100644 >--- a/Source/JavaScriptCore/wasm/WasmModuleInformation.h >+++ b/Source/JavaScriptCore/wasm/WasmModuleInformation.h >@@ -66,6 +66,7 @@ struct ModuleInformation : public ThreadSafeRefCounted<ModuleInformation> { > // If we need to remove this limitation, we would have MemoryInformation and TableInformation in the Vectors. > uint32_t memoryCount() const { return memory ? 1 : 0; } > uint32_t tableCount() const { return tables.size(); } >+ uint32_t elementCount() const { return elements.size(); } > > const BitVector& referencedFunctions() const { return m_referencedFunctions; } > void addReferencedFunction(unsigned index) const { m_referencedFunctions.set(index); } >diff --git a/Source/JavaScriptCore/wasm/WasmOperations.cpp b/Source/JavaScriptCore/wasm/WasmOperations.cpp >index f09b910e761a59bbee9af26150644fbad3acd6c3..5b3d7d31c6294a476d3a409c9922637291286607 100644 >--- a/Source/JavaScriptCore/wasm/WasmOperations.cpp >+++ b/Source/JavaScriptCore/wasm/WasmOperations.cpp >@@ -686,6 +686,26 @@ JSC_DEFINE_JIT_OPERATION(operationSetWasmTableElement, bool, (Instance* instance > return setWasmTableElement(instance, tableIndex, signedIndex, encValue); > } > >+JSC_DEFINE_JIT_OPERATION(operationWasmTableInit, bool, (Instance* instance, unsigned elementIndex, unsigned tableIndex, int32_t dstOffset, int32_t srcOffset, int32_t length)) >+{ >+ ASSERT(elementIndex < instance->module().moduleInformation().elementCount()); >+ ASSERT(tableIndex < instance->module().moduleInformation().tableCount()); >+ >+ if ((srcOffset < 0) || (dstOffset < 0) || (length < 0)) >+ return false; >+ >+ const uint32_t lastSrcElementIdx = srcOffset + length; >+ if (lastSrcElementIdx > instance->elem(elementIndex)->length()) >+ return false; >+ >+ const uint32_t lastDstElementIdx = dstOffset + length; >+ if (lastDstElementIdx > instance->table(tableIndex)->length()) >+ return false; >+ >+ instance->tableInit(dstOffset, srcOffset, length, elementIndex, tableIndex); >+ return true; >+} >+ > JSC_DEFINE_JIT_OPERATION(operationWasmTableGrow, int32_t, (Instance* instance, unsigned tableIndex, EncodedJSValue fill, int32_t delta)) > { > ASSERT(tableIndex < instance->module().moduleInformation().tableCount()); >diff --git a/Source/JavaScriptCore/wasm/WasmOperations.h b/Source/JavaScriptCore/wasm/WasmOperations.h >index 81917a2ebac30ed75a49c7375d02462afe1cd5fc..3cb6d830c2e6aeff0bbb15fdb213ca94e561e112 100644 >--- a/Source/JavaScriptCore/wasm/WasmOperations.h >+++ b/Source/JavaScriptCore/wasm/WasmOperations.h >@@ -65,6 +65,7 @@ JSC_DECLARE_JIT_OPERATION(operationGrowMemory, int32_t, (void*, Instance*, int32 > JSC_DECLARE_JIT_OPERATION(operationGetWasmTableElement, EncodedJSValue, (Instance*, unsigned, int32_t)); > JSC_DECLARE_JIT_OPERATION(operationSetWasmTableElement, bool, (Instance*, unsigned, int32_t, EncodedJSValue encValue)); > JSC_DECLARE_JIT_OPERATION(operationWasmRefFunc, EncodedJSValue, (Instance*, uint32_t)); >+JSC_DECLARE_JIT_OPERATION(operationWasmTableInit, bool, (Instance*, unsigned elementIndex, unsigned tableIndex, int32_t dstOffset, int32_t srcOffset, int32_t length)); > JSC_DECLARE_JIT_OPERATION(operationWasmTableGrow, int32_t, (Instance*, unsigned, EncodedJSValue fill, int32_t delta)); > JSC_DECLARE_JIT_OPERATION(operationWasmTableFill, bool, (Instance*, unsigned, int32_t offset, EncodedJSValue fill, int32_t count)); > JSC_DECLARE_JIT_OPERATION(operationGetWasmTableSize, int32_t, (Instance*, unsigned)); >diff --git a/Source/JavaScriptCore/wasm/WasmSectionParser.cpp b/Source/JavaScriptCore/wasm/WasmSectionParser.cpp >index b411b27d34ca3e6b35a09012d624eb6ed262a880..628d753569501390c7a20785abe1edfe67009599 100644 >--- a/Source/JavaScriptCore/wasm/WasmSectionParser.cpp >+++ b/Source/JavaScriptCore/wasm/WasmSectionParser.cpp >@@ -378,41 +378,169 @@ auto SectionParser::parseElement() -> PartialResult > 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"); >+ >+ switch (elementFlags) { >+ case 0x00: { >+ const 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(parseIndexCountForElemSection(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 (uint32_t index = 0; index < indexCount; ++index) { >+ Optional<uint32_t> funcIdx; >+ WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxForElemSection(funcIdx, elementNum, index)); >+ element.functionIndices.uncheckedAppend(WTFMove(funcIdx)); >+ } >+ >+ m_info->elements.uncheckedAppend(WTFMove(element)); >+ break; >+ } >+ case 0x01: { >+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled"); >+ uint8_t elemKind; >+ WASM_FAIL_IF_HELPER_FAILS(parseElemKind(elemKind)); >+ >+ uint32_t indexCount; >+ WASM_FAIL_IF_HELPER_FAILS(parseIndexCountForElemSection(indexCount, elementNum)); > >- 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"); >+ Element element(Element::Kind::Passive, TableElementType::Funcref); >+ WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices"); > >- if (magic == 2) >+ for (uint32_t index = 0; index < indexCount; ++index) { >+ Optional<uint32_t> funcIdx; >+ WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxForElemSection(funcIdx, elementNum, index)); >+ element.functionIndices.uncheckedAppend(WTFMove(funcIdx)); >+ } >+ >+ m_info->elements.uncheckedAppend(WTFMove(element)); >+ break; >+ } >+ case 0x02: { >+ uint32_t tableIndex; > 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); >+ WASM_FAIL_IF_HELPER_FAILS(validateElementTableIdx(tableIndex)); >+ >+ Optional<I32InitExpr> initExpr; >+ WASM_FAIL_IF_HELPER_FAILS(parseI32InitExpr(initExpr)); >+ >+ uint8_t elemKind; >+ WASM_FAIL_IF_HELPER_FAILS(parseElemKind(elemKind)); > >- ASSERT(!!m_info->tables[tableIndex]); >+ uint32_t indexCount; >+ WASM_FAIL_IF_HELPER_FAILS(parseIndexCountForElemSection(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 (unsigned index = 0; index < indexCount; ++index) { >+ Optional<uint32_t> funcIdx; >+ WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxForElemSection(funcIdx, elementNum, index)); >+ element.functionIndices.uncheckedAppend(WTFMove(funcIdx)); >+ } > >- element.functionIndices.uncheckedAppend(functionIndex); >+ 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"); >+ break; >+ } >+ case 0x04: { >+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled"); >+ >+ const 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(parseIndexCountForElemSection(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) { >+ Optional<uint32_t> funcIdx; >+ WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxFromRefExpForElemSection(funcIdx, elementNum, index)); >+ element.functionIndices.uncheckedAppend(WTFMove(funcIdx)); >+ } >+ >+ m_info->elements.uncheckedAppend(WTFMove(element)); >+ break; >+ } >+ case 0x05: { >+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled"); >+ Type refType; >+ WASM_PARSER_FAIL_IF(!parseRefType(refType), "can't parse reftype in elem section"); >+ WASM_PARSER_FAIL_IF(refType == Externref, "reftype in element section should be funcref"); >+ >+ uint32_t indexCount; >+ WASM_FAIL_IF_HELPER_FAILS(parseIndexCountForElemSection(indexCount, elementNum)); >+ >+ Element element(Element::Kind::Passive, TableElementType::Funcref); >+ WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices"); >+ >+ for (unsigned index = 0; index < indexCount; ++index) { >+ Optional<uint32_t> funcIdx; >+ WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxFromRefExpForElemSection(funcIdx, elementNum, index)); >+ element.functionIndices.uncheckedAppend(WTFMove(funcIdx)); >+ } >+ >+ m_info->elements.uncheckedAppend(WTFMove(element)); >+ 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 == Externref, "reftype in element section should be funcref"); >+ >+ uint32_t indexCount; >+ WASM_FAIL_IF_HELPER_FAILS(parseIndexCountForElemSection(indexCount, elementNum)); >+ ASSERT(!!m_info->tables[tableIndex]); > >- m_info->elements.uncheckedAppend(WTFMove(element)); >+ 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) { >+ Optional<uint32_t> funcIdx; >+ WASM_FAIL_IF_HELPER_FAILS(parseFuncIdxFromRefExpForElemSection(funcIdx, elementNum, index)); >+ element.functionIndices.uncheckedAppend(WTFMove(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"); >+ break; >+ } >+ default: >+ WASM_PARSER_FAIL_IF(true, "can't get ", elementNum, "th Element reserved byte"); >+ } > } > > return { }; >@@ -504,6 +632,79 @@ auto SectionParser::parseInitExpr(uint8_t& opcode, uint64_t& bitsOrImportNumber, > 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::parseElemKind(uint8_t& resultElemKind) -> PartialResult >+{ >+ uint8_t elemKind; >+ WASM_PARSER_FAIL_IF(!parseUInt8(elemKind), "can't get elemkind"); >+ WASM_PARSER_FAIL_IF(!!elemKind, "elemkind must be zero"); >+ resultElemKind = elemKind; >+ >+ return { }; >+} >+ >+auto SectionParser::parseIndexCountForElemSection(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::parseFuncIdxFromRefExpForElemSection(Optional<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"); >+ } >+ >+ 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::parseFuncIdxForElemSection(Optional<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 5277a7ac0fe9090a006a480f0f4a7502a26b0c94..44109d8f93f7e96befb6bda8e613ed398ba1a08b 100644 >--- a/Source/JavaScriptCore/wasm/WasmSectionParser.h >+++ b/Source/JavaScriptCore/wasm/WasmSectionParser.h >@@ -66,6 +66,13 @@ private: > PartialResult WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, Optional<uint32_t>& maximum); > 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 parseElemKind(uint8_t& elemKind); >+ PartialResult WARN_UNUSED_RETURN parseIndexCountForElemSection(uint32_t&, const unsigned); >+ PartialResult WARN_UNUSED_RETURN parseFuncIdxFromRefExpForElemSection(Optional<uint32_t>&, const unsigned, const unsigned); >+ PartialResult WARN_UNUSED_RETURN parseFuncIdxForElemSection(Optional<uint32_t>&, const unsigned, const unsigned); >+ > size_t m_offsetInSource; > Ref<ModuleInformation> m_info; > }; >diff --git a/Source/JavaScriptCore/wasm/WasmSlowPaths.cpp b/Source/JavaScriptCore/wasm/WasmSlowPaths.cpp >index 90621121a81e31b52175b597d9bc41264867633a..42292cc4b5512fe6a3b04d74a34cdce6b9b9b8c7 100644 >--- a/Source/JavaScriptCore/wasm/WasmSlowPaths.cpp >+++ b/Source/JavaScriptCore/wasm/WasmSlowPaths.cpp >@@ -316,6 +316,17 @@ WASM_SLOW_PATH_DECL(table_set) > WASM_END(); > } > >+WASM_SLOW_PATH_DECL(table_init) >+{ >+ auto instruction = pc->as<WasmTableInit, WasmOpcodeTraits>(); >+ int32_t dstOffset = READ(instruction.m_dstOffset).unboxedInt32(); >+ int32_t srcOffset = READ(instruction.m_srcOffset).unboxedInt32(); >+ int32_t length = READ(instruction.m_length).unboxedInt32(); >+ if (!Wasm::operationWasmTableInit(instance, instruction.m_elementIndex, instruction.m_tableIndex, dstOffset, srcOffset, length)) >+ WASM_THROW(Wasm::ExceptionType::OutOfBoundsTableAccess); >+ WASM_END(); >+} >+ > WASM_SLOW_PATH_DECL(table_size) > { > auto instruction = pc->as<WasmTableSize, WasmOpcodeTraits>(); >diff --git a/Source/JavaScriptCore/wasm/WasmSlowPaths.h b/Source/JavaScriptCore/wasm/WasmSlowPaths.h >index 5540a0753f0c6e77d10729c8ca54d69352c4581b..9fc8902119978355b3871d9d721ee56975d55b0e 100644 >--- a/Source/JavaScriptCore/wasm/WasmSlowPaths.h >+++ b/Source/JavaScriptCore/wasm/WasmSlowPaths.h >@@ -59,6 +59,7 @@ WASM_SLOW_PATH_HIDDEN_DECL(out_of_line_jump_target); > WASM_SLOW_PATH_HIDDEN_DECL(ref_func); > WASM_SLOW_PATH_HIDDEN_DECL(table_get); > WASM_SLOW_PATH_HIDDEN_DECL(table_set); >+WASM_SLOW_PATH_HIDDEN_DECL(table_init); > WASM_SLOW_PATH_HIDDEN_DECL(table_size); > WASM_SLOW_PATH_HIDDEN_DECL(table_fill); > WASM_SLOW_PATH_HIDDEN_DECL(table_grow); >diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp >index 2064a466285516d4cc6884a2b324bc6e6697eba7..89b3076dc67d1c23b90c35eb0bfbfaee818e6408 100644 >--- a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp >+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp >@@ -359,7 +359,6 @@ void WebAssemblyModuleRecord::link(JSGlobalObject* globalObject, JSValue, JSObje > } > } > >- unsigned functionImportCount = codeBlock->functionImportCount(); > auto makeFunctionWrapper = [&] (const String& field, uint32_t index) -> JSValue { > // If we already made a wrapper, do not make a new one. > JSValue wrapper = m_instance->instance().getFunctionWrapper(index); >@@ -370,7 +369,7 @@ void WebAssemblyModuleRecord::link(JSGlobalObject* globalObject, JSValue, JSObje > // 1. If e is a closure c: > // i. If there is an Exported Function Exotic Object func in funcs whose func.[[Closure]] equals c, then return func. > // ii. (Note: At most one wrapper is created for any closure, so func is unique, even if there are multiple occurrances in the list. Moreover, if the item was an import that is already an Exported Function Exotic Object, then the original function object will be found. For imports that are regular JS functions, a new wrapper will be created.) >- if (index < functionImportCount) { >+ if (m_instance->instance().isImportFunction(index)) { > JSObject* functionImport = m_instance->instance().importFunction<WriteBarrier<JSObject>>(index)->get(); > if (isWebAssemblyHostFunction(vm, functionImport)) > wrapper = functionImport; >@@ -546,23 +545,27 @@ JSValue WebAssemblyModuleRecord::evaluate(JSGlobalObject* globalObject) > > auto forEachElement = [&] (auto fn) { > for (const Wasm::Element& element : moduleInformation.elements) { >+ if (!element.tableIndexIfActive) >+ continue; > // It should be a validation error to have any elements without a table. > // Also, it could be that a table wasn't imported, or that the table > // imported wasn't compatible. However, those should error out before > // getting here. >- ASSERT(!!m_instance->table(element.tableIndex)); >+ ASSERT(!!m_instance->table(*element.tableIndexIfActive)); > > 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.active()) { >+ uint32_t elementIndex = element.offsetIfActive->isGlobalImport() >+ ? static_cast<uint32_t>(m_instance->instance().loadI32Global(element.offsetIfActive->globalImportIndex())) >+ : element.offsetIfActive->constValue(); > >- fn(element, element.tableIndex, elementIndex); >+ fn(element, *element.tableIndexIfActive, elementIndex); > >- if (exception) >- break; >+ if (exception) >+ break; >+ } > } > }; > >@@ -605,12 +608,17 @@ JSValue WebAssemblyModuleRecord::evaluate(JSGlobalObject* globalObject) > return exception.value(); > > forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex, uint32_t elementIndex) { >- for (uint32_t i = 0; i < element.functionIndices.size(); ++i) { >+ for (uint32_t i = 0; i < element.functionIndices.size(); ++i, ++elementIndex) { >+ if (!element.functionIndices[i].hasValue()) { >+ 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]; >+ 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 +629,11 @@ JSValue WebAssemblyModuleRecord::evaluate(JSGlobalObject* globalObject) > // 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 +646,7 @@ JSValue WebAssemblyModuleRecord::evaluate(JSGlobalObject* globalObject) > // 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; > } > }); > >diff --git a/Source/JavaScriptCore/wasm/wasm.json b/Source/JavaScriptCore/wasm/wasm.json >index 947344e150c114562933377e35d5a8e416d00c23..f1213d1aa60a07dc2b1d0642ff42b349d99fde8f 100644 >--- a/Source/JavaScriptCore/wasm/wasm.json >+++ b/Source/JavaScriptCore/wasm/wasm.json >@@ -69,9 +69,10 @@ > "set_global": { "category": "special", "value": 36, "return": [], "parameter": ["any"], "immediate": [{"name": "global_index", "type": "varuint32"}], "description": "write a global variable" }, > "table.get": { "category": "special", "value": 37, "return": ["externref"], "parameter": ["i32"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "get a table value" }, > "table.set": { "category": "special", "value": 38, "return": [], "parameter": ["i32", "externref"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "set a table value" }, >+ "table.init": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["i32", "i32", "i32"], "immediate": [{"name": "element_index", "type": "varuint32"}, {"name": "table_index","type": "varuint32"}],"description": "initialize table from given element", "extendedOp": 12 }, > "table.grow": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["externref", "i32"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "grow a table by the given delta and return the previous size, or -1 if enough space cannot be allocated", "extendedOp": 15 }, > "table.size": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": [], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "get the size of a table", "extendedOp": 16 }, >- "table.fill": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["i32", "externref", "i32"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "fill entries [i,i+n) with the given value", "extendedOp": 17 }, >+ "table.fill": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["i32", "externref", "i32"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "fill entries [i,i+n) with the given value", "extendedOp": 17 }, > "call": { "category": "call", "value": 16, "return": ["call"], "parameter": ["call"], "immediate": [{"name": "function_index", "type": "varuint32"}], "description": "call a function by its index" }, > "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" }, > "i32.load8_s": { "category": "memory", "value": 44, "return": ["i32"], "parameter": ["addr"], "immediate": [{"name": "flags", "type": "varuint32"}, {"name": "offset", "type": "varuint32"}], "description": "load from memory" }, >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index 25c66b4896283cc0efdfcd928fd60c0954f25b53..bbf26724eeb31767717d821cb709e37cb62556c4 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,46 @@ >+2020-11-26 Dmitry Bezhetskov <dbezhetskov@igalia.com> >+ >+ [WASM-References] Add table.init >+ https://bugs.webkit.org/show_bug.cgi?id=219297 >+ >+ Reviewed by NOBODY (OOPS!). >+ Added very basic tests for table.init. >+ Once we have support for elem.drop and declarative elements we can replace them spec tests. >+ >+ * wasm/references/element_parsing.js: >+ * wasm/references/table_init.js: Added. >+ (module): >+ (basicTest): >+ (elementIndexOutOfBounds): >+ (invalidSourceOffset): >+ (invalidLength): >+ * wasm/wasm.json: >+ >+2020-11-19 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 NOBODY (OOPS!). >+ 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-18 Dmitry Bezhetskov <dbezhetskov@igalia.com> > > [WASM-References] Remove subtyping rule for externref and funcref >diff --git a/JSTests/wasm/Builder.js b/JSTests/wasm/Builder.js >index 327b17d7e4c0447925710e72d63fb89e4ed9565c..011ccb8456dcbddfbb357581843eb2e64f0745ce 100644 >--- a/JSTests/wasm/Builder.js >+++ b/JSTests/wasm/Builder.js >@@ -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); > } > }; >diff --git a/JSTests/wasm/Builder_WebAssemblyBinary.js b/JSTests/wasm/Builder_WebAssemblyBinary.js >index 1eef9d4182de3372014cddc499b8887d052308fa..4711c8cd4dd56f0cb34d1443bc89aec5e0dd6ef3 100644 >--- a/JSTests/wasm/Builder_WebAssemblyBinary.js >+++ b/JSTests/wasm/Builder_WebAssemblyBinary.js >@@ -193,10 +193,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") >@@ -205,6 +208,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); >diff --git a/JSTests/wasm/references-spec-tests/ref_null.js b/JSTests/wasm/references-spec-tests/ref_null.js >index 9dda7affa400a4438a52362e9b33c0b8237120cc..5325abaa3a6ff763b4fa09d8b383aaed4b98e706 100644 >--- a/JSTests/wasm/references-spec-tests/ref_null.js >+++ b/JSTests/wasm/references-spec-tests/ref_null.js >@@ -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); > } >diff --git a/JSTests/wasm/references/element_active_mod.js b/JSTests/wasm/references/element_active_mod.js >new file mode 100644 >index 0000000000000000000000000000000000000000..c17084006834d37ee63b72eb99faf39b7cf039cb >--- /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 93be1fd65762d4455aae935d32e7c6d36408ca01..2443291228cc5807254f2e30a002fba8d4b5c5a3 100644 >--- a/JSTests/wasm/references/element_parsing.js >+++ b/JSTests/wasm/references/element_parsing.js >@@ -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 144: elemkind must be zero (evaluating 'new WebAssembly.Module(buffer)')"); >diff --git a/JSTests/wasm/references/multitable.js b/JSTests/wasm/references/multitable.js >index 48a8560c0c60320e5676204d2063211202b02b24..1007015c2b8b15bc0bb73714b7465a99e33f805e 100644 >--- a/JSTests/wasm/references/multitable.js >+++ b/JSTests/wasm/references/multitable.js >@@ -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() >diff --git a/JSTests/wasm/references/table_init.js b/JSTests/wasm/references/table_init.js >new file mode 100644 >index 0000000000000000000000000000000000000000..8255866dc2d228420d39a957a386ed48efd1a223 >--- /dev/null >+++ b/JSTests/wasm/references/table_init.js >@@ -0,0 +1,159 @@ >+//@ 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 >+ (type $type0 (func (result i32))) >+ (func $f (result i32) i32.const 37) >+ (func $g (result i32) i32.const 42) >+ (table $t0 10 funcref) >+ (elem $e0 func $f $f $g $g) >+ (elem $e1 funcref (ref.null func) (ref.null func) (ref.func $f)) >+ (func (export "init") >+ (table.init $t0 $e0 (i32.const 0) (i32.const 0) (i32.const 4)) >+ (table.init $t0 $e1 (i32.const 4) (i32.const 1) (i32.const 2))) >+ (func (export "get_func") (param $idx i32) (result funcref) >+ (table.get $t0 (local.get $idx)))) >+ */ >+ let instance = new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x0d\x03\x60\x00\x01\x7f\x60\x00\x00\x60\x01\x7f\x01\x70\x03\x05\x04\x00\x00\x01\x02\x04\x04\x01\x70\x00\x0a\x07\x13\x02\x04\x69\x6e\x69\x74\x00\x02\x08\x67\x65\x74\x5f\x66\x75\x6e\x63\x00\x03\x09\x14\x02\x01\x00\x04\x00\x00\x01\x01\x05\x70\x03\xd0\x70\x0b\xd0\x70\x0b\xd2\x00\x0b\x0a\x29\x04\x04\x00\x41\x25\x0b\x04\x00\x41\x2a\x0b\x16\x00\x41\x00\x41\x00\x41\x04\xfc\x0c\x00\x00\x41\x04\x41\x01\x41\x02\xfc\x0c\x01\x00\x0b\x06\x00\x20\x00\x25\x00\x0b")); >+ >+ instance.exports.init(); >+ assert.eq(instance.exports.get_func(0)(), 37); >+ assert.eq(instance.exports.get_func(1)(), 37); >+ assert.eq(instance.exports.get_func(2)(), 42); >+ assert.eq(instance.exports.get_func(3)(), 42); >+ assert.eq(instance.exports.get_func(4), null); >+ assert.eq(instance.exports.get_func(5)(), 37); >+ assert.eq(instance.exports.get_func(6), null); >+ assert.eq(instance.exports.get_func(7), null); >+ assert.eq(instance.exports.get_func(8), null); >+ assert.eq(instance.exports.get_func(9), null); >+} >+ >+function elementIndexOutOfBounds() { >+ /* >+ (module >+ (table $t0 10 funcref) >+ (elem (i32.const 3) funcref (ref.null func)) >+ (func (export "run") >+ (table.init $t0 1 (i32.const 1) (i32.const 2) (i32.const 3)) >+ ) >+ ) >+ */ >+ assert.throws(() => module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x04\x04\x01\x70\x00\x0a\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x09\x09\x01\x04\x41\x03\x0b\x01\xd0\x70\x0b\x0a\x0e\x01\x0c\x00\x41\x01\x41\x02\x41\x03\xfc\x0c\x01\x00\x0b"), >+ WebAssembly.CompileError, >+ "WebAssembly.Module doesn't validate: element index 1 is invalid, limit is 1, in function at index 0 (evaluating 'new WebAssembly.Module(buffer)')"); >+} >+ >+function tableIndexOutOfBounds() { >+ /* >+ (module >+ (table 10 funcref) >+ (elem $e0 (i32.const 3) funcref (ref.null func)) >+ (func (export "run") >+ (table.init 1 $e0 (i32.const 1) (i32.const 2) (i32.const 3)) >+ ) >+ ) >+ */ >+ assert.throws(() => module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x04\x04\x01\x70\x00\x0a\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x09\x09\x01\x04\x41\x03\x0b\x01\xd0\x70\x0b\x0a\x0e\x01\x0c\x00\x41\x01\x41\x02\x41\x03\xfc\x0c\x00\x01\x0b"), >+ WebAssembly.CompileError, >+ "WebAssembly.Module doesn't validate: table index 1 is invalid, limit is 1, in function at index 0 (evaluating 'new WebAssembly.Module(buffer)')"); >+} >+ >+function invalidDestinationOffset() { >+ /* >+ (module >+ (table $t0 10 funcref) >+ (elem $e0 (i32.const 3) funcref (ref.null func)) >+ (func (export "run") >+ (table.init $t0 $e0 (i64.const 1) (i32.const 2) (i32.const 3)) >+ ) >+ ) >+ */ >+ assert.throws(() => module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x04\x04\x01\x70\x00\x0a\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x09\x09\x01\x04\x41\x03\x0b\x01\xd0\x70\x0b\x0a\x0e\x01\x0c\x00\x42\x01\x41\x02\x41\x03\xfc\x0c\x00\x00\x0b"), >+ WebAssembly.CompileError, >+ "WebAssembly.Module doesn't validate: table.init dst_offset to type I64 expected I32, in function at index 0 (evaluating 'new WebAssembly.Module(buffer)')"); >+ >+ /* >+ (module >+ (table $t0 10 funcref) >+ (elem $e0 funcref (ref.null func) (ref.null func) (ref.null func)) >+ (func (export "run") >+ (table.init $t0 $e0 (i32.const 11) (i32.const 0) (i32.const 1)) >+ ) >+ ) >+ */ >+ const instance = new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x04\x04\x01\x70\x00\x0a\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x09\x0d\x01\x05\x70\x03\xd0\x70\x0b\xd0\x70\x0b\xd0\x70\x0b\x0a\x0e\x01\x0c\x00\x41\x0b\x41\x00\x41\x01\xfc\x0c\x00\x00\x0b")); >+ assert.throws(instance.exports.run, WebAssembly.RuntimeError, "Out of bounds table access (evaluating 'func(...args)')"); >+} >+ >+function invalidSourceOffset() { >+ /* >+ (module >+ (table $t0 10 funcref) >+ (elem $e0 (i32.const 3) funcref (ref.null func)) >+ (func (export "run") >+ (table.init $t0 $e0 (i32.const 1) (i64.const 2) (i32.const 3)) >+ ) >+ ) >+ */ >+ assert.throws(() => module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x04\x04\x01\x70\x00\x0a\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x09\x09\x01\x04\x41\x03\x0b\x01\xd0\x70\x0b\x0a\x0e\x01\x0c\x00\x41\x01\x42\x02\x41\x03\xfc\x0c\x00\x00\x0b"), >+ WebAssembly.CompileError, >+ "WebAssembly.Module doesn't validate: table.init src_offset to type I64 expected I32, in function at index 0 (evaluating 'new WebAssembly.Module(buffer)')"); >+ >+ /* >+ (module >+ (table $t0 10 funcref) >+ (elem $e0 funcref (ref.null func) (ref.null func) (ref.null func)) >+ (func (export "run") >+ (table.init $t0 $e0 (i32.const 0) (i32.const 11) (i32.const 1)) >+ ) >+ ) >+ */ >+ const instance = new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x04\x04\x01\x70\x00\x0a\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x09\x0d\x01\x05\x70\x03\xd0\x70\x0b\xd0\x70\x0b\xd0\x70\x0b\x0a\x0e\x01\x0c\x00\x41\x00\x41\x0b\x41\x01\xfc\x0c\x00\x00\x0b")); >+ assert.throws(instance.exports.run, WebAssembly.RuntimeError, "Out of bounds table access (evaluating 'func(...args)')"); >+} >+ >+function invalidLength() { >+ /* >+ (module >+ (table $t0 10 funcref) >+ (elem $e0 (i32.const 3) funcref (ref.null func)) >+ (func (export "run") >+ (table.init $t0 $e0 (i32.const 1) (i64.const 2) (i64.const 3)) >+ ) >+ ) >+ */ >+ assert.throws(() => module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x04\x04\x01\x70\x00\x0a\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x09\x09\x01\x04\x41\x03\x0b\x01\xd0\x70\x0b\x0a\x0e\x01\x0c\x00\x41\x01\x41\x02\x42\x03\xfc\x0c\x00\x00\x0b"), >+ WebAssembly.CompileError, >+ "WebAssembly.Module doesn't validate: table.init length to type I64 expected I32, in function at index 0 (evaluating 'new WebAssembly.Module(buffer)')"); >+ >+ /* >+ (module >+ (table $t0 10 funcref) >+ (elem $e0 funcref (ref.null func) (ref.null func) (ref.null func)) >+ (func (export "run") >+ (table.init $t0 $e0 (i32.const 0) (i32.const 0) (i32.const 11)) >+ ) >+ ) >+ */ >+ const instance = new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x04\x04\x01\x70\x00\x0a\x07\x07\x01\x03\x72\x75\x6e\x00\x00\x09\x0d\x01\x05\x70\x03\xd0\x70\x0b\xd0\x70\x0b\xd0\x70\x0b\x0a\x0e\x01\x0c\x00\x41\x00\x41\x00\x41\x0b\xfc\x0c\x00\x00\x0b")); >+ assert.throws(instance.exports.run, WebAssembly.RuntimeError, "Out of bounds table access (evaluating 'func(...args)')"); >+} >+ >+elementIndexOutOfBounds(); >+tableIndexOutOfBounds(); >+invalidDestinationOffset(); >+invalidSourceOffset(); >+invalidLength(); >+basicTest(); >diff --git a/JSTests/wasm/wasm.json b/JSTests/wasm/wasm.json >index 947344e150c114562933377e35d5a8e416d00c23..f1213d1aa60a07dc2b1d0642ff42b349d99fde8f 100644 >--- a/JSTests/wasm/wasm.json >+++ b/JSTests/wasm/wasm.json >@@ -69,9 +69,10 @@ > "set_global": { "category": "special", "value": 36, "return": [], "parameter": ["any"], "immediate": [{"name": "global_index", "type": "varuint32"}], "description": "write a global variable" }, > "table.get": { "category": "special", "value": 37, "return": ["externref"], "parameter": ["i32"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "get a table value" }, > "table.set": { "category": "special", "value": 38, "return": [], "parameter": ["i32", "externref"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "set a table value" }, >+ "table.init": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["i32", "i32", "i32"], "immediate": [{"name": "element_index", "type": "varuint32"}, {"name": "table_index","type": "varuint32"}],"description": "initialize table from given element", "extendedOp": 12 }, > "table.grow": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["externref", "i32"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "grow a table by the given delta and return the previous size, or -1 if enough space cannot be allocated", "extendedOp": 15 }, > "table.size": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": [], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "get the size of a table", "extendedOp": 16 }, >- "table.fill": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["i32", "externref", "i32"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "fill entries [i,i+n) with the given value", "extendedOp": 17 }, >+ "table.fill": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["i32", "externref", "i32"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "fill entries [i,i+n) with the given value", "extendedOp": 17 }, > "call": { "category": "call", "value": 16, "return": ["call"], "parameter": ["call"], "immediate": [{"name": "function_index", "type": "varuint32"}], "description": "call a function by its index" }, > "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" }, > "i32.load8_s": { "category": "memory", "value": 44, "return": ["i32"], "parameter": ["addr"], "immediate": [{"name": "flags", "type": "varuint32"}, {"name": "offset", "type": "varuint32"}], "description": "load from memory" },
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 219297
:
414892
|
414915
|
415626
|
415733
|
415747
|
415850
|
415968