WebKit Bugzilla
Attachment 372398 Details for
Bug 198761
: [WASM-References] Add support for Table.size, grow and fill instructions
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-198761-20190618155810.patch (text/plain), 37.13 KB, created by
Justin Michaud
on 2019-06-18 15:58:11 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Justin Michaud
Created:
2019-06-18 15:58:11 PDT
Size:
37.13 KB
patch
obsolete
>Subversion Revision: 246575 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 6f4dcb24ea7e40776a3e167f450befa2af09a5c7..59d6874c137a1976fd3c114cb83bc260a1c2614c 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,44 @@ >+2019-06-14 Justin Michaud <justin_michaud@apple.com> >+ >+ [WASM-References] Add support for Table.size, grow and fill instructions >+ https://bugs.webkit.org/show_bug.cgi?id=198761 >+ >+ Reviewed by Yusuke Suzuki. >+ >+ Add support for Table.size, grow and fill instructions. This also required >+ adding support for two-byte opcodes to the ops generator. >+ >+ * wasm/WasmAirIRGenerator.cpp: >+ (JSC::Wasm::AirIRGenerator::gAnyref): >+ (JSC::Wasm::AirIRGenerator::tmpForType): >+ (JSC::Wasm::AirIRGenerator::addTableSize): >+ (JSC::Wasm::AirIRGenerator::addTableGrow): >+ (JSC::Wasm::AirIRGenerator::addTableFill): >+ * wasm/WasmB3IRGenerator.cpp: >+ (JSC::Wasm::B3IRGenerator::addTableSize): >+ (JSC::Wasm::B3IRGenerator::addTableGrow): >+ (JSC::Wasm::B3IRGenerator::addTableFill): >+ * wasm/WasmExceptionType.h: >+ * wasm/WasmFormat.h: >+ (JSC::Wasm::TableInformation::wasmType const): >+ * wasm/WasmFunctionParser.h: >+ (JSC::Wasm::FunctionParser<Context>::parseExpression): >+ (JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression): >+ * wasm/WasmInstance.cpp: >+ (JSC::Wasm::doWasmTableGrow): >+ (JSC::Wasm::doWasmTableFill): >+ * wasm/WasmInstance.h: >+ * wasm/WasmTable.cpp: >+ (JSC::Wasm::Table::grow): >+ * wasm/WasmValidate.cpp: >+ (JSC::Wasm::Validate::addTableSize): >+ (JSC::Wasm::Validate::addTableGrow): >+ (JSC::Wasm::Validate::addTableFill): >+ * wasm/generateWasmOpsHeader.py: >+ (opcodeMacroizer): >+ (ExtTableOpType): >+ * wasm/wasm.json: >+ > 2019-06-18 Keith Miller <keith_miller@apple.com> > > Unreviewed, fix signature of currentWeakRefVersion to return an uintptr_t. >diff --git a/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp b/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp >index eff7e3227bf9df24c21623edf893f5c9338d77b0..47b4ec6b47708609a74dca35fb2ac3dabb1ac0f1 100644 >--- a/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp >+++ b/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp >@@ -239,6 +239,9 @@ 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 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); > > // Locals > PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result); >@@ -361,6 +364,8 @@ private: > > TypedTmp g32() { return { newTmp(B3::GP), Type::I32 }; } > TypedTmp g64() { return { newTmp(B3::GP), Type::I64 }; } >+ TypedTmp gAnyref() { return { newTmp(B3::GP), Type::Anyref }; } >+ TypedTmp gAnyfunc() { return { newTmp(B3::GP), Type::Anyfunc }; } > TypedTmp f32() { return { newTmp(B3::FP), Type::F32 }; } > TypedTmp f64() { return { newTmp(B3::FP), Type::F64 }; } > >@@ -370,9 +375,11 @@ private: > case Type::I32: > return g32(); > case Type::I64: >- case Type::Anyref: >- case Type::Anyfunc: > return g64(); >+ case Type::Anyfunc: >+ return gAnyfunc(); >+ case Type::Anyref: >+ return gAnyref(); > case Type::F32: > return f32(); > case Type::F64: >@@ -508,6 +515,8 @@ private: > resultType = B3::Int32; > break; > case Type::I64: >+ case Type::Anyref: >+ case Type::Anyfunc: > resultType = B3::Int64; > break; > case Type::F32: >@@ -975,7 +984,7 @@ auto AirIRGenerator::addTableGet(unsigned tableIndex, ExpressionType& index, Exp > // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>. > ASSERT(index.tmp()); > ASSERT(index.type() == Type::I32); >- result = tmpForType(Type::Anyref); >+ result = tmpForType(m_info.tables[tableIndex].wasmType()); > > emitCCall(&getWasmTableElement, result, instanceValue(), addConstant(Type::I32, tableIndex), index); > emitCheck([&] { >@@ -1006,6 +1015,54 @@ auto AirIRGenerator::addTableSet(unsigned tableIndex, ExpressionType& index, Exp > return { }; > } > >+auto AirIRGenerator::addTableSize(unsigned tableIndex, ExpressionType& result) -> PartialResult >+{ >+ // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>. >+ result = tmpForType(Type::I32); >+ >+ int32_t (*doSize)(Instance*, unsigned) = [] (Instance* instance, unsigned tableIndex) -> int32_t { >+ return instance->table(tableIndex)->length(); >+ }; >+ >+ emitCCall(doSize, result, instanceValue(), addConstant(Type::I32, tableIndex)); >+ >+ return { }; >+} >+ >+auto AirIRGenerator::addTableGrow(unsigned tableIndex, ExpressionType& fill, ExpressionType& delta, ExpressionType& result) -> PartialResult >+{ >+ ASSERT(fill.tmp()); >+ ASSERT(isSubtype(fill.type(), m_info.tables[tableIndex].wasmType())); >+ ASSERT(delta.tmp()); >+ ASSERT(delta.type() == Type::I32); >+ result = tmpForType(Type::I32); >+ >+ emitCCall(&doWasmTableGrow, result, instanceValue(), addConstant(Type::I32, tableIndex), fill, delta); >+ >+ return { }; >+} >+ >+auto AirIRGenerator::addTableFill(unsigned tableIndex, ExpressionType& offset, ExpressionType& fill, ExpressionType& count) -> PartialResult >+{ >+ ASSERT(fill.tmp()); >+ ASSERT(isSubtype(fill.type(), m_info.tables[tableIndex].wasmType())); >+ ASSERT(offset.tmp()); >+ ASSERT(offset.type() == Type::I32); >+ ASSERT(count.tmp()); >+ ASSERT(count.type() == Type::I32); >+ >+ auto result = tmpForType(Type::I32); >+ emitCCall(&doWasmTableFill, result, instanceValue(), addConstant(Type::I32, tableIndex), offset, fill, count); >+ >+ emitCheck([&] { >+ return Inst(BranchTest32, nullptr, Arg::resCond(MacroAssembler::Zero), result, result); >+ }, [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) { >+ this->emitThrowException(jit, ExceptionType::OutOfBoundsTableAccess); >+ }); >+ >+ return { }; >+} >+ > auto AirIRGenerator::getLocal(uint32_t index, ExpressionType& result) -> PartialResult > { > ASSERT(m_locals[index].tmp()); >diff --git a/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp b/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp >index 1eb24652ae4ed6b3290719f7ed533692d511d2f6..99967fdc4b643fc356955211c512d6a57f95c5e4 100644 >--- a/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp >+++ b/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp >@@ -192,7 +192,9 @@ 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 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); > // Locals > PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result); > PartialResult WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value); >@@ -617,6 +619,47 @@ auto B3IRGenerator::addRefFunc(uint32_t index, ExpressionType& result) -> Partia > return { }; > } > >+auto B3IRGenerator::addTableSize(unsigned tableIndex, ExpressionType& result) -> PartialResult >+{ >+ // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>. >+ uint32_t (*doSize)(Instance*, unsigned) = [] (Instance* instance, unsigned tableIndex) -> uint32_t { >+ return instance->table(tableIndex)->length(); >+ }; >+ >+ result = m_currentBlock->appendNew<CCallValue>(m_proc, toB3Type(I32), origin(), >+ m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(doSize, B3CCallPtrTag)), >+ instanceValue(), m_currentBlock->appendNew<Const32Value>(m_proc, origin(), tableIndex)); >+ >+ return { }; >+} >+ >+auto B3IRGenerator::addTableGrow(unsigned tableIndex, ExpressionType& fill, ExpressionType& delta, ExpressionType& result) -> PartialResult >+{ >+ result = m_currentBlock->appendNew<CCallValue>(m_proc, toB3Type(I32), origin(), >+ m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&doWasmTableGrow, B3CCallPtrTag)), >+ instanceValue(), m_currentBlock->appendNew<Const32Value>(m_proc, origin(), tableIndex), fill, delta); >+ >+ return { }; >+} >+ >+auto B3IRGenerator::addTableFill(unsigned tableIndex, ExpressionType& offset, ExpressionType& fill, ExpressionType& count) -> PartialResult >+{ >+ auto result = m_currentBlock->appendNew<CCallValue>(m_proc, toB3Type(I32), origin(), >+ m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&doWasmTableFill, B3CCallPtrTag)), >+ instanceValue(), m_currentBlock->appendNew<Const32Value>(m_proc, origin(), tableIndex), offset, fill, count); >+ >+ { >+ 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::getLocal(uint32_t index, ExpressionType& result) -> PartialResult > { > ASSERT(m_locals[index]); >diff --git a/Source/JavaScriptCore/wasm/WasmExceptionType.h b/Source/JavaScriptCore/wasm/WasmExceptionType.h >index 932861ca9dd1e5ab8373956143045d17535003bc..54dbe26a9526115ce2da3d29a2ddd5153cc82987 100644 >--- a/Source/JavaScriptCore/wasm/WasmExceptionType.h >+++ b/Source/JavaScriptCore/wasm/WasmExceptionType.h >@@ -33,7 +33,7 @@ namespace Wasm { > > #define FOR_EACH_EXCEPTION(macro) \ > macro(OutOfBoundsMemoryAccess, "Out of bounds memory access") \ >- macro(OutOfBoundsTableAccess, "Out of bounds table access") \ >+ macro(OutOfBoundsTableAccess, "Out of bounds table access") \ > macro(OutOfBoundsCallIndirect, "Out of bounds call_indirect") \ > macro(NullTableEntry, "call_indirect to a null table entry") \ > macro(BadSignature, "call_indirect to a signature that does not match") \ >diff --git a/Source/JavaScriptCore/wasm/WasmFunctionParser.h b/Source/JavaScriptCore/wasm/WasmFunctionParser.h >index 72505428a9ee4560597ee71cd6e3b4efb950201a..1a7658c1efd5afc87fe43d4e273e30c2906599fe 100644 >--- a/Source/JavaScriptCore/wasm/WasmFunctionParser.h >+++ b/Source/JavaScriptCore/wasm/WasmFunctionParser.h >@@ -303,6 +303,43 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult > return { }; > } > >+ case ExtTable: { >+ 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"); >+ >+ switch (static_cast<ExtTableOpType>(extOp)) { >+ case ExtTableOpType::TableSize: { >+ ExpressionType result; >+ WASM_TRY_ADD_TO_CONTEXT(addTableSize(tableIndex, result)); >+ m_expressionStack.append(result); >+ break; >+ } >+ case ExtTableOpType::TableGrow: { >+ ExpressionType fill, delta, result; >+ WASM_TRY_POP_EXPRESSION_STACK_INTO(delta, "table.grow"); >+ WASM_TRY_POP_EXPRESSION_STACK_INTO(fill, "table.grow"); >+ WASM_TRY_ADD_TO_CONTEXT(addTableGrow(tableIndex, fill, delta, result)); >+ m_expressionStack.append(result); >+ break; >+ } >+ case ExtTableOpType::TableFill: { >+ ExpressionType offset, fill, count; >+ WASM_TRY_POP_EXPRESSION_STACK_INTO(count, "table.fill"); >+ WASM_TRY_POP_EXPRESSION_STACK_INTO(fill, "table.fill"); >+ WASM_TRY_POP_EXPRESSION_STACK_INTO(offset, "table.fill"); >+ WASM_TRY_ADD_TO_CONTEXT(addTableFill(tableIndex, offset, fill, count)); >+ break; >+ } >+ default: >+ WASM_PARSER_FAIL_IF(true, "invalid extended table op ", extOp); >+ break; >+ } >+ return { }; >+ } >+ > case RefNull: { > WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled"); > m_expressionStack.append(m_context.addConstant(Anyfunc, JSValue::encode(jsNull()))); >@@ -688,6 +725,7 @@ auto FunctionParser<Context>::parseUnreachableExpression() -> PartialResult > return { }; > } > >+ case ExtTable: > case TableGet: > case TableSet: { > unsigned tableIndex; >diff --git a/Source/JavaScriptCore/wasm/WasmInstance.cpp b/Source/JavaScriptCore/wasm/WasmInstance.cpp >index c41549be51584880feb262e9ee72a91d47e3b476..ec15d86ec86792daccadf792dc86b502d7094ee3 100644 >--- a/Source/JavaScriptCore/wasm/WasmInstance.cpp >+++ b/Source/JavaScriptCore/wasm/WasmInstance.cpp >@@ -159,6 +159,40 @@ bool setWasmTableElement(Instance* instance, unsigned tableIndex, int32_t signed > return true; > } > >+int32_t doWasmTableGrow(Instance* instance, unsigned tableIndex, EncodedJSValue fill, int32_t delta) >+{ >+ ASSERT(tableIndex < instance->module().moduleInformation().tableCount()); >+ auto oldSize = instance->table(tableIndex)->length(); >+ if (delta < 0) >+ return oldSize; >+ auto newSize = instance->table(tableIndex)->grow(delta); >+ if (!newSize || *newSize == oldSize) >+ return -1; >+ >+ for (unsigned i = oldSize; i < instance->table(tableIndex)->length(); ++i) >+ setWasmTableElement(instance, tableIndex, i, fill); >+ >+ return oldSize; >+} >+ >+bool doWasmTableFill(Instance* instance, unsigned tableIndex, int32_t unsafeOffset, EncodedJSValue fill, int32_t unsafeCount) >+{ >+ ASSERT(tableIndex < instance->module().moduleInformation().tableCount()); >+ if (unsafeOffset < 0 || unsafeCount < 0) >+ return false; >+ >+ unsigned offset = unsafeOffset; >+ unsigned count = unsafeCount; >+ >+ if (offset >= instance->table(tableIndex)->length() || offset + count > instance->table(tableIndex)->length()) >+ return false; >+ >+ for (unsigned j = 0; j < count; ++j) >+ setWasmTableElement(instance, tableIndex, offset + j, fill); >+ >+ return true; >+} >+ > EncodedJSValue doWasmRefFunc(Instance* instance, uint32_t index) > { > JSValue value = instance->getFunctionWrapper(index); >diff --git a/Source/JavaScriptCore/wasm/WasmInstance.h b/Source/JavaScriptCore/wasm/WasmInstance.h >index 012cd4573aa84f96470cb07198c7a70bb0f3a7c4..f4f35087e256d092ce74b21b8440a93725d16685 100644 >--- a/Source/JavaScriptCore/wasm/WasmInstance.h >+++ b/Source/JavaScriptCore/wasm/WasmInstance.h >@@ -44,6 +44,8 @@ class Instance; > EncodedJSValue getWasmTableElement(Instance*, unsigned, int32_t); > bool setWasmTableElement(Instance*, unsigned, int32_t, EncodedJSValue encValue); > EncodedJSValue doWasmRefFunc(Instance*, uint32_t); >+int32_t doWasmTableGrow(Instance*, unsigned, EncodedJSValue fill, int32_t delta); >+bool doWasmTableFill(Instance*, unsigned, int32_t offset, EncodedJSValue fill, int32_t count); > > class Instance : public ThreadSafeRefCounted<Instance>, public CanMakeWeakPtr<Instance> { > public: >diff --git a/Source/JavaScriptCore/wasm/WasmValidate.cpp b/Source/JavaScriptCore/wasm/WasmValidate.cpp >index bd21d80ef1a53f379b15c708821e8c6765dbdfa4..6a0bd9ffb2f9c36e87c2e15fe1043d6a57c52ee2 100644 >--- a/Source/JavaScriptCore/wasm/WasmValidate.cpp >+++ b/Source/JavaScriptCore/wasm/WasmValidate.cpp >@@ -108,7 +108,9 @@ public: > // Tables > Result WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType& index, ExpressionType& result); > Result WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType& index, ExpressionType& value); >- >+ Result WARN_UNUSED_RETURN addTableSize(unsigned, ExpressionType& result); >+ Result WARN_UNUSED_RETURN addTableGrow(unsigned, ExpressionType& fill, ExpressionType& delta, ExpressionType& result); >+ Result WARN_UNUSED_RETURN addTableFill(unsigned, ExpressionType& offset, ExpressionType& fill, ExpressionType& count); > // Locals > Result WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result); > Result WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value); >@@ -198,6 +200,34 @@ auto Validate::addTableSet(unsigned tableIndex, ExpressionType& index, Expressio > return { }; > } > >+auto Validate::addTableSize(unsigned tableIndex, ExpressionType& result) -> Result >+{ >+ result = Type::I32; >+ WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount()); >+ >+ return { }; >+} >+ >+auto Validate::addTableGrow(unsigned tableIndex, ExpressionType& fill, ExpressionType& delta, ExpressionType& result) -> Result >+{ >+ result = Type::I32; >+ WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount()); >+ WASM_VALIDATOR_FAIL_IF(!isSubtype(fill, m_module.tables[tableIndex].wasmType()), "table.grow expects fill value of type ", m_module.tables[tableIndex].wasmType(), " got ", fill); >+ WASM_VALIDATOR_FAIL_IF(Type::I32 != delta, "table.grow expects an i32 delta value, got ", delta); >+ >+ return { }; >+} >+ >+auto Validate::addTableFill(unsigned tableIndex, ExpressionType& offset, ExpressionType& fill, ExpressionType& count) -> Result >+{ >+ WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount()); >+ WASM_VALIDATOR_FAIL_IF(!isSubtype(fill, m_module.tables[tableIndex].wasmType()), "table.fill expects fill value of type ", m_module.tables[tableIndex].wasmType(), " got ", fill); >+ WASM_VALIDATOR_FAIL_IF(Type::I32 != offset, "table.fill expects an i32 offset value, got ", offset); >+ WASM_VALIDATOR_FAIL_IF(Type::I32 != count, "table.fill expects an i32 count value, got ", count); >+ >+ return { }; >+} >+ > auto Validate::addRefIsNull(ExpressionType& value, ExpressionType& result) -> Result > { > result = Type::I32; >diff --git a/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py b/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py >index 4e9a6656631979d2c9378b637e1b88f0692b751c..77564c303ca30093161cb24d9bdffaa92320d912 100755 >--- a/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py >+++ b/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py >@@ -55,17 +55,17 @@ type_definitions.extend([t for t in typeMacroizer()]) > type_definitions = "".join(type_definitions) > > >-def opcodeMacroizer(filter): >+def opcodeMacroizer(filter, opcodeField="value"): > inc = 0 > for op in wasm.opcodeIterator(filter): > b3op = "Oops" > if isSimple(op["opcode"]): > b3op = op["opcode"]["b3op"] >- yield cppMacro(op["name"], op["opcode"]["value"], b3op, inc) >+ yield cppMacro(op["name"], op["opcode"][opcodeField], b3op, inc) > inc += 1 > > defines = ["#define FOR_EACH_WASM_SPECIAL_OP(macro)"] >-defines.extend([op for op in opcodeMacroizer(lambda op: not (isUnary(op) or isBinary(op) or op["category"] == "control" or op["category"] == "memory"))]) >+defines.extend([op for op in opcodeMacroizer(lambda op: not (isUnary(op) or isBinary(op) or op["category"] == "control" or op["category"] == "memory" or op["category"] == "exttable"))]) > defines.append("\n\n#define FOR_EACH_WASM_CONTROL_FLOW_OP(macro)") > defines.extend([op for op in opcodeMacroizer(lambda op: op["category"] == "control")]) > defines.append("\n\n#define FOR_EACH_WASM_SIMPLE_UNARY_OP(macro)") >@@ -80,6 +80,8 @@ defines.append("\n\n#define FOR_EACH_WASM_MEMORY_LOAD_OP(macro)") > defines.extend([op for op in opcodeMacroizer(lambda op: (op["category"] == "memory" and len(op["return"]) == 1))]) > defines.append("\n\n#define FOR_EACH_WASM_MEMORY_STORE_OP(macro)") > defines.extend([op for op in opcodeMacroizer(lambda op: (op["category"] == "memory" and len(op["return"]) == 0))]) >+defines.append("\n\n#define FOR_EACH_WASM_EXT_TABLE_OP(macro)") >+defines.extend([op for op in opcodeMacroizer(lambda op: (op["category"] == "exttable"), "extendedOp")]) > defines.append("\n\n") > > defines = "".join(defines) >@@ -202,7 +204,8 @@ inline Type linearizedToType(int i) > FOR_EACH_WASM_UNARY_OP(macro) \\ > FOR_EACH_WASM_BINARY_OP(macro) \\ > FOR_EACH_WASM_MEMORY_LOAD_OP(macro) \\ >- FOR_EACH_WASM_MEMORY_STORE_OP(macro) >+ FOR_EACH_WASM_MEMORY_STORE_OP(macro) \\ >+ macro(ExtTable, 0xFC, Oops, 0) > > #define CREATE_ENUM_VALUE(name, id, b3op, inc) name = id, > >@@ -234,6 +237,10 @@ enum class StoreOpType : uint8_t { > FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_ENUM_VALUE) > }; > >+enum class ExtTableOpType : uint8_t { >+ FOR_EACH_WASM_EXT_TABLE_OP(CREATE_ENUM_VALUE) >+}; >+ > #undef CREATE_ENUM_VALUE > > inline bool isControlOp(OpType op) >diff --git a/Source/JavaScriptCore/wasm/wasm.json b/Source/JavaScriptCore/wasm/wasm.json >index 96e8a1d207729900d39518b10965e6c576d0f828..0d280ecd9944f742a82280eca6f56cab059733b1 100644 >--- a/Source/JavaScriptCore/wasm/wasm.json >+++ b/Source/JavaScriptCore/wasm/wasm.json >@@ -69,6 +69,9 @@ > "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": ["anyref"], "parameter": ["i32"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "get a table value" }, > "table.set": { "category": "special", "value": 38, "return": [], "parameter": ["i32", "anyref"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "set a table value" }, >+ "table.size": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": [], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "get the size of a table", "extendedOp": 15 }, >+ "table.grow": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["anyref", "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": 16 }, >+ "table.fill": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["i32", "anyref", "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 b4ee27327bc2bb117a75c013eae2e59b2675ee6b..cf7e15de02554f04fe155351debf9a1132f1706e 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,17 @@ >+2019-06-14 Justin Michaud <justin_michaud@apple.com> >+ >+ [WASM-References] Add support for Table.size, grow and fill instructions >+ https://bugs.webkit.org/show_bug.cgi?id=198761 >+ >+ Reviewed by Yusuke Suzuki. >+ >+ * wasm/Builder_WebAssemblyBinary.js: >+ (const.putOp): >+ * wasm/references/table_misc.js: Added. >+ (TableSize.End.End.WebAssembly): >+ (GetLocal.0.GetLocal.1.TableGrow.End.End.WebAssembly): >+ * wasm/wasm.json: >+ > 2019-06-18 Justin Michaud <justin_michaud@apple.com> > > [WASM-References] Add support for multiple tables >diff --git a/JSTests/wasm/Builder_WebAssemblyBinary.js b/JSTests/wasm/Builder_WebAssemblyBinary.js >index ca8fd8f65f696f9b509810c1c602ca4a7ad4c6e4..4f3a23f74ec3dc43ea452a44f3baec2ddd731ea5 100644 >--- a/JSTests/wasm/Builder_WebAssemblyBinary.js >+++ b/JSTests/wasm/Builder_WebAssemblyBinary.js >@@ -60,6 +60,8 @@ const putGlobalType = (bin, global) => { > > const putOp = (bin, op) => { > put(bin, "uint8", op.value); >+ if (WASM.description.opcode[op.name].extendedOp) >+ put(bin, "uint8", WASM.description.opcode[op.name].extendedOp); > if (op.arguments.length !== 0) > throw new Error(`Unimplemented: arguments`); // FIXME https://bugs.webkit.org/show_bug.cgi?id=162706 > >diff --git a/JSTests/wasm/references/table_misc.js b/JSTests/wasm/references/table_misc.js >new file mode 100644 >index 0000000000000000000000000000000000000000..d2095d52b60b4dd6899b4dd5f4ca63d41cd41096 >--- /dev/null >+++ b/JSTests/wasm/references/table_misc.js >@@ -0,0 +1,225 @@ >+import * as assert from '../assert.js'; >+import Builder from '../Builder.js'; >+ >+{ >+ const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder()) >+ .Type().End() >+ .Function().End() >+ .Table() >+ .Table({initial: 0, maximum: 0, element: "anyref"}) >+ .Table({initial: 20, maximum: 30, element: "anyref"}) >+ .End() >+ .Export() >+ .Function("tbl_size") >+ .Table("tbl", 1) >+ .End() >+ .Code() >+ .Function("tbl_size", { params: [], ret: "i32" }) >+ .TableSize(1) >+ .End() >+ .End().WebAssembly().get())); >+ fullGC() >+ >+ assert.eq($1.exports.tbl_size(), 20) >+ assert.eq($1.exports.tbl.grow(5), 20) >+ assert.eq($1.exports.tbl_size(), 25) >+ assert.eq($1.exports.tbl.get(0), null) >+ assert.eq($1.exports.tbl.get(24), null) >+} >+ >+assert.throws(() => new WebAssembly.Module((new Builder()) >+ .Type().End() >+ .Function().End() >+ .Export() >+ .Function("tbl_size") >+ .End() >+ .Code() >+ .Function("tbl_size", { params: [], ret: "i32" }) >+ .TableSize(0) >+ .End() >+ .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't validate: table index 0 is invalid, limit is 0, in function at index 0 (evaluating 'new WebAssembly.Module')") >+ >+{ >+ const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder()) >+ .Type().End() >+ .Function().End() >+ .Table() >+ .Table({initial: 0, maximum: 0, element: "anyref"}) >+ .Table({initial: 20, maximum: 30, element: "anyref"}) >+ .End() >+ .Export() >+ .Function("tbl_size") >+ .Function("tbl_grow") >+ .Table("tbl", 1) >+ .End() >+ .Code() >+ .Function("tbl_size", { params: [], ret: "i32" }) >+ .TableSize(1) >+ .End() >+ .Function("tbl_grow", { params: ["anyref", "i32"], ret: "i32" }) >+ .GetLocal(0) >+ .GetLocal(1) >+ .TableGrow(1) >+ .End() >+ .End().WebAssembly().get())); >+ fullGC() >+ >+ assert.eq($1.exports.tbl_size(), 20) >+ assert.eq($1.exports.tbl_grow("hi", 5), 20) >+ assert.eq($1.exports.tbl_size(), 25) >+ assert.eq($1.exports.tbl.get(0), null) >+ assert.eq($1.exports.tbl.get(24), "hi") >+ >+ assert.eq($1.exports.tbl_grow(null, 5), 25) >+ assert.eq($1.exports.tbl.get(24), "hi") >+ assert.eq($1.exports.tbl.get(25), null) >+ assert.eq($1.exports.tbl_size(), 30) >+ assert.eq($1.exports.tbl_grow(null, 0), -1) >+ assert.eq($1.exports.tbl_grow(null, 5), -1) >+ assert.eq($1.exports.tbl_grow(null, 0), -1) >+} >+ >+assert.throws(() => new WebAssembly.Module((new Builder()) >+ .Type().End() >+ .Function().End() >+ .Code() >+ .Function("tbl_grow", { params: ["anyref", "i32"], ret: "i32" }) >+ .GetLocal(0) >+ .GetLocal(1) >+ .TableGrow(0) >+ .End() >+ .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't validate: table index 0 is invalid, limit is 0, in function at index 0 (evaluating 'new WebAssembly.Module')") >+ >+assert.throws(() => new WebAssembly.Module((new Builder()) >+ .Type().End() >+ .Function().End() >+ .Table() >+ .Table({initial: 20, maximum: 30, element: "anyref"}) >+ .End() >+ .Code() >+ .Function("tbl_grow", { params: ["anyref", "i32"], ret: "i32" }) >+ .GetLocal(0) >+ .TableGrow(0) >+ .End() >+ .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't parse at byte 6: can't pop empty stack in table.grow, in function at index 0 (evaluating 'new WebAssembly.Module')") >+ >+assert.throws(() => new WebAssembly.Module((new Builder()) >+ .Type().End() >+ .Function().End() >+ .Table() >+ .Table({initial: 20, maximum: 30, element: "anyref"}) >+ .End() >+ .Code() >+ .Function("tbl_grow", { params: ["i32", "i32"], ret: "i32" }) >+ .GetLocal(0) >+ .GetLocal(1) >+ .TableGrow(0) >+ .End() >+ .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't validate: table.grow expects fill value of type Anyref got I32, in function at index 0 (evaluating 'new WebAssembly.Module')") >+ >+{ >+ const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder()) >+ .Type().End() >+ .Function().End() >+ .Table() >+ .Table({initial: 20, maximum: 30, element: "anyref"}) >+ .End() >+ .Export() >+ .Function("tbl_size") >+ .Function("tbl_fill") >+ .Table("tbl", 0) >+ .End() >+ .Code() >+ .Function("tbl_size", { params: [], ret: "i32" }) >+ .TableSize(0) >+ .End() >+ .Function("tbl_fill", { params: ["i32", "anyref", "i32"], ret: "void" }) >+ .GetLocal(0) >+ .GetLocal(1) >+ .GetLocal(2) >+ .TableFill(0) >+ .End() >+ .End().WebAssembly().get())); >+ fullGC() >+ >+ assert.eq($1.exports.tbl_size(), 20) >+ $1.exports.tbl_fill(1,"hi",3) >+ assert.eq($1.exports.tbl.get(0), null) >+ assert.eq($1.exports.tbl.get(1), "hi") >+ assert.eq($1.exports.tbl.get(2), "hi") >+ assert.eq($1.exports.tbl.get(3), "hi") >+ assert.eq($1.exports.tbl.get(4), null) >+ >+ $1.exports.tbl_fill(0,null,1) >+ assert.eq($1.exports.tbl.get(0), null) >+ $1.exports.tbl_fill(0,null,0) >+ >+ $1.exports.tbl_fill(19,"test",1) >+ assert.eq($1.exports.tbl.get(19), "test") >+ assert.eq($1.exports.tbl.get(18), null) >+ >+ assert.throws(() => $1.exports.tbl_fill(20,null,0), Error, "Out of bounds table access (evaluating 'func(...args)')") >+ assert.throws(() => $1.exports.tbl_fill(20,null,1), Error, "Out of bounds table access (evaluating 'func(...args)')") >+ assert.throws(() => $1.exports.tbl_fill(19,null,2), Error, "Out of bounds table access (evaluating 'func(...args)')") >+ assert.throws(() => $1.exports.tbl_fill(4294967295,null,1), Error, "Out of bounds table access (evaluating 'func(...args)')") >+} >+ >+assert.throws(() => new WebAssembly.Module((new Builder()) >+ .Type().End() >+ .Function().End() >+ .Code() >+ .Function("tbl_grow", { params: ["anyref", "i32"], ret: "void" }) >+ .GetLocal(1) >+ .GetLocal(0) >+ .GetLocal(1) >+ .TableFill(0) >+ .End() >+ .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't validate: table index 0 is invalid, limit is 0, in function at index 0 (evaluating 'new WebAssembly.Module')") >+ >+assert.throws(() => new WebAssembly.Module((new Builder()) >+ .Type().End() >+ .Function().End() >+ .Table() >+ .Table({initial: 20, maximum: 30, element: "anyref"}) >+ .End() >+ .Code() >+ .Function("tbl_grow", { params: ["anyref", "i32"], ret: "i32" }) >+ .GetLocal(0) >+ .TableFill(0) >+ .End() >+ .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't parse at byte 6: can't pop empty stack in table.fill, in function at index 0 (evaluating 'new WebAssembly.Module')") >+ >+{ >+ const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder()) >+ .Type().End() >+ .Function().End() >+ .Table() >+ .Table({initial: 0, maximum: 0, element: "anyfunc"}) >+ .Table({initial: 20, maximum: 30, element: "anyfunc"}) >+ .End() >+ .Export() >+ .Function("tbl_size") >+ .Function("tbl_grow") >+ .Table("tbl", 1) >+ .End() >+ .Code() >+ .Function("tbl_size", { params: [], ret: "i32" }) >+ .TableSize(1) >+ .End() >+ .Function("tbl_grow", { params: ["i32"], ret: "i32" }) >+ .I32Const(0) >+ .TableGet(1) >+ .GetLocal(0) >+ .TableGrow(1) >+ .End() >+ .End().WebAssembly().get())); >+ fullGC() >+ >+ $1.exports.tbl.set(0, $1.exports.tbl_size); >+ assert.eq($1.exports.tbl_size(), 20) >+ assert.eq($1.exports.tbl_grow(5), 20) >+ assert.eq($1.exports.tbl_size(), 25) >+ assert.eq($1.exports.tbl.get(0), $1.exports.tbl_size) >+ assert.eq($1.exports.tbl.get(1), null) >+ assert.eq($1.exports.tbl.get(24), $1.exports.tbl_size) >+} >diff --git a/JSTests/wasm/wasm.json b/JSTests/wasm/wasm.json >index 45308fbbd57532f5eba13956caacd055934acbaf..4a46904f971bcec42c306a25fc9307d30b92c90f 100644 >--- a/JSTests/wasm/wasm.json >+++ b/JSTests/wasm/wasm.json >@@ -69,6 +69,9 @@ > "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": ["anyref"], "parameter": ["i32"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "get a table value" }, > "table.set": { "category": "special", "value": 38, "return": [], "parameter": ["i32", "anyref"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "set a table value" }, >+ "table.size": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": [], "immediate": [{"name": "global_index", "type": "varuint32"}], "description": "get the size of a table", "extendedOp": 15 }, >+ "table.grow": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["anyref", "i32"], "immediate": [{"name": "global_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": 16 }, >+ "table.fill": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["i32", "anyref", "i32"], "immediate": [{"name": "global_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 198761
:
372141
|
372156
|
372397
| 372398