From 73051f6c32cbbce5992fa84a6d0e45a543b51df3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 12:02:38 -0700 Subject: [PATCH 01/38] start --- src/ir/ReFinalize.cpp | 1 + src/ir/child-typer.h | 6 ++++++ src/ir/cost.h | 3 +++ src/ir/effects.h | 4 ++++ src/ir/possible-contents.cpp | 1 + src/ir/subtype-exprs.h | 5 +++++ src/parser/contexts.h | 4 ++++ src/parser/parsers.h | 16 ++++++++++++++++ src/passes/Directize.cpp | 3 +++ src/passes/Table64Lowering.cpp | 6 ++++++ src/wasm.h | 15 +++++++++++++++ 11 files changed, 64 insertions(+) diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 8fae5d0731a..0f78d37b7e9 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -126,6 +126,7 @@ void ReFinalize::visitTableSize(TableSize* curr) { curr->finalize(); } void ReFinalize::visitTableGrow(TableGrow* curr) { curr->finalize(); } void ReFinalize::visitTableFill(TableFill* curr) { curr->finalize(); } void ReFinalize::visitTableCopy(TableCopy* curr) { curr->finalize(); } +void ReFinalize::visitTableInit(TableInit* curr) { curr->finalize(); } void ReFinalize::visitTry(Try* curr) { curr->finalize(); } void ReFinalize::visitTryTable(TryTable* curr) { curr->finalize(); } void ReFinalize::visitThrow(Throw* curr) { curr->finalize(); } diff --git a/src/ir/child-typer.h b/src/ir/child-typer.h index 17717a32c14..9041ca1fb79 100644 --- a/src/ir/child-typer.h +++ b/src/ir/child-typer.h @@ -736,6 +736,12 @@ template struct ChildTyper : OverriddenVisitor { note(&curr->size, Type::i32); } + void visitTableInit(TableInit* curr) { + note(&curr->dest, Type::i32); + note(&curr->source, Type::i32); + note(&curr->size, Type::i32); + } + void visitTry(Try* curr) { note(&curr->body, curr->type); for (auto& expr : curr->catchBodies) { diff --git a/src/ir/cost.h b/src/ir/cost.h index 06512d656de..462f7a4750a 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -589,6 +589,9 @@ struct CostAnalyzer : public OverriddenVisitor { CostType visitTableCopy(TableCopy* curr) { return 6 + visit(curr->dest) + visit(curr->source) + visit(curr->size); } + CostType visitTableInit(TableInit* curr) { + return 6 + visit(curr->dest) + visit(curr->offset) + visit(curr->size); + } CostType visitTry(Try* curr) { // We assume no exception will be thrown in most cases return visit(curr->body); diff --git a/src/ir/effects.h b/src/ir/effects.h index be949a8bf57..fee8b344174 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -752,6 +752,10 @@ class EffectAnalyzer { parent.writesTable = true; parent.implicitTrap = true; } + void visitTableInit(TableInit* curr) { + parent.writesTable = true; + parent.implicitTrap = true; + } void visitTry(Try* curr) { if (curr->delegateTarget.is()) { parent.delegateTargets.insert(curr->delegateTarget); diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 38fa3e5f6cf..e7454c7c6d5 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -663,6 +663,7 @@ struct InfoCollector void visitTableGrow(TableGrow* curr) { addRoot(curr); } void visitTableFill(TableFill* curr) { addRoot(curr); } void visitTableCopy(TableCopy* curr) { addRoot(curr); } + void visitTableInit(TableInit* curr) {} void visitNop(Nop* curr) {} void visitUnreachable(Unreachable* curr) {} diff --git a/src/ir/subtype-exprs.h b/src/ir/subtype-exprs.h index f563cce1453..640240df932 100644 --- a/src/ir/subtype-exprs.h +++ b/src/ir/subtype-exprs.h @@ -238,6 +238,11 @@ struct SubtypingDiscoverer : public OverriddenVisitor { self()->noteSubtype(self()->getModule()->getTable(curr->sourceTable)->type, self()->getModule()->getTable(curr->destTable)->type); } + void visitTableInit(TableInit* curr) { + auto* seg = self()->getModule()->getElementSegment(curr->segment); + self()->noteSubtype(seg->type, + self()->getModule()->getTable(curr->table)->type); + } void visitTry(Try* curr) { self()->noteSubtype(curr->body, curr); for (auto* body : curr->catchBodies) { diff --git a/src/parser/contexts.h b/src/parser/contexts.h index 5acb842d67b..721a3d3ab44 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -674,6 +674,10 @@ struct NullInstrParserCtx { makeTableCopy(Index, const std::vector&, TableIdxT*, TableIdxT*) { return Ok{}; } + Result<> + makeTableInit(Index, const std::vector&, TableIdxT*, ElemIdxT*) { + return Ok{}; + } Result<> makeThrow(Index, const std::vector&, TagIdxT) { return Ok{}; } diff --git a/src/parser/parsers.h b/src/parser/parsers.h index e3434d1e653..276130f7194 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -206,6 +206,8 @@ Result<> makeTableFill(Ctx&, Index, const std::vector&); template Result<> makeTableCopy(Ctx&, Index, const std::vector&); template +Result<> makeTableInit(Ctx&, Index, const std::vector&); +template Result<> makeThrow(Ctx&, Index, const std::vector&); template Result<> makeRethrow(Ctx&, Index, const std::vector&); @@ -2067,6 +2069,20 @@ makeTableCopy(Ctx& ctx, Index pos, const std::vector& annotations) { pos, annotations, destTable.getPtr(), srcTable.getPtr()); } +template +Result<> +makeTableInit(Ctx& ctx, Index pos, const std::vector& annotations) { + auto table = maybeTableidx(ctx); + if (table.getErr()) { + return retry(); + } + auto elem = elemidx(ctx); + if (elem.getErr()) { + return retry(); + } + return ctx.makeTableInit(pos, annotations, table.getPtr(), *elem); +} + template Result<> makeThrow(Ctx& ctx, Index pos, const std::vector& annotations) { diff --git a/src/passes/Directize.cpp b/src/passes/Directize.cpp index 6cb4e46d8c2..7faf2e23a4f 100644 --- a/src/passes/Directize.cpp +++ b/src/passes/Directize.cpp @@ -266,6 +266,9 @@ struct Directize : public Pass { void visitTableCopy(TableCopy* curr) { tablesWithSet.insert(curr->destTable); } + void visitTableInit(TableInit* curr) { + tablesWithSet.insert(curr->table); + } }; Finder(tablesWithSet).walkFunction(func); diff --git a/src/passes/Table64Lowering.cpp b/src/passes/Table64Lowering.cpp index 65c9a2a63c9..b02eecb09f7 100644 --- a/src/passes/Table64Lowering.cpp +++ b/src/passes/Table64Lowering.cpp @@ -91,6 +91,12 @@ struct Table64Lowering : public WalkerPass> { wrapAddress64(curr->size, curr->destTable); } + void visitTableInit(TableInit* curr) { + wrapAddress64(curr->dest, curr->table); + wrapAddress64(curr->offset, curr->table); + wrapAddress64(curr->size, curr->table); + } + void visitCallIndirect(CallIndirect* curr) { wrapAddress64(curr->target, curr->table); } diff --git a/src/wasm.h b/src/wasm.h index 56e94fef78b..8939f859b32 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -672,6 +672,7 @@ class Expression { TableGrowId, TableFillId, TableCopyId, + TableInitId, TryId, TryTableId, ThrowId, @@ -1415,6 +1416,20 @@ class TableCopy : public SpecificExpression { void finalize(); }; +class TableInit : public SpecificExpression { +public: + TableInit() = default; + TableInit(MixedArena& allocator) : TableInit() {} + + Name segment; + Expression* dest; + Expression* offset; + Expression* size; + Name table; + + void finalize(); +}; + // 'try' from the old (Phase 3) EH proposal class Try : public SpecificExpression { public: From 305e9a14b8642ab98aa5e4a8da601058cff221ea Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 12:56:36 -0700 Subject: [PATCH 02/38] work --- src/passes/Print.cpp | 4 ++++ src/passes/TypeGeneralizing.cpp | 2 ++ src/wasm/wasm-validator.cpp | 21 +++++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index fd22f1b716f..70ee817528b 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2037,6 +2037,10 @@ struct PrintExpressionContents o << ' '; curr->sourceTable.print(o); } + void visitTableInit(TableInit* curr) { + printMedium(o, "table.init "); + curr->table.print(o); + } void visitTry(Try* curr) { printMedium(o, "try"); if (curr->name.is()) { diff --git a/src/passes/TypeGeneralizing.cpp b/src/passes/TypeGeneralizing.cpp index faf01f173e8..fad55e50699 100644 --- a/src/passes/TypeGeneralizing.cpp +++ b/src/passes/TypeGeneralizing.cpp @@ -499,6 +499,8 @@ struct TransferFn : OverriddenVisitor { // Cannot generalize table types yet. } + void visitTableInit(TableInit* curr) {} + void visitTry(Try* curr) { WASM_UNREACHABLE("TODO"); } void visitTryTable(TryTable* curr) { WASM_UNREACHABLE("TODO"); } void visitThrow(Throw* curr) { WASM_UNREACHABLE("TODO"); } diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 6e59ce8d81b..291357fe159 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2445,6 +2445,27 @@ void FunctionValidator::visitTableCopy(TableCopy* curr) { curr->size->type, Type(Type::i32), curr, "table.copy size must be i32"); } +void FunctionValidator::visitTableCopy(TableCopy* curr) { + shouldBeTrue(getModule()->features.hasBulkMemory(), + curr, + "table.init requires bulk-memory [--enable-bulk-memory]"); + auto* segment = getModule()->getElementSegment(curr->segment); + auto* table = getModule()->getTableOrNull(curr->table); + if (shouldBeTrue(!!segment, curr, "table.init segment must exist") && + if (shouldBeTrue(!!table, curr, "table.init table must exist")) { + shouldBeSubType(segment->type, + table->type, + curr, + "table.init source must have right type for dest"); + } + shouldBeEqualOrFirstIsUnreachable( + curr->dest->type, Type(Type::i32), curr, "table.init dest must be i32"); + shouldBeEqualOrFirstIsUnreachable( + curr->offset->type, Type(Type::i32), curr, "table.init offset must be i32"); + shouldBeEqualOrFirstIsUnreachable( + curr->size->type, Type(Type::i32), curr, "table.init size must be i32"); +} + void FunctionValidator::noteDelegate(Name name, Expression* curr) { if (name != DELEGATE_CALLER_TARGET) { shouldBeTrue(delegateTargetNames.count(name) != 0, From 8fa13640a842891f51e96b561054257246f5a0ed Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 12:58:56 -0700 Subject: [PATCH 03/38] work --- src/wasm-builder.h | 14 ++++++++++++++ src/wasm/wasm-ir-builder.cpp | 8 ++++++++ src/wasm/wasm-stack.cpp | 5 +++++ src/wasm/wasm-validator.cpp | 3 ++- src/wasm/wasm.cpp | 8 ++++++++ 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/wasm-builder.h b/src/wasm-builder.h index a4f1c5cf915..72d2a1db03b 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -775,6 +775,20 @@ class Builder { ret->finalize(); return ret; } + TableInit* makeTableInit(Name segment, + Expression* dest, + Expression* offset, + Expression* size, + Name table) { + auto* ret = wasm.allocator.alloc(); + ret->segment = segment; + ret->dest = dest; + ret->offset = offset; + ret->size = size; + ret->table = table; + ret->finalize(); + return ret; + } private: Try* makeTry(Name name, diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 3db6238c4e1..1a564b25f31 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -1523,6 +1523,14 @@ Result<> IRBuilder::makeTableCopy(Name destTable, Name srcTable) { return Ok{}; } +Result<> IRBuilder::makeTableInit(Name destTable, Name srcTable) { + TableInit curr; + CHECK_ERR(visitTableInit(&curr)); + push(builder.makeTableInit( + curr.dest, curr.offset, curr.size, table, segment)); + return Ok{}; +} + Result<> IRBuilder::makeTry(Name label, Type type) { auto* tryy = wasm.allocator.alloc(); tryy->type = type; diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 19b98769b56..613bb362b18 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2035,6 +2035,11 @@ void BinaryInstWriter::visitTableCopy(TableCopy* curr) { o << U32LEB(parent.getTableIndex(curr->sourceTable)); } +void BinaryInstWriter::visitTableInit(TableInit* curr) { + o << int8_t(BinaryConsts::MiscPrefix) << U32LEB(BinaryConsts::TableInit); + o << U32LEB(parent.getTableIndex(curr->table)); +} + void BinaryInstWriter::visitTry(Try* curr) { breakStack.push_back(curr->name); o << int8_t(BinaryConsts::Try); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 291357fe159..925e9384250 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -469,6 +469,7 @@ struct FunctionValidator : public WalkerPass> { void visitTableGrow(TableGrow* curr); void visitTableFill(TableFill* curr); void visitTableCopy(TableCopy* curr); + void visitTableInit(TableInit* curr); void noteDelegate(Name name, Expression* curr); void noteRethrow(Name name, Expression* curr); void visitTry(Try* curr); @@ -2445,7 +2446,7 @@ void FunctionValidator::visitTableCopy(TableCopy* curr) { curr->size->type, Type(Type::i32), curr, "table.copy size must be i32"); } -void FunctionValidator::visitTableCopy(TableCopy* curr) { +void FunctionValidator::visitTableInit(TableInit* curr) { shouldBeTrue(getModule()->features.hasBulkMemory(), curr, "table.init requires bulk-memory [--enable-bulk-memory]"); diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index ae70e4a2238..48ccfb5153c 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -874,6 +874,14 @@ void TableCopy::finalize() { } } +void TableInit::finalize() { + type = Type::none; + if (dest->type == Type::unreachable || offset->type == Type::unreachable || + size->type == Type::unreachable) { + type = Type::unreachable; + } +} + void Try::finalize(std::optional type_) { if (type_) { type = *type_; From cb619bcb8552b3910b9078e7d359dc561cca512f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 13:07:31 -0700 Subject: [PATCH 04/38] work --- src/abi/js.h | 1 + src/asmjs/shared-constants.cpp | 1 + src/wasm-binary.h | 1 + src/wasm-delegations-fields.def | 8 ++++++ src/wasm-delegations.def | 1 + src/wasm-interpreter.h | 50 +++++++++++++++++++++++++++++++++ src/wasm-ir-builder.h | 1 + src/wasm/wasm-binary.cpp | 20 +++++++++++++ src/wasm2js.h | 16 +++++++++++ 9 files changed, 99 insertions(+) diff --git a/src/abi/js.h b/src/abi/js.h index b8f56f14d64..ff13185c682 100644 --- a/src/abi/js.h +++ b/src/abi/js.h @@ -39,6 +39,7 @@ extern IString MEMORY_COPY; extern IString TABLE_GROW; extern IString TABLE_FILL; extern IString TABLE_COPY; +extern IString TABLE_INIT; extern IString DATA_DROP; extern IString ATOMIC_WAIT_I32; extern IString ATOMIC_RMW_I64; diff --git a/src/asmjs/shared-constants.cpp b/src/asmjs/shared-constants.cpp index bd924f17943..ba06f3d73e2 100644 --- a/src/asmjs/shared-constants.cpp +++ b/src/asmjs/shared-constants.cpp @@ -115,6 +115,7 @@ IString MEMORY_COPY("wasm2js_memory_copy"); IString TABLE_GROW("wasm2js_table_grow"); IString TABLE_FILL("wasm2js_table_fill"); IString TABLE_COPY("wasm2js_table_copy"); +IString TABLE_INIT("wasm2js_table_init"); IString DATA_DROP("wasm2js_data_drop"); IString ATOMIC_WAIT_I32("wasm2js_atomic_wait_i32"); IString ATOMIC_RMW_I64("wasm2js_atomic_rmw_i64"); diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 38bf5d475a4..3cfb03d33a3 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1071,6 +1071,7 @@ enum ASTNodes { TableSize = 0x10, TableFill = 0x11, TableCopy = 0x0e, + TableInit = 0x0c, RefNull = 0xd0, RefIsNull = 0xd1, RefFunc = 0xd2, diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index 03d46020e24..3be04022094 100644 --- a/src/wasm-delegations-fields.def +++ b/src/wasm-delegations-fields.def @@ -545,6 +545,14 @@ DELEGATE_FIELD_NAME_KIND(TableCopy, sourceTable, ModuleItemKind::Table) DELEGATE_FIELD_NAME_KIND(TableCopy, destTable, ModuleItemKind::Table) DELEGATE_FIELD_CASE_END(TableCopy) +DELEGATE_FIELD_CASE_START(TableInit) +DELEGATE_FIELD_CHILD(TableInit, size) +DELEGATE_FIELD_CHILD(TableInit, offset) +DELEGATE_FIELD_CHILD(TableInit, dest) +DELEGATE_FIELD_NAME_KIND(TableInit, segment, ModuleItemKind::ElementSegment) +DELEGATE_FIELD_NAME_KIND(TableInit, table, ModuleItemKind::Table) +DELEGATE_FIELD_CASE_END(TableInit) + DELEGATE_FIELD_CASE_START(Try) DELEGATE_FIELD_SCOPE_NAME_USE(Try, delegateTarget) DELEGATE_FIELD_CHILD_VECTOR(Try, catchBodies) diff --git a/src/wasm-delegations.def b/src/wasm-delegations.def index ea801ab9bb3..f4552a98b20 100644 --- a/src/wasm-delegations.def +++ b/src/wasm-delegations.def @@ -64,6 +64,7 @@ DELEGATE(TableSize); DELEGATE(TableGrow); DELEGATE(TableFill); DELEGATE(TableCopy); +DELEGATE(TableInit); DELEGATE(Try); DELEGATE(TryTable); DELEGATE(Throw); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index f59a005b645..87f7f7f635f 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1405,6 +1405,7 @@ class ExpressionRunner : public OverriddenVisitor { Flow visitTableGrow(TableGrow* curr) { WASM_UNREACHABLE("unimp"); } Flow visitTableFill(TableFill* curr) { WASM_UNREACHABLE("unimp"); } Flow visitTableCopy(TableCopy* curr) { WASM_UNREACHABLE("unimp"); } + Flow visitTableInit(TableInit* curr) { WASM_UNREACHABLE("unimp"); } Flow visitTry(Try* curr) { WASM_UNREACHABLE("unimp"); } Flow visitTryTable(TryTable* curr) { WASM_UNREACHABLE("unimp"); } Flow visitThrow(Throw* curr) { @@ -2342,6 +2343,10 @@ class ConstantExpressionRunner : public ExpressionRunner { NOTE_ENTER("TableCopy"); return Flow(NONCONSTANT_FLOW); } + Flow visitTableInit(TableInit* curr) { + NOTE_ENTER("TableInit"); + return Flow(NONCONSTANT_FLOW); + } Flow visitLoad(Load* curr) { NOTE_ENTER("Load"); return Flow(NONCONSTANT_FLOW); @@ -3239,6 +3244,51 @@ class ModuleRunnerBase : public ExpressionRunner { return {}; } + Flow visitTableInit(TableInit* curr) { + NOTE_ENTER("TableInit"); + Flow dest = self()->visit(curr->dest); + if (dest.breaking()) { + return dest; + } + Flow offset = self()->visit(curr->offset); + if (offset.breaking()) { + return offset; + } + Flow size = self()->visit(curr->size); + if (size.breaking()) { + return size; + } + NOTE_EVAL1(dest); + NOTE_EVAL1(offset); + NOTE_EVAL1(size); + + auto* segment = wasm.getDataSegment(curr->segment); + + Address destVal(dest.getSingleValue().getUnsigned()); + Address offsetVal(uint32_t(offset.getSingleValue().geti32())); + Address sizeVal(uint32_t(size.getSingleValue().geti32())); + + if (offsetVal + sizeVal > 0 && droppedDataSegments.count(curr->segment)) { + trap("out of bounds segment access in table.init"); + } + if ((uint64_t)offsetVal + sizeVal > segment->data.size()) { + trap("out of bounds segment access in table.init"); + } + auto info = getTableInstanceInfo(curr->table); + auto tableSize = info.instance->getTableSize(info.name); + if (destVal + sizeVal > tableSize) { + trap("out of bounds table access in table.init"); + } + for (size_t i = 0; i < sizeVal; ++i) { + Literal addr(destVal + i); + info.interface()->tableStore( + info.instance->getFinalAddressWithoutOffset(addr, 1, tableSize), + segment->data[offsetVal + i], + info.name); + } + return {}; + } + Flow visitLocalGet(LocalGet* curr) { NOTE_ENTER("LocalGet"); auto index = curr->index; diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index eff8c85ad8d..a44bf01af2d 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -169,6 +169,7 @@ class IRBuilder : public UnifiedExpressionVisitor> { [[nodiscard]] Result<> makeTableGrow(Name table); [[nodiscard]] Result<> makeTableFill(Name table); [[nodiscard]] Result<> makeTableCopy(Name destTable, Name srcTable); + [[nodiscard]] Result<> makeTableInit(Name segment, Name table); [[nodiscard]] Result<> makeTry(Name label, Type type); [[nodiscard]] Result<> makeTryTable(Name label, Type type, diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 5eaa8451510..50a683aafbd 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -4198,6 +4198,9 @@ BinaryConsts::ASTNodes WasmBinaryReader::readExpression(Expression*& curr) { if (maybeVisitTableCopy(curr, opcode)) { break; } + if (maybeVisitTableInit(curr, opcode)) { + break; + } if (maybeVisitLoad(curr, opcode, BinaryConsts::MiscPrefix)) { break; } @@ -5621,6 +5624,23 @@ bool WasmBinaryReader::maybeVisitTableCopy(Expression*& out, uint32_t code) { return true; } +bool WasmBinaryReader::maybeVisitTableInit(Expression*& out, uint32_t code) { + if (code != BinaryConsts::TableInit) { + return false; + } + auto* curr = allocator.alloc(); + curr->size = popNonVoidExpression(); + curr->offset = popNonVoidExpression(); + curr->dest = popNonVoidExpression(); + Index segIdx = getU32LEB(); + elemRefs[segIdx].push_back(&curr->segment); + Index memIdx = getU32LEB(); + tableRefs[memIdx].push_back(&curr->table); + curr->finalize(); + out = curr; + return true; +} + bool WasmBinaryReader::maybeVisitBinary(Expression*& out, uint8_t code) { Binary* curr; #define INT_TYPED_CODE(code) \ diff --git a/src/wasm2js.h b/src/wasm2js.h index 7fa923ceb07..7ba0d898eb2 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -2241,6 +2241,15 @@ Ref Wasm2JSBuilder::processExpression(Expression* curr, visit(curr->source, EXPRESSION_RESULT), visit(curr->size, EXPRESSION_RESULT)); } + Ref visitTableInit(TableInit* curr) { + ABI::wasm2js::ensureHelpers(module, ABI::wasm2js::TABLE_INIT); + return ValueBuilder::makeCall( + ABI::wasm2js::TABLE_INIT, + ValueBuilder::makeNum(parent->getElemIndex(curr->segment)), + visit(curr->dest, EXPRESSION_RESULT), + visit(curr->offset, EXPRESSION_RESULT), + visit(curr->size, EXPRESSION_RESULT)); + } Ref visitTry(Try* curr) { unimplemented(curr); WASM_UNREACHABLE("unimp"); @@ -3043,6 +3052,13 @@ void Wasm2JSGlue::emitSpecialSupport() { for (var i = 0; i < size; i++) { FUNCTION_TABLE[dest + i] = FUNCTION_TABLE[source + i]; } + } + )"; + } else if (import->base == ABI::wasm2js::TABLE_INIT) { + out << R"( + function wasm2js_table_init(segment, dest, offset, size) { + // TODO: traps on invalid things + FUNCTION_TABLE.set(elementSegments[segment].subarray(offset, offset + size), dest); } )"; } else if (import->base == ABI::wasm2js::DATA_DROP) { From eba52d408c15fa8bc2df7ce741dcb114ac06d8b3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 13:07:44 -0700 Subject: [PATCH 05/38] format --- src/wasm/wasm-ir-builder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 1a564b25f31..7d04feae121 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -1526,8 +1526,8 @@ Result<> IRBuilder::makeTableCopy(Name destTable, Name srcTable) { Result<> IRBuilder::makeTableInit(Name destTable, Name srcTable) { TableInit curr; CHECK_ERR(visitTableInit(&curr)); - push(builder.makeTableInit( - curr.dest, curr.offset, curr.size, table, segment)); + push( + builder.makeTableInit(curr.dest, curr.offset, curr.size, table, segment)); return Ok{}; } From 252b7b46e7ec2435f87a6b4e8c0483c9ee84d99c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 13:22:22 -0700 Subject: [PATCH 06/38] work --- src/parser/parsers.h | 10 +++------- src/wasm-binary.h | 1 + src/wasm-interpreter.h | 7 ++++--- src/wasm2js.h | 16 ++-------------- 4 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/parser/parsers.h b/src/parser/parsers.h index 276130f7194..ba372ef5a6a 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -2073,13 +2073,9 @@ template Result<> makeTableInit(Ctx& ctx, Index pos, const std::vector& annotations) { auto table = maybeTableidx(ctx); - if (table.getErr()) { - return retry(); - } - auto elem = elemidx(ctx); - if (elem.getErr()) { - return retry(); - } + CHECK_ERR(table); + auto segment = elemidx(ctx); + CHECK_ERR(segment); return ctx.makeTableInit(pos, annotations, table.getPtr(), *elem); } diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 3cfb03d33a3..b5721cd0b34 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1746,6 +1746,7 @@ class WasmBinaryReader { bool maybeVisitTableGrow(Expression*& out, uint32_t code); bool maybeVisitTableFill(Expression*& out, uint32_t code); bool maybeVisitTableCopy(Expression*& out, uint32_t code); + bool maybeVisitTableInit(Expression*& out, uint32_t code); bool maybeVisitRefI31(Expression*& out, uint32_t code); bool maybeVisitI31Get(Expression*& out, uint32_t code); bool maybeVisitRefTest(Expression*& out, uint32_t code); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 87f7f7f635f..5f0eb364aaf 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3262,20 +3262,21 @@ class ModuleRunnerBase : public ExpressionRunner { NOTE_EVAL1(offset); NOTE_EVAL1(size); - auto* segment = wasm.getDataSegment(curr->segment); + auto* segment = wasm.getElementSegment(curr->segment); Address destVal(dest.getSingleValue().getUnsigned()); Address offsetVal(uint32_t(offset.getSingleValue().geti32())); Address sizeVal(uint32_t(size.getSingleValue().geti32())); - if (offsetVal + sizeVal > 0 && droppedDataSegments.count(curr->segment)) { + if (offsetVal + sizeVal > 0 && + droppedElementSegments.count(curr->segment)) { trap("out of bounds segment access in table.init"); } if ((uint64_t)offsetVal + sizeVal > segment->data.size()) { trap("out of bounds segment access in table.init"); } auto info = getTableInstanceInfo(curr->table); - auto tableSize = info.instance->getTableSize(info.name); + auto tableSize = info.interface()->tableSize(info.name); if (destVal + sizeVal > tableSize) { trap("out of bounds table access in table.init"); } diff --git a/src/wasm2js.h b/src/wasm2js.h index 7ba0d898eb2..15ae019ea22 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -2242,13 +2242,8 @@ Ref Wasm2JSBuilder::processExpression(Expression* curr, visit(curr->size, EXPRESSION_RESULT)); } Ref visitTableInit(TableInit* curr) { - ABI::wasm2js::ensureHelpers(module, ABI::wasm2js::TABLE_INIT); - return ValueBuilder::makeCall( - ABI::wasm2js::TABLE_INIT, - ValueBuilder::makeNum(parent->getElemIndex(curr->segment)), - visit(curr->dest, EXPRESSION_RESULT), - visit(curr->offset, EXPRESSION_RESULT), - visit(curr->size, EXPRESSION_RESULT)); + unimplemented(curr); + WASM_UNREACHABLE("unimp"); } Ref visitTry(Try* curr) { unimplemented(curr); @@ -3052,13 +3047,6 @@ void Wasm2JSGlue::emitSpecialSupport() { for (var i = 0; i < size; i++) { FUNCTION_TABLE[dest + i] = FUNCTION_TABLE[source + i]; } - } - )"; - } else if (import->base == ABI::wasm2js::TABLE_INIT) { - out << R"( - function wasm2js_table_init(segment, dest, offset, size) { - // TODO: traps on invalid things - FUNCTION_TABLE.set(elementSegments[segment].subarray(offset, offset + size), dest); } )"; } else if (import->base == ABI::wasm2js::DATA_DROP) { From dfa45812a02cd8381dbc15c1c49f41a22d3c546f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 13:25:51 -0700 Subject: [PATCH 07/38] work --- src/wasm-interpreter.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 5f0eb364aaf..9374525a98d 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3281,11 +3281,8 @@ class ModuleRunnerBase : public ExpressionRunner { trap("out of bounds table access in table.init"); } for (size_t i = 0; i < sizeVal; ++i) { - Literal addr(destVal + i); - info.interface()->tableStore( - info.instance->getFinalAddressWithoutOffset(addr, 1, tableSize), - segment->data[offsetVal + i], - info.name); + auto value = self()->visit(segment->data[offsetVal + i]).getSingleValue(); + info.interface()->tableStore(info.name, destVal + i, value); } return {}; } From 162c19876c56263657652c0d358f894066b474d9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 13:39:32 -0700 Subject: [PATCH 08/38] work --- src/ir/child-typer.h | 2 +- src/parser/parsers.h | 4 ++-- src/wasm-ir-builder.h | 2 +- src/wasm/wasm-ir-builder.cpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ir/child-typer.h b/src/ir/child-typer.h index 9041ca1fb79..216ccef5940 100644 --- a/src/ir/child-typer.h +++ b/src/ir/child-typer.h @@ -738,7 +738,7 @@ template struct ChildTyper : OverriddenVisitor { void visitTableInit(TableInit* curr) { note(&curr->dest, Type::i32); - note(&curr->source, Type::i32); + note(&curr->offset, Type::i32); note(&curr->size, Type::i32); } diff --git a/src/parser/parsers.h b/src/parser/parsers.h index ba372ef5a6a..b11cd5786ef 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -2074,8 +2074,8 @@ Result<> makeTableInit(Ctx& ctx, Index pos, const std::vector& annotations) { auto table = maybeTableidx(ctx); CHECK_ERR(table); - auto segment = elemidx(ctx); - CHECK_ERR(segment); + auto elem = elemidx(ctx); + CHECK_ERR(elem); return ctx.makeTableInit(pos, annotations, table.getPtr(), *elem); } diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index a44bf01af2d..d7a1dde87b9 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -169,7 +169,7 @@ class IRBuilder : public UnifiedExpressionVisitor> { [[nodiscard]] Result<> makeTableGrow(Name table); [[nodiscard]] Result<> makeTableFill(Name table); [[nodiscard]] Result<> makeTableCopy(Name destTable, Name srcTable); - [[nodiscard]] Result<> makeTableInit(Name segment, Name table); + [[nodiscard]] Result<> makeTableInit(Name elem, Name table); [[nodiscard]] Result<> makeTry(Name label, Type type); [[nodiscard]] Result<> makeTryTable(Name label, Type type, diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 7d04feae121..5e63e199633 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -1523,11 +1523,11 @@ Result<> IRBuilder::makeTableCopy(Name destTable, Name srcTable) { return Ok{}; } -Result<> IRBuilder::makeTableInit(Name destTable, Name srcTable) { +Result<> IRBuilder::makeTableInit(Name elem, Name table) { TableInit curr; CHECK_ERR(visitTableInit(&curr)); push( - builder.makeTableInit(curr.dest, curr.offset, curr.size, table, segment)); + builder.makeTableInit(elem, curr.dest, curr.offset, curr.size, table)); return Ok{}; } From 0f9df5b6c3a8cae91f128180ff5b5b2cd47b4813 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 13:43:13 -0700 Subject: [PATCH 09/38] fix --- src/wasm/wasm-validator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 925e9384250..504a57a9b85 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2453,7 +2453,7 @@ void FunctionValidator::visitTableInit(TableInit* curr) { auto* segment = getModule()->getElementSegment(curr->segment); auto* table = getModule()->getTableOrNull(curr->table); if (shouldBeTrue(!!segment, curr, "table.init segment must exist") && - if (shouldBeTrue(!!table, curr, "table.init table must exist")) { + shouldBeTrue(!!table, curr, "table.init table must exist")) { shouldBeSubType(segment->type, table->type, curr, From 5e71c44522ce68a26145f318dd593367bc29de80 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 13:46:05 -0700 Subject: [PATCH 10/38] work --- scripts/gen-s-parser.py | 4 +--- src/gen-s-parser.inc | 6 ++++++ test/lit/basic/table-operations.wast | 8 ++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py index 9519ad4eeae..d7a8882dc32 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -554,9 +554,7 @@ ("table.grow", "makeTableGrow()"), ("table.fill", "makeTableFill()"), ("table.copy", "makeTableCopy()"), - # TODO: - # table.init - # + ("table.init", "makeTableInit()"), # exception handling instructions ("try", "makeTry()"), ("try_table", "makeTryTable()"), diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 33cddcb26b7..1660c82fd2e 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -4885,6 +4885,12 @@ switch (buf[0]) { default: goto parse_error; } } + case 'i': + if (op == "table.init"sv) { + CHECK_ERR(makeTableInit(ctx, pos, annotations)); + return Ok{}; + } + goto parse_error; case 's': { switch (buf[7]) { case 'e': diff --git a/test/lit/basic/table-operations.wast b/test/lit/basic/table-operations.wast index 4ccbe6c6a4a..037c4852e36 100644 --- a/test/lit/basic/table-operations.wast +++ b/test/lit/basic/table-operations.wast @@ -200,6 +200,14 @@ (local.get $size) ) ) + + (func $table-init param $dest i32) (param $offset i32) (param $size i32) + (table.init $foo $table-1 + (local.get $dest) + (local.get $offset) + (local.get $size) + ) + ) ) ;; CHECK-BIN-NODEBUG: (type $0 (func)) From 7ab229d8e0717e1604fb053ee5fa58863c08bc7e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 13:52:45 -0700 Subject: [PATCH 11/38] work --- src/parser/contexts.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/parser/contexts.h b/src/parser/contexts.h index 721a3d3ab44..7e70b67764a 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -675,7 +675,7 @@ struct NullInstrParserCtx { return Ok{}; } Result<> - makeTableInit(Index, const std::vector&, TableIdxT*, ElemIdxT*) { + makeTableInit(Index, const std::vector&, TableIdxT*, ElemIdxT) { return Ok{}; } Result<> makeThrow(Index, const std::vector&, TagIdxT) { @@ -2329,6 +2329,15 @@ struct ParseDefsCtx : TypeParserCtx { return withLoc(pos, irBuilder.makeTableCopy(*dest, *src)); } + Result<> makeTableInit(Index pos, + const std::vector& annotations, + Name* table, + Name elem) { + auto t = getTable(pos, table); + CHECK_ERR(t); + return withLoc(pos, irBuilder.makeTableInit(elem, *t)); + } + Result<> makeThrow(Index pos, const std::vector& annotations, Name tag) { return withLoc(pos, irBuilder.makeThrow(tag)); From 992068f5b798fed692895ea9ffa668389fed9fe2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 13:57:28 -0700 Subject: [PATCH 12/38] wat --- test/lit/basic/table-operations.wast | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/lit/basic/table-operations.wast b/test/lit/basic/table-operations.wast index 037c4852e36..0ffd944195b 100644 --- a/test/lit/basic/table-operations.wast +++ b/test/lit/basic/table-operations.wast @@ -42,6 +42,8 @@ (elem $bar $bar $bar) ) + (elem $elem funcref) + ;; CHECK-TEXT: (elem $implicit-elem (table $table-1) (i32.const 0) func $foo) ;; CHECK-TEXT: (elem $implicit-elem_1 (table $table-2) (i32.const 0) func $bar $bar $bar) @@ -201,8 +203,8 @@ ) ) - (func $table-init param $dest i32) (param $offset i32) (param $size i32) - (table.init $foo $table-1 + (func $table-init (param $dest i32) (param $offset i32) (param $size i32) + (table.init $table-1 $elem (local.get $dest) (local.get $offset) (local.get $size) From 089210b586772d54af4713f01c9f6a67f99ff9de Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 13:59:45 -0700 Subject: [PATCH 13/38] fix --- src/wasm/wasm-stack.cpp | 1 + test/lit/basic/table-operations.wast | 84 ++++++++++++++++++---------- 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 613bb362b18..28546f74849 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2037,6 +2037,7 @@ void BinaryInstWriter::visitTableCopy(TableCopy* curr) { void BinaryInstWriter::visitTableInit(TableInit* curr) { o << int8_t(BinaryConsts::MiscPrefix) << U32LEB(BinaryConsts::TableInit); + o << U32LEB(parent.getElementSegmentIndex(curr->segment)); o << U32LEB(parent.getTableIndex(curr->table)); } diff --git a/test/lit/basic/table-operations.wast b/test/lit/basic/table-operations.wast index 0ffd944195b..d976332b3cb 100644 --- a/test/lit/basic/table-operations.wast +++ b/test/lit/basic/table-operations.wast @@ -12,24 +12,24 @@ (module ;; CHECK-TEXT: (type $0 (func)) - ;; CHECK-TEXT: (type $1 (func (result i32))) + ;; CHECK-TEXT: (type $1 (func (param i32 i32 i32))) - ;; CHECK-TEXT: (type $2 (func (param i32) (result i32))) + ;; CHECK-TEXT: (type $2 (func (result i32))) - ;; CHECK-TEXT: (type $3 (func (param i32 funcref i32))) + ;; CHECK-TEXT: (type $3 (func (param i32) (result i32))) - ;; CHECK-TEXT: (type $4 (func (param i32 i32 i32))) + ;; CHECK-TEXT: (type $4 (func (param i32 funcref i32))) ;; CHECK-TEXT: (table $table-1 1 1 funcref) ;; CHECK-BIN: (type $0 (func)) - ;; CHECK-BIN: (type $1 (func (result i32))) + ;; CHECK-BIN: (type $1 (func (param i32 i32 i32))) - ;; CHECK-BIN: (type $2 (func (param i32) (result i32))) + ;; CHECK-BIN: (type $2 (func (result i32))) - ;; CHECK-BIN: (type $3 (func (param i32 funcref i32))) + ;; CHECK-BIN: (type $3 (func (param i32) (result i32))) - ;; CHECK-BIN: (type $4 (func (param i32 i32 i32))) + ;; CHECK-BIN: (type $4 (func (param i32 funcref i32))) ;; CHECK-BIN: (table $table-1 1 1 funcref) (table $table-1 funcref @@ -42,19 +42,21 @@ (elem $bar $bar $bar) ) - (elem $elem funcref) - ;; CHECK-TEXT: (elem $implicit-elem (table $table-1) (i32.const 0) func $foo) ;; CHECK-TEXT: (elem $implicit-elem_1 (table $table-2) (i32.const 0) func $bar $bar $bar) - ;; CHECK-TEXT: (func $foo (type $0) - ;; CHECK-TEXT-NEXT: (nop) - ;; CHECK-TEXT-NEXT: ) + ;; CHECK-TEXT: (elem $elem func) ;; CHECK-BIN: (elem $0 (table $table-1) (i32.const 0) func $foo) ;; CHECK-BIN: (elem $1 (table $table-2) (i32.const 0) func $bar $bar $bar) + ;; CHECK-BIN: (elem $elem func) + (elem $elem funcref) + + ;; CHECK-TEXT: (func $foo (type $0) + ;; CHECK-TEXT-NEXT: (nop) + ;; CHECK-TEXT-NEXT: ) ;; CHECK-BIN: (func $foo (type $0) ;; CHECK-BIN-NEXT: (nop) ;; CHECK-BIN-NEXT: ) @@ -133,23 +135,23 @@ ) ) - ;; CHECK-TEXT: (func $get-table-size (type $1) (result i32) + ;; CHECK-TEXT: (func $get-table-size (type $2) (result i32) ;; CHECK-TEXT-NEXT: (table.size $table-1) ;; CHECK-TEXT-NEXT: ) - ;; CHECK-BIN: (func $get-table-size (type $1) (result i32) + ;; CHECK-BIN: (func $get-table-size (type $2) (result i32) ;; CHECK-BIN-NEXT: (table.size $table-1) ;; CHECK-BIN-NEXT: ) (func $get-table-size (result i32) (table.size $table-1) ) - ;; CHECK-TEXT: (func $table-grow (type $2) (param $sz i32) (result i32) + ;; CHECK-TEXT: (func $table-grow (type $3) (param $sz i32) (result i32) ;; CHECK-TEXT-NEXT: (table.grow $table-1 ;; CHECK-TEXT-NEXT: (ref.null nofunc) ;; CHECK-TEXT-NEXT: (local.get $sz) ;; CHECK-TEXT-NEXT: ) ;; CHECK-TEXT-NEXT: ) - ;; CHECK-BIN: (func $table-grow (type $2) (param $sz i32) (result i32) + ;; CHECK-BIN: (func $table-grow (type $3) (param $sz i32) (result i32) ;; CHECK-BIN-NEXT: (table.grow $table-1 ;; CHECK-BIN-NEXT: (ref.null nofunc) ;; CHECK-BIN-NEXT: (local.get $sz) @@ -159,14 +161,14 @@ (table.grow $table-1 (ref.null func) (local.get $sz)) ) - ;; CHECK-TEXT: (func $table-fill (type $3) (param $dest i32) (param $value funcref) (param $size i32) + ;; CHECK-TEXT: (func $table-fill (type $4) (param $dest i32) (param $value funcref) (param $size i32) ;; CHECK-TEXT-NEXT: (table.fill $table-1 ;; CHECK-TEXT-NEXT: (local.get $dest) ;; CHECK-TEXT-NEXT: (local.get $value) ;; CHECK-TEXT-NEXT: (local.get $size) ;; CHECK-TEXT-NEXT: ) ;; CHECK-TEXT-NEXT: ) - ;; CHECK-BIN: (func $table-fill (type $3) (param $dest i32) (param $value funcref) (param $size i32) + ;; CHECK-BIN: (func $table-fill (type $4) (param $dest i32) (param $value funcref) (param $size i32) ;; CHECK-BIN-NEXT: (table.fill $table-1 ;; CHECK-BIN-NEXT: (local.get $dest) ;; CHECK-BIN-NEXT: (local.get $value) @@ -181,14 +183,14 @@ ) ) - ;; CHECK-TEXT: (func $table-copy (type $4) (param $dest i32) (param $source i32) (param $size i32) + ;; CHECK-TEXT: (func $table-copy (type $1) (param $dest i32) (param $source i32) (param $size i32) ;; CHECK-TEXT-NEXT: (table.copy $table-1 $table-2 ;; CHECK-TEXT-NEXT: (local.get $dest) ;; CHECK-TEXT-NEXT: (local.get $source) ;; CHECK-TEXT-NEXT: (local.get $size) ;; CHECK-TEXT-NEXT: ) ;; CHECK-TEXT-NEXT: ) - ;; CHECK-BIN: (func $table-copy (type $4) (param $dest i32) (param $source i32) (param $size i32) + ;; CHECK-BIN: (func $table-copy (type $1) (param $dest i32) (param $source i32) (param $size i32) ;; CHECK-BIN-NEXT: (table.copy $table-1 $table-2 ;; CHECK-BIN-NEXT: (local.get $dest) ;; CHECK-BIN-NEXT: (local.get $source) @@ -203,6 +205,20 @@ ) ) + ;; CHECK-TEXT: (func $table-init (type $1) (param $dest i32) (param $offset i32) (param $size i32) + ;; CHECK-TEXT-NEXT: (table.init $table-1 + ;; CHECK-TEXT-NEXT: (local.get $dest) + ;; CHECK-TEXT-NEXT: (local.get $offset) + ;; CHECK-TEXT-NEXT: (local.get $size) + ;; CHECK-TEXT-NEXT: ) + ;; CHECK-TEXT-NEXT: ) + ;; CHECK-BIN: (func $table-init (type $1) (param $dest i32) (param $offset i32) (param $size i32) + ;; CHECK-BIN-NEXT: (table.init $table-1 + ;; CHECK-BIN-NEXT: (local.get $dest) + ;; CHECK-BIN-NEXT: (local.get $offset) + ;; CHECK-BIN-NEXT: (local.get $size) + ;; CHECK-BIN-NEXT: ) + ;; CHECK-BIN-NEXT: ) (func $table-init (param $dest i32) (param $offset i32) (param $size i32) (table.init $table-1 $elem (local.get $dest) @@ -213,13 +229,13 @@ ) ;; CHECK-BIN-NODEBUG: (type $0 (func)) -;; CHECK-BIN-NODEBUG: (type $1 (func (result i32))) +;; CHECK-BIN-NODEBUG: (type $1 (func (param i32 i32 i32))) -;; CHECK-BIN-NODEBUG: (type $2 (func (param i32) (result i32))) +;; CHECK-BIN-NODEBUG: (type $2 (func (result i32))) -;; CHECK-BIN-NODEBUG: (type $3 (func (param i32 funcref i32))) +;; CHECK-BIN-NODEBUG: (type $3 (func (param i32) (result i32))) -;; CHECK-BIN-NODEBUG: (type $4 (func (param i32 i32 i32))) +;; CHECK-BIN-NODEBUG: (type $4 (func (param i32 funcref i32))) ;; CHECK-BIN-NODEBUG: (table $0 1 1 funcref) @@ -229,6 +245,8 @@ ;; CHECK-BIN-NODEBUG: (elem $1 (table $1) (i32.const 0) func $1 $1 $1) +;; CHECK-BIN-NODEBUG: (elem $2 func) + ;; CHECK-BIN-NODEBUG: (func $0 (type $0) ;; CHECK-BIN-NODEBUG-NEXT: (nop) ;; CHECK-BIN-NODEBUG-NEXT: ) @@ -258,18 +276,18 @@ ;; CHECK-BIN-NODEBUG-NEXT: ) ;; CHECK-BIN-NODEBUG-NEXT: ) -;; CHECK-BIN-NODEBUG: (func $3 (type $1) (result i32) +;; CHECK-BIN-NODEBUG: (func $3 (type $2) (result i32) ;; CHECK-BIN-NODEBUG-NEXT: (table.size $0) ;; CHECK-BIN-NODEBUG-NEXT: ) -;; CHECK-BIN-NODEBUG: (func $4 (type $2) (param $0 i32) (result i32) +;; CHECK-BIN-NODEBUG: (func $4 (type $3) (param $0 i32) (result i32) ;; CHECK-BIN-NODEBUG-NEXT: (table.grow $0 ;; CHECK-BIN-NODEBUG-NEXT: (ref.null nofunc) ;; CHECK-BIN-NODEBUG-NEXT: (local.get $0) ;; CHECK-BIN-NODEBUG-NEXT: ) ;; CHECK-BIN-NODEBUG-NEXT: ) -;; CHECK-BIN-NODEBUG: (func $5 (type $3) (param $0 i32) (param $1 funcref) (param $2 i32) +;; CHECK-BIN-NODEBUG: (func $5 (type $4) (param $0 i32) (param $1 funcref) (param $2 i32) ;; CHECK-BIN-NODEBUG-NEXT: (table.fill $0 ;; CHECK-BIN-NODEBUG-NEXT: (local.get $0) ;; CHECK-BIN-NODEBUG-NEXT: (local.get $1) @@ -277,10 +295,18 @@ ;; CHECK-BIN-NODEBUG-NEXT: ) ;; CHECK-BIN-NODEBUG-NEXT: ) -;; CHECK-BIN-NODEBUG: (func $6 (type $4) (param $0 i32) (param $1 i32) (param $2 i32) +;; CHECK-BIN-NODEBUG: (func $6 (type $1) (param $0 i32) (param $1 i32) (param $2 i32) ;; CHECK-BIN-NODEBUG-NEXT: (table.copy $0 $1 ;; CHECK-BIN-NODEBUG-NEXT: (local.get $0) ;; CHECK-BIN-NODEBUG-NEXT: (local.get $1) ;; CHECK-BIN-NODEBUG-NEXT: (local.get $2) ;; CHECK-BIN-NODEBUG-NEXT: ) ;; CHECK-BIN-NODEBUG-NEXT: ) + +;; CHECK-BIN-NODEBUG: (func $7 (type $1) (param $0 i32) (param $1 i32) (param $2 i32) +;; CHECK-BIN-NODEBUG-NEXT: (table.init $0 +;; CHECK-BIN-NODEBUG-NEXT: (local.get $0) +;; CHECK-BIN-NODEBUG-NEXT: (local.get $1) +;; CHECK-BIN-NODEBUG-NEXT: (local.get $2) +;; CHECK-BIN-NODEBUG-NEXT: ) +;; CHECK-BIN-NODEBUG-NEXT: ) From 33ffa762e21985c22fbf355d8ab127ab370008d6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 14:07:20 -0700 Subject: [PATCH 14/38] fix --- src/wasm-interpreter.h | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 9374525a98d..7c7acca7453 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2814,23 +2814,24 @@ class ModuleRunnerBase : public ExpressionRunner { } } + Const zero; + zero.value = Literal(uint32_t(0)); + zero.finalize(); + ModuleUtils::iterActiveElementSegments(wasm, [&](ElementSegment* segment) { - Address offset = - (uint32_t)self()->visit(segment->offset).getSingleValue().geti32(); - - Table* table = wasm.getTable(segment->table); - ExternalInterface* extInterface = externalInterface; - Name tableName = segment->table; - if (table->imported()) { - auto inst = linkedInstances.at(table->module); - extInterface = inst->externalInterface; - tableName = inst->wasm.getExport(table->base)->value; - } + Const size; + size.value = Literal(uint32_t(segment->data.size())); + size.finalize(); - for (Index i = 0; i < segment->data.size(); ++i) { - Flow ret = self()->visit(segment->data[i]); - extInterface->tableStore(tableName, offset + i, ret.getSingleValue()); - } + TableInit init; + init.table = segment->table; + init.segment = segment->name; + init.dest = segment->offset; + init.offset = &zero; + init.size = &size; + init.finalize(); + + self()->visit(&init); droppedElementSegments.insert(segment->name); }); @@ -2858,9 +2859,10 @@ class ModuleRunnerBase : public ExpressionRunner { void initializeMemoryContents() { initializeMemorySizes(); - Const offset; - offset.value = Literal(uint32_t(0)); - offset.finalize(); + + Const zero; + zero.value = Literal(uint32_t(0)); + zero.finalize(); // apply active memory segments for (size_t i = 0, e = wasm.dataSegments.size(); i < e; ++i) { @@ -2876,7 +2878,7 @@ class ModuleRunnerBase : public ExpressionRunner { init.memory = segment->memory; init.segment = segment->name; init.dest = segment->offset; - init.offset = &offset; + init.offset = &zero; init.size = &size; init.finalize(); From 126a75f2c572600da15413eb643396dd9c98395d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 14:16:42 -0700 Subject: [PATCH 15/38] work --- scripts/update_lit_checks.py | 1 + test/spec/table_init.wast | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 test/spec/table_init.wast diff --git a/scripts/update_lit_checks.py b/scripts/update_lit_checks.py index 345ff39d0c6..adf01b12a31 100755 --- a/scripts/update_lit_checks.py +++ b/scripts/update_lit_checks.py @@ -158,6 +158,7 @@ def parse_output_modules(text): def parse_output_fuzz_exec(text): + print(text) # Returns the same data as `parse_output_modules`, but can't tell where # module boundaries are, so always just returns items for a single module. items = [] diff --git a/test/spec/table_init.wast b/test/spec/table_init.wast new file mode 100644 index 00000000000..7fcc6d2c06c --- /dev/null +++ b/test/spec/table_init.wast @@ -0,0 +1,21 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --output=fuzz-exec and should not be edited. + +;; RUN: wasm-opt %s -all --fuzz-exec-before -q -o /dev/null 2>&1 | filecheck %s + +;; The elem is out of bounds, leading to a trap during initialization. +(assert_unlinkable + (module + (table $table 1 1 funcref) + (elem $elem (i32.const 1) $foo) + (func $foo) + ) + "trap" +) + +;; Now it is in bounds, with the elem offset reduced to 0. +(module + (table $table 1 1 funcref) + (elem $elem (i32.const 0) $foo) + (func $foo) +) + From 8f92daa69f1d636953e8434732f77b42ab6329ef Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 14:16:56 -0700 Subject: [PATCH 16/38] format --- src/wasm/wasm-ir-builder.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 5e63e199633..ce43e151d27 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -1526,8 +1526,7 @@ Result<> IRBuilder::makeTableCopy(Name destTable, Name srcTable) { Result<> IRBuilder::makeTableInit(Name elem, Name table) { TableInit curr; CHECK_ERR(visitTableInit(&curr)); - push( - builder.makeTableInit(elem, curr.dest, curr.offset, curr.size, table)); + push(builder.makeTableInit(elem, curr.dest, curr.offset, curr.size, table)); return Ok{}; } From 4e0365253ec75879cca01963923f031e2c691407 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 15:19:29 -0700 Subject: [PATCH 17/38] oops --- scripts/update_lit_checks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/update_lit_checks.py b/scripts/update_lit_checks.py index adf01b12a31..345ff39d0c6 100755 --- a/scripts/update_lit_checks.py +++ b/scripts/update_lit_checks.py @@ -158,7 +158,6 @@ def parse_output_modules(text): def parse_output_fuzz_exec(text): - print(text) # Returns the same data as `parse_output_modules`, but can't tell where # module boundaries are, so always just returns items for a single module. items = [] From 27bf238c03901bcbebb14718498de529b88f0eff Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 15:20:27 -0700 Subject: [PATCH 18/38] fix --- src/asmjs/shared-constants.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/asmjs/shared-constants.cpp b/src/asmjs/shared-constants.cpp index ba06f3d73e2..bd924f17943 100644 --- a/src/asmjs/shared-constants.cpp +++ b/src/asmjs/shared-constants.cpp @@ -115,7 +115,6 @@ IString MEMORY_COPY("wasm2js_memory_copy"); IString TABLE_GROW("wasm2js_table_grow"); IString TABLE_FILL("wasm2js_table_fill"); IString TABLE_COPY("wasm2js_table_copy"); -IString TABLE_INIT("wasm2js_table_init"); IString DATA_DROP("wasm2js_data_drop"); IString ATOMIC_WAIT_I32("wasm2js_atomic_wait_i32"); IString ATOMIC_RMW_I64("wasm2js_atomic_rmw_i64"); From a7b6c19b85a6bec51c3f82ab08529a73d7a43a58 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 15:29:13 -0700 Subject: [PATCH 19/38] test --- .../passes/simplify-locals-table_copy.wast | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 test/lit/passes/simplify-locals-table_copy.wast diff --git a/test/lit/passes/simplify-locals-table_copy.wast b/test/lit/passes/simplify-locals-table_copy.wast new file mode 100644 index 00000000000..b55cf70f379 --- /dev/null +++ b/test/lit/passes/simplify-locals-table_copy.wast @@ -0,0 +1,73 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --simplify-locals -all -S -o - | filecheck %s + +(module + ;; CHECK: (table $table 10 funcref) + (table $table 10 funcref) + + ;; CHECK: (elem $zero (i32.const 0) $zero) + (elem $zero (i32.const 0) $zero) + + ;; CHECK: (elem $one func $one) + (elem $one $one) + + ;; CHECK: (func $move (type $0) (result funcref) + ;; CHECK-NEXT: (local $temp funcref) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (table.get $table + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $move (result funcref) + (local $temp funcref) + (local.set $temp + (table.get $table + (i32.const 0) + ) + ) + ;; We can move the table.get past the nop. + (nop) + (local.get $temp) + ) + + ;; CHECK: (func $no-move (type $0) (result funcref) + ;; CHECK-NEXT: (local $temp funcref) + ;; CHECK-NEXT: (local.set $temp + ;; CHECK-NEXT: (table.get $table + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (table.init $table + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $temp) + ;; CHECK-NEXT: ) + (func $no-move (result funcref) + (local $temp funcref) + (local.set $temp + (table.get $table + (i32.const 0) + ) + ) + ;; table.init writes to the table, so table reads cannot cross it. + (table.init $table $one (i32.const 0) (i32.const 0) (i32.const 1)) + (local.get $temp) + ) + + ;; CHECK: (func $zero (type $1) (result i32) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + (func $zero (result i32) + (i32.const 0) + ) + + ;; CHECK: (func $one (type $1) (result i32) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + (func $one (result i32) + (i32.const 1) + ) +) From 4a6044bd9998973bcf82a34d86a81d6a613785e7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 15:33:22 -0700 Subject: [PATCH 20/38] work --- test/spec/table_init.wast | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/spec/table_init.wast b/test/spec/table_init.wast index 7fcc6d2c06c..09cc0afdaf7 100644 --- a/test/spec/table_init.wast +++ b/test/spec/table_init.wast @@ -19,3 +19,34 @@ (func $foo) ) +;; The table begins with a function that returns zero. table.init will replace +;; it with one that returns 1. +(module + (type $i (func (result i32))) + + (table $table 10 funcref) + (elem $zero (i32.const 0) $zero) + (elem $one $one) + + (func $call (export "call") (result i32) + (call_indirect (type $i) (i32.const 0)) + ) + + (func $init (export "init") (result i32) + (table.init $table $one (i32.const 0) (i32.const 0) (i32.const 1)) + (call $call) + ) + + (func $zero (result i32) + (i32.const 0) + ) + + (func $one (result i32) + (i32.const 1) + ) +) + +;; First we get 0, then 1. +(assert_return (invoke "call") (i32.const 0)) +(assert_return (invoke "init") (i32.const 1)) + From 05dea1cc83559b362d1dbacc0228ea9f791fd547 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 15:36:56 -0700 Subject: [PATCH 21/38] test --- test/lit/passes/unsubtyping.wast | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/lit/passes/unsubtyping.wast b/test/lit/passes/unsubtyping.wast index 5181b9a1cdd..e531c277e71 100644 --- a/test/lit/passes/unsubtyping.wast +++ b/test/lit/passes/unsubtyping.wast @@ -818,6 +818,38 @@ ) ) +(module + ;; CHECK: (rec + ;; CHECK-NEXT: (type $0 (func)) + + ;; CHECK: (type $super (sub (struct))) + (type $super (sub (struct))) + ;; CHECK: (type $sub (sub $super (struct))) + (type $sub (sub $super (struct))) + + ;; CHECK: (table $super 1 1 (ref null $super)) + (table $super 1 1 (ref null $super)) + + ;; CHECK: (elem $sub (ref null $sub)) + (elem $sub (ref null $sub)) + + ;; CHECK: (func $table-copy (type $0) + ;; CHECK-NEXT: (table.init $super + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $table-copy + ;; This requires $sub <: $super. + (table.init $super $sub + (i32.const 0) + (i32.const 0) + (i32.const 0) + ) + ) +) + (module ;; CHECK: (rec ;; CHECK-NEXT: (type $super (sub (struct))) From ac984122a41b0192bb6c49fbe1a611fc5bfa57cb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 15:40:17 -0700 Subject: [PATCH 22/38] test --- test/lit/passes/directize_all-features.wast | 95 +++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/test/lit/passes/directize_all-features.wast b/test/lit/passes/directize_all-features.wast index 997992b0766..d645094a745 100644 --- a/test/lit/passes/directize_all-features.wast +++ b/test/lit/passes/directize_all-features.wast @@ -1599,6 +1599,101 @@ ) ) +;; A table.init prevents optimization. +(module + ;; CHECK: (type $i32 (func (result i32))) + ;; IMMUT: (type $i32 (func (result i32))) + (type $i32 (func (result i32))) + + ;; CHECK: (type $1 (func)) + + ;; CHECK: (table $table 111 funcref) + ;; IMMUT: (type $1 (func)) + + ;; IMMUT: (table $table 111 funcref) + (table $table 111 funcref) + (elem (i32.const 0) $func-A) + + ;; CHECK: (elem $0 (i32.const 0) $func-A) + + ;; CHECK: (elem $elem func $func-B) + ;; IMMUT: (elem $0 (i32.const 0) $func-A) + + ;; IMMUT: (elem $elem func $func-B) + (elem $elem $func-B) + + ;; CHECK: (export "a" (func $init)) + ;; IMMUT: (export "a" (func $init)) + (export "a" (func $init)) + ;; CHECK: (export "b" (func $call)) + ;; IMMUT: (export "b" (func $call)) + (export "b" (func $call)) + + ;; CHECK: (func $func-A (type $i32) (result i32) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; IMMUT: (func $func-A (type $i32) (result i32) + ;; IMMUT-NEXT: (i32.const 0) + ;; IMMUT-NEXT: ) + (func $func-A (result i32) + (i32.const 0) + ) + + ;; CHECK: (func $func-B (type $i32) (result i32) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; IMMUT: (func $func-B (type $i32) (result i32) + ;; IMMUT-NEXT: (unreachable) + ;; IMMUT-NEXT: ) + (func $func-B (result i32) + (unreachable) + ) + + ;; CHECK: (func $init (type $1) + ;; CHECK-NEXT: (table.init $table + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; IMMUT: (func $init (type $1) + ;; IMMUT-NEXT: (table.init $table + ;; IMMUT-NEXT: (i32.const 0) + ;; IMMUT-NEXT: (i32.const 0) + ;; IMMUT-NEXT: (i32.const 1) + ;; IMMUT-NEXT: ) + ;; IMMUT-NEXT: ) + (func $init + (table.init $table $elem + (i32.const 0) + (i32.const 0) + (i32.const 1) + ) + ) + + ;; CHECK: (func $call (type $1) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call_indirect $table (type $i32) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; IMMUT: (func $call (type $1) + ;; IMMUT-NEXT: (drop + ;; IMMUT-NEXT: (call $func-A) + ;; IMMUT-NEXT: ) + ;; IMMUT-NEXT: ) + (func $call + (drop + ;; This cannot be turned into a direct call due to the table.init, unless we + ;; assume initial contents are immutable. + (call_indirect (type $i32) + (i32.const 0) + ) + ) + ) +) + ;; The elem's offset is way out of bounds, which we should not error on, and do ;; nothing otherwise. (module From 799bc0d3bd444b540a66563c1e62f9fdb02a5e89 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 15:50:02 -0700 Subject: [PATCH 23/38] fix --- src/wasm/wasm-validator.cpp | 12 ++++++------ test/lit/passes/table64-lowering.wast | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 504a57a9b85..0fee7125ed5 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2439,11 +2439,11 @@ void FunctionValidator::visitTableCopy(TableCopy* curr) { "table.copy source must have right type for dest"); } shouldBeEqualOrFirstIsUnreachable( - curr->dest->type, Type(Type::i32), curr, "table.copy dest must be i32"); + curr->dest->type, destTable->indexType, curr, "table.copy dest must be valid"); shouldBeEqualOrFirstIsUnreachable( - curr->source->type, Type(Type::i32), curr, "table.copy source must be i32"); + curr->source->type, sourceTable->indexType, curr, "table.copy source must be valid"); shouldBeEqualOrFirstIsUnreachable( - curr->size->type, Type(Type::i32), curr, "table.copy size must be i32"); + curr->size->type, destTable->indexType, curr, "table.copy size must be valid"); } void FunctionValidator::visitTableInit(TableInit* curr) { @@ -2460,11 +2460,11 @@ void FunctionValidator::visitTableInit(TableInit* curr) { "table.init source must have right type for dest"); } shouldBeEqualOrFirstIsUnreachable( - curr->dest->type, Type(Type::i32), curr, "table.init dest must be i32"); + curr->dest->type, table->indexType, curr, "table.init dest must be valid"); shouldBeEqualOrFirstIsUnreachable( - curr->offset->type, Type(Type::i32), curr, "table.init offset must be i32"); + curr->offset->type, table->indexType, curr, "table.init offset must be valid"); shouldBeEqualOrFirstIsUnreachable( - curr->size->type, Type(Type::i32), curr, "table.init size must be i32"); + curr->size->type, table->indexType, curr, "table.init size must be valid"); } void FunctionValidator::noteDelegate(Name name, Expression* curr) { diff --git a/test/lit/passes/table64-lowering.wast b/test/lit/passes/table64-lowering.wast index 7e49d3e7303..0a1208f87fa 100644 --- a/test/lit/passes/table64-lowering.wast +++ b/test/lit/passes/table64-lowering.wast @@ -67,4 +67,21 @@ (func $test_table_fill (table.fill $t64 (i64.const 0) (ref.null func) (i64.const 10)) ) + + ;; CHECK: (func $test_table_init + ;; CHECK-NEXT: (table.init $t64 + ;; CHECK-NEXT: (i32.wrap_i64 + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.wrap_i64 + ;; CHECK-NEXT: (i64.const 5) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.wrap_i64 + ;; CHECK-NEXT: (i64.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test_table_init + (table.init $t64 $elem64 (i64.const 0) (i64.const 5) (i64.const 10)) + ) ) From 47d55869eab4e3664036fe10590025eb42a6fd53 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 15:51:15 -0700 Subject: [PATCH 24/38] fix --- src/wasm/wasm-validator.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 0fee7125ed5..6c3394345f7 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2438,12 +2438,18 @@ void FunctionValidator::visitTableCopy(TableCopy* curr) { curr, "table.copy source must have right type for dest"); } - shouldBeEqualOrFirstIsUnreachable( - curr->dest->type, destTable->indexType, curr, "table.copy dest must be valid"); - shouldBeEqualOrFirstIsUnreachable( - curr->source->type, sourceTable->indexType, curr, "table.copy source must be valid"); - shouldBeEqualOrFirstIsUnreachable( - curr->size->type, destTable->indexType, curr, "table.copy size must be valid"); + shouldBeEqualOrFirstIsUnreachable(curr->dest->type, + destTable->indexType, + curr, + "table.copy dest must be valid"); + shouldBeEqualOrFirstIsUnreachable(curr->source->type, + sourceTable->indexType, + curr, + "table.copy source must be valid"); + shouldBeEqualOrFirstIsUnreachable(curr->size->type, + destTable->indexType, + curr, + "table.copy size must be valid"); } void FunctionValidator::visitTableInit(TableInit* curr) { @@ -2461,8 +2467,10 @@ void FunctionValidator::visitTableInit(TableInit* curr) { } shouldBeEqualOrFirstIsUnreachable( curr->dest->type, table->indexType, curr, "table.init dest must be valid"); - shouldBeEqualOrFirstIsUnreachable( - curr->offset->type, table->indexType, curr, "table.init offset must be valid"); + shouldBeEqualOrFirstIsUnreachable(curr->offset->type, + table->indexType, + curr, + "table.init offset must be valid"); shouldBeEqualOrFirstIsUnreachable( curr->size->type, table->indexType, curr, "table.init size must be valid"); } From 86e87402909ac84889447ef01c8cc00fe1c990f9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 15:54:23 -0700 Subject: [PATCH 25/38] clean --- src/abi/js.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/abi/js.h b/src/abi/js.h index ff13185c682..b8f56f14d64 100644 --- a/src/abi/js.h +++ b/src/abi/js.h @@ -39,7 +39,6 @@ extern IString MEMORY_COPY; extern IString TABLE_GROW; extern IString TABLE_FILL; extern IString TABLE_COPY; -extern IString TABLE_INIT; extern IString DATA_DROP; extern IString ATOMIC_WAIT_I32; extern IString ATOMIC_RMW_I64; From 07e4dbac7cf6c257646532a07521dcce1bdbb7b9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 16:19:10 -0700 Subject: [PATCH 26/38] fix --- src/tools/wasm-ctor-eval.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 22e666a52e3..328d7cb5416 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -363,7 +363,8 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { } Index tableSize(Name tableName) override { - throw FailToEvalException("table size"); + // See callTable above, we assume the table is not modified FIXME + return wasm->getTableOrNull(tableName)->initial; } Literal tableLoad(Name tableName, Index index) override { From 14941eca3cd0fb47f0c332329703f79a5e20407d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 16:22:04 -0700 Subject: [PATCH 27/38] fix --- src/passes/Print.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 70ee817528b..9182cb2e11b 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2040,6 +2040,7 @@ struct PrintExpressionContents void visitTableInit(TableInit* curr) { printMedium(o, "table.init "); curr->table.print(o); + curr->segment.print(o); } void visitTry(Try* curr) { printMedium(o, "try"); From 9eeca0b0bf2cdec69951264cdc9012689f70565a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 16:24:42 -0700 Subject: [PATCH 28/38] fix --- src/passes/Print.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 9182cb2e11b..c9607ef8121 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2040,6 +2040,7 @@ struct PrintExpressionContents void visitTableInit(TableInit* curr) { printMedium(o, "table.init "); curr->table.print(o); + o << ' '; curr->segment.print(o); } void visitTry(Try* curr) { From e77dbcee049e1d4c3c3b05092640c38706a545bd Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 8 Aug 2024 16:25:24 -0700 Subject: [PATCH 29/38] fix --- test/lit/basic/table-operations.wast | 6 +++--- test/lit/passes/directize_all-features.wast | 4 ++-- test/lit/passes/simplify-locals-table_copy.wast | 2 +- test/lit/passes/table64-lowering.wast | 2 +- test/lit/passes/unsubtyping.wast | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/lit/basic/table-operations.wast b/test/lit/basic/table-operations.wast index d976332b3cb..8999814107a 100644 --- a/test/lit/basic/table-operations.wast +++ b/test/lit/basic/table-operations.wast @@ -206,14 +206,14 @@ ) ;; CHECK-TEXT: (func $table-init (type $1) (param $dest i32) (param $offset i32) (param $size i32) - ;; CHECK-TEXT-NEXT: (table.init $table-1 + ;; CHECK-TEXT-NEXT: (table.init $table-1 $elem ;; CHECK-TEXT-NEXT: (local.get $dest) ;; CHECK-TEXT-NEXT: (local.get $offset) ;; CHECK-TEXT-NEXT: (local.get $size) ;; CHECK-TEXT-NEXT: ) ;; CHECK-TEXT-NEXT: ) ;; CHECK-BIN: (func $table-init (type $1) (param $dest i32) (param $offset i32) (param $size i32) - ;; CHECK-BIN-NEXT: (table.init $table-1 + ;; CHECK-BIN-NEXT: (table.init $table-1 $elem ;; CHECK-BIN-NEXT: (local.get $dest) ;; CHECK-BIN-NEXT: (local.get $offset) ;; CHECK-BIN-NEXT: (local.get $size) @@ -304,7 +304,7 @@ ;; CHECK-BIN-NODEBUG-NEXT: ) ;; CHECK-BIN-NODEBUG: (func $7 (type $1) (param $0 i32) (param $1 i32) (param $2 i32) -;; CHECK-BIN-NODEBUG-NEXT: (table.init $0 +;; CHECK-BIN-NODEBUG-NEXT: (table.init $0 $2 ;; CHECK-BIN-NODEBUG-NEXT: (local.get $0) ;; CHECK-BIN-NODEBUG-NEXT: (local.get $1) ;; CHECK-BIN-NODEBUG-NEXT: (local.get $2) diff --git a/test/lit/passes/directize_all-features.wast b/test/lit/passes/directize_all-features.wast index d645094a745..074558d95ae 100644 --- a/test/lit/passes/directize_all-features.wast +++ b/test/lit/passes/directize_all-features.wast @@ -1650,14 +1650,14 @@ ) ;; CHECK: (func $init (type $1) - ;; CHECK-NEXT: (table.init $table + ;; CHECK-NEXT: (table.init $table $elem ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; IMMUT: (func $init (type $1) - ;; IMMUT-NEXT: (table.init $table + ;; IMMUT-NEXT: (table.init $table $elem ;; IMMUT-NEXT: (i32.const 0) ;; IMMUT-NEXT: (i32.const 0) ;; IMMUT-NEXT: (i32.const 1) diff --git a/test/lit/passes/simplify-locals-table_copy.wast b/test/lit/passes/simplify-locals-table_copy.wast index b55cf70f379..a10c16b1b16 100644 --- a/test/lit/passes/simplify-locals-table_copy.wast +++ b/test/lit/passes/simplify-locals-table_copy.wast @@ -38,7 +38,7 @@ ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (table.init $table + ;; CHECK-NEXT: (table.init $table $one ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (i32.const 1) diff --git a/test/lit/passes/table64-lowering.wast b/test/lit/passes/table64-lowering.wast index 0a1208f87fa..e68b78a9c17 100644 --- a/test/lit/passes/table64-lowering.wast +++ b/test/lit/passes/table64-lowering.wast @@ -69,7 +69,7 @@ ) ;; CHECK: (func $test_table_init - ;; CHECK-NEXT: (table.init $t64 + ;; CHECK-NEXT: (table.init $t64 $elem64 ;; CHECK-NEXT: (i32.wrap_i64 ;; CHECK-NEXT: (i64.const 0) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/unsubtyping.wast b/test/lit/passes/unsubtyping.wast index e531c277e71..590cc5ae104 100644 --- a/test/lit/passes/unsubtyping.wast +++ b/test/lit/passes/unsubtyping.wast @@ -834,7 +834,7 @@ (elem $sub (ref null $sub)) ;; CHECK: (func $table-copy (type $0) - ;; CHECK-NEXT: (table.init $super + ;; CHECK-NEXT: (table.init $super $sub ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (i32.const 0) From 5f5fe11118e267fd13a132cc56170912e0f7e760 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 14 Aug 2024 10:13:39 -0700 Subject: [PATCH 30/38] fix ctor-eval --- src/tools/wasm-ctor-eval.cpp | 21 +++++++---- test/lit/ctor-eval/table.init.wat | 62 +++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 test/lit/ctor-eval/table.init.wat diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 328d7cb5416..6c72f1c73a8 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -86,13 +86,6 @@ class EvallingModuleRunner : public ModuleRunnerBase { return ModuleRunnerBase::visitGlobalGet(curr); } - - Flow visitTableSet(TableSet* curr) { - // TODO: Full dynamic table support. For now we stop evalling when we see a - // table.set. (To support this we need to track sets and add code to - // serialize them.) - throw FailToEvalException("table.set: TODO"); - } }; // Build an artificial `env` module based on a module's imports, so that the @@ -174,6 +167,9 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { // not yet been re-added are a blind spot for it). std::unordered_set usedGlobalNames; + // Set to true after we create the instance. + bool instanceInitialized = false; + CtorEvalExternalInterface( std::map> linkedInstances_ = {}) { @@ -372,7 +368,15 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { } // called during initialization - void tableStore(Name tableName, Index index, const Literal& value) override {} + void tableStore(Name tableName, Index index, const Literal& value) override { + // We allow stores to the table during initialization, but not after, as we + // assume the table does not change at runtime. + // TODO: Allow table changes by updating the table later like we do with the + // memory, by tracking and serializing them. + if (instanceInitialized) { + throw FailToEvalException("tableStore after init: TODO"); + } + } int8_t load8s(Address addr, Name memoryName) override { return doLoad(addr, memoryName); @@ -1295,6 +1299,7 @@ void evalCtors(Module& wasm, try { // create an instance for evalling EvallingModuleRunner instance(wasm, &interface, linkedInstances); + interface.instanceInitialized = true; // go one by one, in order, until we fail // TODO: if we knew priorities, we could reorder? for (auto& ctor : ctors) { diff --git a/test/lit/ctor-eval/table.init.wat b/test/lit/ctor-eval/table.init.wat new file mode 100644 index 00000000000..7af2a09c6e1 --- /dev/null +++ b/test/lit/ctor-eval/table.init.wat @@ -0,0 +1,62 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: wasm-ctor-eval %s --ctors=run --kept-exports=run --quiet -all -S -o - | filecheck %s + +(module + ;; CHECK: (type $none_=>_none (func)) + (type $none_=>_none (func)) + + ;; CHECK: (table $table 22 funcref) + (table $table 22 funcref) + + ;; CHECK: (elem $init (i32.const 0) $nop) + (elem $init (i32.const 0) $nop) + + ;; CHECK: (elem $later func $trap) + (elem $later $trap) + + (export "run" (func $run)) + + (func $run (type $none_=>_none) + ;; This call can be evalled away (it does nothing as the target is a nop). + (call_indirect $table (type $none_=>_none) + (i32.const 0) + ) + + ;; We stop at this table.init, which is not handled yet. The call after it + ;; should also remain where it is. + (table.init $table $later + (i32.const 0) + (i32.const 0) + (i32.const 1) + ) + (call_indirect $table (type $none_=>_none) + (i32.const 0) + ) + ) + + ;; CHECK: (export "run" (func $run_3)) + + ;; CHECK: (func $nop (type $none_=>_none) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $nop (type $none_=>_none) + (nop) + ) + + ;; CHECK: (func $trap (type $none_=>_none) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $trap (type $none_=>_none) + (unreachable) + ) +) +;; CHECK: (func $run_3 (type $none_=>_none) +;; CHECK-NEXT: (table.init $table $later +;; CHECK-NEXT: (i32.const 0) +;; CHECK-NEXT: (i32.const 0) +;; CHECK-NEXT: (i32.const 1) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (call_indirect $table (type $none_=>_none) +;; CHECK-NEXT: (i32.const 0) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) From b5adc0be5a16c37aa55b110c8a8c1a34e26dff42 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 Aug 2024 14:01:59 -0700 Subject: [PATCH 31/38] add fixme for pre-existing bug --- src/wasm-interpreter.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 7c7acca7453..dad74844399 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3283,6 +3283,11 @@ class ModuleRunnerBase : public ExpressionRunner { trap("out of bounds table access in table.init"); } for (size_t i = 0; i < sizeVal; ++i) { + // FIXME: We should not call visit() here more than once at runtime. The + // values in the segment should be computed once during startup, + // and then read here as needed. For example, if we had a + // struct.new here then we should not allocate a new struct each + // time we table.init that data. auto value = self()->visit(segment->data[offsetVal + i]).getSingleValue(); info.interface()->tableStore(info.name, destVal + i, value); } From 8840520445d05e6491edc75015532b3c975b8cd6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 Aug 2024 16:12:07 -0700 Subject: [PATCH 32/38] remove unneeded cast in old + new code --- src/wasm-interpreter.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index dad74844399..ec215eab5eb 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3274,7 +3274,7 @@ class ModuleRunnerBase : public ExpressionRunner { droppedElementSegments.count(curr->segment)) { trap("out of bounds segment access in table.init"); } - if ((uint64_t)offsetVal + sizeVal > segment->data.size()) { + if (offsetVal + sizeVal > segment->data.size()) { trap("out of bounds segment access in table.init"); } auto info = getTableInstanceInfo(curr->table); @@ -3784,7 +3784,7 @@ class ModuleRunnerBase : public ExpressionRunner { if (offsetVal + sizeVal > 0 && droppedDataSegments.count(curr->segment)) { trap("out of bounds segment access in memory.init"); } - if ((uint64_t)offsetVal + sizeVal > segment->data.size()) { + if (offsetVal + sizeVal > segment->data.size()) { trap("out of bounds segment access in memory.init"); } auto info = getMemoryInstanceInfo(curr->memory); From 8737f7a28dc174ab21db26787c893f9565daa7b9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 Aug 2024 16:24:21 -0700 Subject: [PATCH 33/38] Properly pop an i64 for table64s --- src/ir/child-typer.h | 2 +- src/wasm/wasm-ir-builder.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ir/child-typer.h b/src/ir/child-typer.h index 216ccef5940..831523085cc 100644 --- a/src/ir/child-typer.h +++ b/src/ir/child-typer.h @@ -737,7 +737,7 @@ template struct ChildTyper : OverriddenVisitor { } void visitTableInit(TableInit* curr) { - note(&curr->dest, Type::i32); + note(&curr->dest, wasm.getTable(curr->table)->indexType); note(&curr->offset, Type::i32); note(&curr->size, Type::i32); } diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index ce43e151d27..2f2f3b595fe 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -1525,6 +1525,7 @@ Result<> IRBuilder::makeTableCopy(Name destTable, Name srcTable) { Result<> IRBuilder::makeTableInit(Name elem, Name table) { TableInit curr; + curr.table = table; CHECK_ERR(visitTableInit(&curr)); push(builder.makeTableInit(elem, curr.dest, curr.offset, curr.size, table)); return Ok{}; From 914d9ed6b7ef4d8dc0811d83964b85d2dc186b37 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 Aug 2024 16:29:23 -0700 Subject: [PATCH 34/38] fix table64 table.init --- src/passes/Table64Lowering.cpp | 2 -- src/wasm/wasm-validator.cpp | 4 ++-- test/lit/passes/table64-lowering.wast | 10 +++------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/passes/Table64Lowering.cpp b/src/passes/Table64Lowering.cpp index b02eecb09f7..71fc6a6fe6d 100644 --- a/src/passes/Table64Lowering.cpp +++ b/src/passes/Table64Lowering.cpp @@ -93,8 +93,6 @@ struct Table64Lowering : public WalkerPass> { void visitTableInit(TableInit* curr) { wrapAddress64(curr->dest, curr->table); - wrapAddress64(curr->offset, curr->table); - wrapAddress64(curr->size, curr->table); } void visitCallIndirect(CallIndirect* curr) { diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 6c3394345f7..ee767a8cd43 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2468,11 +2468,11 @@ void FunctionValidator::visitTableInit(TableInit* curr) { shouldBeEqualOrFirstIsUnreachable( curr->dest->type, table->indexType, curr, "table.init dest must be valid"); shouldBeEqualOrFirstIsUnreachable(curr->offset->type, - table->indexType, + Type(Type::i32), curr, "table.init offset must be valid"); shouldBeEqualOrFirstIsUnreachable( - curr->size->type, table->indexType, curr, "table.init size must be valid"); + curr->size->type, Type(Type::i32), curr, "table.init size must be valid"); } void FunctionValidator::noteDelegate(Name name, Expression* curr) { diff --git a/test/lit/passes/table64-lowering.wast b/test/lit/passes/table64-lowering.wast index e68b78a9c17..f3aaf4ef8a0 100644 --- a/test/lit/passes/table64-lowering.wast +++ b/test/lit/passes/table64-lowering.wast @@ -73,15 +73,11 @@ ;; CHECK-NEXT: (i32.wrap_i64 ;; CHECK-NEXT: (i64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.wrap_i64 - ;; CHECK-NEXT: (i64.const 5) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.wrap_i64 - ;; CHECK-NEXT: (i64.const 10) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 5) + ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $test_table_init - (table.init $t64 $elem64 (i64.const 0) (i64.const 5) (i64.const 10)) + (table.init $t64 $elem64 (i64.const 0) (i32.const 5) (i32.const 10)) ) ) From b60dcdc6db7921bded692fbf67629156a0fab12c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 Aug 2024 16:32:16 -0700 Subject: [PATCH 35/38] fix table.copy size validation --- src/wasm/wasm-validator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index ee767a8cd43..a10088238bc 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2446,8 +2446,9 @@ void FunctionValidator::visitTableCopy(TableCopy* curr) { sourceTable->indexType, curr, "table.copy source must be valid"); + Type sizeType = sourceTable->is64() && destTable->is64() ? Type::i64 : Type::i32; shouldBeEqualOrFirstIsUnreachable(curr->size->type, - destTable->indexType, + sizeType, curr, "table.copy size must be valid"); } From 6592e3a5f6968649395b5427872605688b2ed28f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 15 Aug 2024 16:32:48 -0700 Subject: [PATCH 36/38] format --- src/wasm/wasm-validator.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index a10088238bc..fa7bdfb6a4f 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2446,11 +2446,10 @@ void FunctionValidator::visitTableCopy(TableCopy* curr) { sourceTable->indexType, curr, "table.copy source must be valid"); - Type sizeType = sourceTable->is64() && destTable->is64() ? Type::i64 : Type::i32; - shouldBeEqualOrFirstIsUnreachable(curr->size->type, - sizeType, - curr, - "table.copy size must be valid"); + Type sizeType = + sourceTable->is64() && destTable->is64() ? Type::i64 : Type::i32; + shouldBeEqualOrFirstIsUnreachable( + curr->size->type, sizeType, curr, "table.copy size must be valid"); } void FunctionValidator::visitTableInit(TableInit* curr) { From ca584b18e4d17f722da0e1eefed9c5ce16d6b157 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 16 Aug 2024 10:54:37 -0700 Subject: [PATCH 37/38] update test --- test/binaryen.js/exception-handling.js.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/binaryen.js/exception-handling.js.txt b/test/binaryen.js/exception-handling.js.txt index d2a0c6dd62f..f8b71302538 100644 --- a/test/binaryen.js/exception-handling.js.txt +++ b/test/binaryen.js/exception-handling.js.txt @@ -34,7 +34,7 @@ ) ) -getExpressionInfo(throw) = {"id":53,"type":1,"tag":"e"} -getExpressionInfo(rethrow) = {"id":54,"type":1,"target":"l0"} -getExpressionInfo(try_catch) = {"id":51,"type":1,"name":"l0","hasCatchAll":0,"delegateTarget":"","isDelegate":0} -getExpressionInfo(try_delegate) = {"id":51,"type":0,"name":"try_outer","hasCatchAll":1,"delegateTarget":"","isDelegate":0} +getExpressionInfo(throw) = {"id":54,"type":1,"tag":"e"} +getExpressionInfo(rethrow) = {"id":55,"type":1,"target":"l0"} +getExpressionInfo(try_catch) = {"id":52,"type":1,"name":"l0","hasCatchAll":0,"delegateTarget":"","isDelegate":0} +getExpressionInfo(try_delegate) = {"id":52,"type":0,"name":"try_outer","hasCatchAll":1,"delegateTarget":"","isDelegate":0} From a0217b891307d8c48cd6e86d6cf66c1ceee3dfb5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 16 Aug 2024 11:19:54 -0700 Subject: [PATCH 38/38] update test --- test/binaryen.js/kitchen-sink.js.txt | 58 ++++++++++++++-------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt index 28922c2a0ab..212194c9c86 100644 --- a/test/binaryen.js/kitchen-sink.js.txt +++ b/test/binaryen.js/kitchen-sink.js.txt @@ -82,35 +82,35 @@ TableGetId: 45 TableSetId: 46 TableSizeId: 47 TableGrowId: 48 -TryId: 51 -ThrowId: 53 -RethrowId: 54 -TupleMakeId: 56 -TupleExtractId: 57 -RefI31Id: 58 -I31GetId: 59 -CallRefId: 60 -RefTestId: 61 -RefCastId: 62 -BrOnId: 63 -StructNewId: 64 -StructGetId: 65 -StructSetId: 66 -ArrayNewId: 67 -ArrayNewFixedId: 70 -ArrayGetId: 71 -ArraySetId: 72 -ArrayLenId: 73 -ArrayCopy: 74 -RefAs: 78 -StringNew: 79 -StringConst: 80 -StringMeasure: 81 -StringEncode: 82 -StringConcat: 83 -StringEq: 84 -StringWTF16Get: 85 -StringSliceWTF: 86 +TryId: 52 +ThrowId: 54 +RethrowId: 55 +TupleMakeId: 57 +TupleExtractId: 58 +RefI31Id: 59 +I31GetId: 60 +CallRefId: 61 +RefTestId: 62 +RefCastId: 63 +BrOnId: 64 +StructNewId: 65 +StructGetId: 66 +StructSetId: 67 +ArrayNewId: 68 +ArrayNewFixedId: 71 +ArrayGetId: 72 +ArraySetId: 73 +ArrayLenId: 74 +ArrayCopy: 75 +RefAs: 79 +StringNew: 80 +StringConst: 81 +StringMeasure: 82 +StringEncode: 83 +StringConcat: 84 +StringEq: 85 +StringWTF16Get: 86 +StringSliceWTF: 87 getExpressionInfo={"id":15,"type":4,"op":6} (f32.neg (f32.const -33.61199951171875)