WebKit Bugzilla
Attachment 372141 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-20190614142014.patch (text/plain), 34.26 KB, created by
Justin Michaud
on 2019-06-14 14:20:15 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Justin Michaud
Created:
2019-06-14 14:20:15 PDT
Size:
34.26 KB
patch
obsolete
>Subversion Revision: 246418 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 65ee267357143c50676cb7e14a2d9ac568a2d18b..8a0ec1f90f9b737e30fdac25543c401d8825d6db 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 NOBODY (OOPS!). >+ >+ 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-13 Yusuke Suzuki <ysuzuki@apple.com> > > Yarr bytecode compilation failure should be gracefully handled >diff --git a/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp b/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp >index 57b3df810e4b12f9e73ac4b14780b1649d873cb2..c91f99964dff3e9477cb30f2fb216db61f1897c2 100644 >--- a/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp >+++ b/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp >@@ -238,6 +238,9 @@ public: > // Tables > PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& idx, ExpressionType& result); > PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& idx, ExpressionType& value); >+ PartialResult WARN_UNUSED_RETURN addTableSize(ExpressionType& result); >+ PartialResult WARN_UNUSED_RETURN addTableGrow(ExpressionType& fill, ExpressionType& delta, ExpressionType& result); >+ PartialResult WARN_UNUSED_RETURN addTableFill(ExpressionType& offset, ExpressionType& fill, ExpressionType& count); > > // Locals > PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result); >@@ -360,6 +363,7 @@ 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 f32() { return { newTmp(B3::FP), Type::F32 }; } > TypedTmp f64() { return { newTmp(B3::FP), Type::F64 }; } > >@@ -369,8 +373,9 @@ private: > case Type::I32: > return g32(); > case Type::I64: >- case Type::Anyref: > return g64(); >+ case Type::Anyref: >+ return gAnyref(); > case Type::F32: > return f32(); > case Type::F64: >@@ -988,6 +993,54 @@ auto AirIRGenerator::addTableSet(ExpressionType& idx, ExpressionType& value) -> > return { }; > } > >+auto AirIRGenerator::addTableSize(ExpressionType& result) -> PartialResult >+{ >+ // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>. >+ result = tmpForType(Type::I32); >+ >+ int32_t (*doSize)(Instance*) = [] (Instance* instance) -> int32_t { >+ return instance->table()->length(); >+ }; >+ >+ emitCCall(doSize, result, instanceValue()); >+ >+ return { }; >+} >+ >+auto AirIRGenerator::addTableGrow(ExpressionType& fill, ExpressionType& delta, ExpressionType& result) -> PartialResult >+{ >+ ASSERT(fill.tmp()); >+ ASSERT(fill.type() == m_info.tableInformation.wasmType()); >+ ASSERT(delta.tmp()); >+ ASSERT(delta.type() == Type::I32); >+ result = tmpForType(Type::I32); >+ >+ emitCCall(&doWasmTableGrow, result, instanceValue(), fill, delta); >+ >+ return { }; >+} >+ >+auto AirIRGenerator::addTableFill(ExpressionType& offset, ExpressionType& fill, ExpressionType& count) -> PartialResult >+{ >+ ASSERT(fill.tmp()); >+ ASSERT(fill.type() == m_info.tableInformation.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(), 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 2226ffc72c9382cc26fb3ebbe09429760ef44ab7..3048c6161712763fc30ddde35c95eb6e8c8a9991 100644 >--- a/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp >+++ b/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp >@@ -191,7 +191,9 @@ public: > // Tables > PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& idx, ExpressionType& result); > PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& idx, ExpressionType& value); >- >+ PartialResult WARN_UNUSED_RETURN addTableSize(ExpressionType& result); >+ PartialResult WARN_UNUSED_RETURN addTableGrow(ExpressionType& fill, ExpressionType& delta, ExpressionType& result); >+ PartialResult WARN_UNUSED_RETURN addTableFill(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); >@@ -596,6 +598,47 @@ auto B3IRGenerator::addTableSet(ExpressionType& idx, ExpressionType& value) -> P > return { }; > } > >+auto B3IRGenerator::addTableSize(ExpressionType& result) -> PartialResult >+{ >+ // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>. >+ uint32_t (*doSize)(Instance*) = [] (Instance* instance) -> uint32_t { >+ return instance->table()->length(); >+ }; >+ >+ result = m_currentBlock->appendNew<CCallValue>(m_proc, toB3Type(I32), origin(), >+ m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(doSize, B3CCallPtrTag)), >+ instanceValue()); >+ >+ return { }; >+} >+ >+auto B3IRGenerator::addTableGrow(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(), fill, delta); >+ >+ return { }; >+} >+ >+auto B3IRGenerator::addTableFill(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(), 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 d446c0ed1b4dd9f66ff5938265a066e0dc92d611..1aae76446858e26288c3de2b09d7d3834aab843b 100644 >--- a/Source/JavaScriptCore/wasm/WasmExceptionType.h >+++ b/Source/JavaScriptCore/wasm/WasmExceptionType.h >@@ -33,6 +33,7 @@ namespace Wasm { > > #define FOR_EACH_EXCEPTION(macro) \ > macro(OutOfBoundsMemoryAccess, "Out of bounds memory 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/WasmFormat.h b/Source/JavaScriptCore/wasm/WasmFormat.h >index 6292250f25eea9490c43a4ebd46d2e25e0c36c95..6b43cacc4c24f0c7d66022a43e4f7163d1ae72bb 100644 >--- a/Source/JavaScriptCore/wasm/WasmFormat.h >+++ b/Source/JavaScriptCore/wasm/WasmFormat.h >@@ -234,6 +234,7 @@ public: > uint32_t initial() const { return m_initial; } > Optional<uint32_t> maximum() const { return m_maximum; } > TableElementType type() const { return m_type; } >+ Wasm::Type wasmType() const { return m_type == TableElementType::Funcref ? Type::Anyfunc : Type::Anyref; } > > private: > uint32_t m_initial; >diff --git a/Source/JavaScriptCore/wasm/WasmFunctionParser.h b/Source/JavaScriptCore/wasm/WasmFunctionParser.h >index dfae8f2cf3ad2da18aa88bb26bd558cc7d8476de..24e25a13e0067425e47ef4b98bd69756f067be6f 100644 >--- a/Source/JavaScriptCore/wasm/WasmFunctionParser.h >+++ b/Source/JavaScriptCore/wasm/WasmFunctionParser.h >@@ -299,6 +299,41 @@ 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"); >+ >+ switch ((ExtTableOpType) extOp) { >+ case ExtTableOpType::TableSize: { >+ ExpressionType result; >+ WASM_TRY_ADD_TO_CONTEXT(addTableSize(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(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(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(Anyref, JSValue::encode(jsNull()))); >@@ -673,6 +708,7 @@ auto FunctionParser<Context>::parseUnreachableExpression() -> PartialResult > return { }; > } > >+ case ExtTable: > case TableGet: > case TableSet: > case RefIsNull: >diff --git a/Source/JavaScriptCore/wasm/WasmInstance.cpp b/Source/JavaScriptCore/wasm/WasmInstance.cpp >index 37059968e0b7854d27336f1937ec258a370b4966..94f5d8bb63b19dcd6e7be67fef6a7f5ec3e2f597 100644 >--- a/Source/JavaScriptCore/wasm/WasmInstance.cpp >+++ b/Source/JavaScriptCore/wasm/WasmInstance.cpp >@@ -80,6 +80,44 @@ void Instance::setGlobal(unsigned i, JSValue value) > m_globals.get()[i].anyref.set(*owner<JSWebAssemblyInstance>()->vm(), owner<JSWebAssemblyInstance>(), value); > } > >+int32_t doWasmTableGrow(Instance* instance, EncodedJSValue fill, int32_t delta) >+{ >+ if (delta < 0) >+ return -1; >+ auto oldSize = instance->table()->length(); >+ auto newSize = instance->table()->grow(delta); >+ if (!newSize || *newSize == oldSize) >+ return -1; >+ >+ JSValue fillJS = JSValue::decode(fill); >+ >+ // TODO doSet >+ for (unsigned i = oldSize; i < instance->table()->length(); ++i) >+ instance->table()->set(i, fillJS); >+ >+ return oldSize; >+} >+ >+bool doWasmTableFill(Instance* instance, int32_t offset, EncodedJSValue fill, int32_t count) >+{ >+ if (offset < 0 || count < 0) >+ return false; >+ >+ unsigned i = offset; >+ unsigned n = count; >+ >+ if (i >= instance->table()->length() || i + n > instance->table()->length()) >+ return false; >+ >+ JSValue fillJS = JSValue::decode(fill); >+ >+ // TODO doSet >+ for (unsigned j = 0; j < n; ++j) >+ instance->table()->set(j + i, fillJS); >+ >+ return true; >+} >+ > } } // namespace JSC::Wasm > > #endif // ENABLE(WEBASSEMBLY) >diff --git a/Source/JavaScriptCore/wasm/WasmInstance.h b/Source/JavaScriptCore/wasm/WasmInstance.h >index 5d1fcf3f9d3b82bd0981a20cccd544e7807ce4d7..e63ea875fc5e7da4598b123bf46170753c1d931b 100644 >--- a/Source/JavaScriptCore/wasm/WasmInstance.h >+++ b/Source/JavaScriptCore/wasm/WasmInstance.h >@@ -39,6 +39,10 @@ > namespace JSC { namespace Wasm { > > struct Context; >+class Instance; >+ >+int32_t doWasmTableGrow(Instance*, EncodedJSValue fill, int32_t delta); >+bool doWasmTableFill(Instance*, int32_t offset, EncodedJSValue fill, int32_t count); > > class Instance : public ThreadSafeRefCounted<Instance>, public CanMakeWeakPtr<Instance> { > public: >diff --git a/Source/JavaScriptCore/wasm/WasmTable.cpp b/Source/JavaScriptCore/wasm/WasmTable.cpp >index 13313468d160e85e519284e82dadc0a9adf68c03..f1a8a3e2d40df098014afe21dfdd065d23832122 100644 >--- a/Source/JavaScriptCore/wasm/WasmTable.cpp >+++ b/Source/JavaScriptCore/wasm/WasmTable.cpp >@@ -125,6 +125,9 @@ Optional<uint32_t> Table::grow(uint32_t delta) > if (!checkedGrow(m_jsValues)) > return WTF::nullopt; > >+ for (uint32_t i = m_length; i < allocatedLength(newLength); ++i) >+ m_jsValues.get()[i].setWithoutWriteBarrier(jsNull()); >+ > setLength(newLength); > return newLength; > } >diff --git a/Source/JavaScriptCore/wasm/WasmValidate.cpp b/Source/JavaScriptCore/wasm/WasmValidate.cpp >index a4b78e458df4598e0ccda61fa94ec919a29afcf4..5b943d2e3c1a9693f15d13048171a951d3cf569f 100644 >--- a/Source/JavaScriptCore/wasm/WasmValidate.cpp >+++ b/Source/JavaScriptCore/wasm/WasmValidate.cpp >@@ -107,7 +107,9 @@ public: > // Tables > Result WARN_UNUSED_RETURN addTableGet(ExpressionType& idx, ExpressionType& result); > Result WARN_UNUSED_RETURN addTableSet(ExpressionType& idx, ExpressionType& value); >- >+ Result WARN_UNUSED_RETURN addTableSize(ExpressionType& result); >+ Result WARN_UNUSED_RETURN addTableGrow(ExpressionType& fill, ExpressionType& delta, ExpressionType& result); >+ Result WARN_UNUSED_RETURN addTableFill(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); >@@ -195,6 +197,34 @@ auto Validate::addTableSet(ExpressionType& idx, ExpressionType& value) -> Result > return { }; > } > >+auto Validate::addTableSize(ExpressionType& result) -> Result >+{ >+ result = Type::I32; >+ WASM_VALIDATOR_FAIL_IF(!m_module.tableInformation, "table.size expects a table"); >+ >+ return { }; >+} >+ >+auto Validate::addTableGrow(ExpressionType& fill, ExpressionType& delta, ExpressionType& result) -> Result >+{ >+ result = Type::I32; >+ WASM_VALIDATOR_FAIL_IF(!m_module.tableInformation, "table.grow expects a table"); >+ WASM_VALIDATOR_FAIL_IF(fill != m_module.tableInformation.wasmType(), "table.grow expects fill value of type ", m_module.tableInformation.wasmType(), " got ", fill); >+ WASM_VALIDATOR_FAIL_IF(Type::I32 != delta, "table.grow expects an i32 delta value, got ", delta); >+ >+ return { }; >+} >+ >+auto Validate::addTableFill(ExpressionType& offset, ExpressionType& fill, ExpressionType& count) -> Result >+{ >+ WASM_VALIDATOR_FAIL_IF(!m_module.tableInformation, "table.fill expects a table"); >+ WASM_VALIDATOR_FAIL_IF(fill != m_module.tableInformation.wasmType(), "table.fill expects fill value of type ", m_module.tableInformation.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 30bbc74723783922edbbf634993490f48b7b7e02..615328fe64d7ea1ff87d4778d27a9f4bdb9513d3 100644 >--- a/Source/JavaScriptCore/wasm/wasm.json >+++ b/Source/JavaScriptCore/wasm/wasm.json >@@ -68,6 +68,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": [], "description": "get a table value" }, > "table.set": { "category": "special", "value": 38, "return": [], "parameter": ["i32", "anyref"], "immediate": [], "description": "set a table value" }, >+ "table.size": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": [], "immediate": [], "description": "get the size of a table", "extendedOp": 15 }, >+ "table.grow": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["anyref", "i32"], "immediate": [], "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": [], "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": "reserved", "type": "varuint1"}], "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 c64efc71170c2abb45edc2b59ac5ac0c4e016ecb..95b35a719dbcd4fb5760959c75a70c835aa6feeb 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 NOBODY (OOPS!). >+ >+ * 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-13 Yusuke Suzuki <ysuzuki@apple.com> > > Yarr bytecode compilation failure should be gracefully handled >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..eceaa53cad54c16aee68342760aba874659d27ce >--- /dev/null >+++ b/JSTests/wasm/references/table_misc.js >@@ -0,0 +1,186 @@ >+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: 20, maximum: 30, element: "anyref"}) >+ .End() >+ .Export() >+ .Function("tbl_size") >+ .Table("tbl", 0) >+ .End() >+ .Code() >+ .Function("tbl_size", { params: [], ret: "i32" }) >+ .TableSize() >+ .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() >+ .End() >+ .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't validate: table.size expects a table, 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_grow") >+ .Table("tbl", 0) >+ .End() >+ .Code() >+ .Function("tbl_size", { params: [], ret: "i32" }) >+ .TableSize() >+ .End() >+ .Function("tbl_grow", { params: ["anyref", "i32"], ret: "i32" }) >+ .GetLocal(0) >+ .GetLocal(1) >+ .TableGrow() >+ .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() >+ .End() >+ .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't validate: table.grow expects a table, 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() >+ .End() >+ .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't parse at byte 5: 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() >+ .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() >+ .End() >+ .Function("tbl_fill", { params: ["i32", "anyref", "i32"], ret: "void" }) >+ .GetLocal(0) >+ .GetLocal(1) >+ .GetLocal(2) >+ .TableFill() >+ .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(19,null,2), 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() >+ .End() >+ .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't validate: table.fill expects a table, 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() >+ .End() >+ .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't parse at byte 5: can't pop empty stack in table.fill, in function at index 0 (evaluating 'new WebAssembly.Module')") >diff --git a/JSTests/wasm/wasm.json b/JSTests/wasm/wasm.json >index 30bbc74723783922edbbf634993490f48b7b7e02..6e0d38640db18198aefe3bed3245c3ba424f4c2d 100644 >--- a/JSTests/wasm/wasm.json >+++ b/JSTests/wasm/wasm.json >@@ -68,6 +68,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": [], "description": "get a table value" }, > "table.set": { "category": "special", "value": 38, "return": [], "parameter": ["i32", "anyref"], "immediate": [], "description": "set a table value" }, >+ "table.size": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": [], "immediate": [], "description": "get the size of a table", "extendedOp": 15 }, >+ "table.grow": { "category": "exttable", "value": 252, "return": ["i32"], "parameter": ["anyref", "i32"], "immediate": [], "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": [], "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": "reserved", "type": "varuint1"}], "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