diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gen-s-parser.inc | 16 | ||||
-rw-r--r-- | src/ir/ReFinalize.cpp | 6 | ||||
-rw-r--r-- | src/ir/cost.h | 11 | ||||
-rw-r--r-- | src/ir/effects.h | 11 | ||||
-rw-r--r-- | src/ir/memory-utils.cpp | 6 | ||||
-rw-r--r-- | src/ir/module-utils.cpp | 8 | ||||
-rw-r--r-- | src/ir/possible-contents.cpp | 30 | ||||
-rw-r--r-- | src/passes/MemoryPacking.cpp | 24 | ||||
-rw-r--r-- | src/passes/Print.cpp | 45 | ||||
-rw-r--r-- | src/passes/RemoveUnusedModuleElements.cpp | 33 | ||||
-rw-r--r-- | src/passes/TypeSSA.cpp | 7 | ||||
-rw-r--r-- | src/wasm-binary.h | 4 | ||||
-rw-r--r-- | src/wasm-builder.h | 52 | ||||
-rw-r--r-- | src/wasm-delegations-fields.def | 48 | ||||
-rw-r--r-- | src/wasm-delegations.def | 6 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 201 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 6 | ||||
-rw-r--r-- | src/wasm.h | 51 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 47 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 34 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 54 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 141 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 19 | ||||
-rw-r--r-- | src/wasm/wat-parser.cpp | 59 | ||||
-rw-r--r-- | src/wasm2js.h | 12 |
25 files changed, 563 insertions, 368 deletions
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 64027fc59..772847f9b 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -41,10 +41,10 @@ switch (buf[0]) { case 'i': { switch (buf[11]) { case 'd': - if (op == "array.init_data"sv) { return makeArrayInit(s, InitData); } + if (op == "array.init_data"sv) { return makeArrayInitData(s); } goto parse_error; case 'e': - if (op == "array.init_elem"sv) { return makeArrayInit(s, InitElem); } + if (op == "array.init_elem"sv) { return makeArrayInitElem(s); } goto parse_error; case 's': if (op == "array.init_static"sv) { return makeArrayNewFixed(s); } @@ -65,7 +65,7 @@ switch (buf[0]) { case 'd': { switch (buf[11]) { case 'a': - if (op == "array.new_data"sv) { return makeArrayNewSeg(s, NewData); } + if (op == "array.new_data"sv) { return makeArrayNewData(s); } goto parse_error; case 'e': if (op == "array.new_default"sv) { return makeArrayNew(s, true); } @@ -74,7 +74,7 @@ switch (buf[0]) { } } case 'e': - if (op == "array.new_elem"sv) { return makeArrayNewSeg(s, NewElem); } + if (op == "array.new_elem"sv) { return makeArrayNewElem(s); } goto parse_error; case 'f': if (op == "array.new_fixed"sv) { return makeArrayNewFixed(s); } @@ -3663,14 +3663,14 @@ switch (buf[0]) { switch (buf[11]) { case 'd': if (op == "array.init_data"sv) { - auto ret = makeArrayInit(ctx, pos, InitData); + auto ret = makeArrayInitData(ctx, pos); CHECK_ERR(ret); return *ret; } goto parse_error; case 'e': if (op == "array.init_elem"sv) { - auto ret = makeArrayInit(ctx, pos, InitElem); + auto ret = makeArrayInitElem(ctx, pos); CHECK_ERR(ret); return *ret; } @@ -3707,7 +3707,7 @@ switch (buf[0]) { switch (buf[11]) { case 'a': if (op == "array.new_data"sv) { - auto ret = makeArrayNewSeg(ctx, pos, NewData); + auto ret = makeArrayNewData(ctx, pos); CHECK_ERR(ret); return *ret; } @@ -3724,7 +3724,7 @@ switch (buf[0]) { } case 'e': if (op == "array.new_elem"sv) { - auto ret = makeArrayNewSeg(ctx, pos, NewElem); + auto ret = makeArrayNewElem(ctx, pos); CHECK_ERR(ret); return *ret; } diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 9d68a9fe8..e6ea0ecf1 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -164,14 +164,16 @@ void ReFinalize::visitStructNew(StructNew* curr) { curr->finalize(); } void ReFinalize::visitStructGet(StructGet* curr) { curr->finalize(); } void ReFinalize::visitStructSet(StructSet* curr) { curr->finalize(); } void ReFinalize::visitArrayNew(ArrayNew* curr) { curr->finalize(); } -void ReFinalize::visitArrayNewSeg(ArrayNewSeg* curr) { curr->finalize(); } +void ReFinalize::visitArrayNewData(ArrayNewData* curr) { curr->finalize(); } +void ReFinalize::visitArrayNewElem(ArrayNewElem* curr) { curr->finalize(); } void ReFinalize::visitArrayNewFixed(ArrayNewFixed* curr) { curr->finalize(); } void ReFinalize::visitArrayGet(ArrayGet* curr) { curr->finalize(); } void ReFinalize::visitArraySet(ArraySet* curr) { curr->finalize(); } void ReFinalize::visitArrayLen(ArrayLen* curr) { curr->finalize(); } void ReFinalize::visitArrayCopy(ArrayCopy* curr) { curr->finalize(); } void ReFinalize::visitArrayFill(ArrayFill* curr) { curr->finalize(); } -void ReFinalize::visitArrayInit(ArrayInit* curr) { curr->finalize(); } +void ReFinalize::visitArrayInitData(ArrayInitData* curr) { curr->finalize(); } +void ReFinalize::visitArrayInitElem(ArrayInitElem* curr) { curr->finalize(); } void ReFinalize::visitRefAs(RefAs* curr) { curr->finalize(); } void ReFinalize::visitStringNew(StringNew* curr) { curr->finalize(); } void ReFinalize::visitStringConst(StringConst* curr) { curr->finalize(); } diff --git a/src/ir/cost.h b/src/ir/cost.h index c19441555..c34ca1fb6 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -636,7 +636,10 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> { CostType visitArrayNew(ArrayNew* curr) { return 4 + visit(curr->size) + maybeVisit(curr->init); } - CostType visitArrayNewSeg(ArrayNewSeg* curr) { + CostType visitArrayNewData(ArrayNewData* curr) { + return 4 + visit(curr->offset) + visit(curr->size); + } + CostType visitArrayNewElem(ArrayNewElem* curr) { return 4 + visit(curr->offset) + visit(curr->size); } CostType visitArrayNewFixed(ArrayNewFixed* curr) { @@ -665,7 +668,11 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> { return 6 + visit(curr->ref) + visit(curr->index) + visit(curr->value) + visit(curr->size); } - CostType visitArrayInit(ArrayInit* curr) { + CostType visitArrayInitData(ArrayInitData* curr) { + return 6 + visit(curr->ref) + visit(curr->index) + visit(curr->offset) + + visit(curr->size); + } + CostType visitArrayInitElem(ArrayInitElem* curr) { return 6 + visit(curr->ref) + visit(curr->index) + visit(curr->offset) + visit(curr->size); } diff --git a/src/ir/effects.h b/src/ir/effects.h index c5251ae64..fe2520299 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -755,7 +755,12 @@ private: } } void visitArrayNew(ArrayNew* curr) {} - void visitArrayNewSeg(ArrayNewSeg* curr) { + void visitArrayNewData(ArrayNewData* curr) { + // Traps on out of bounds access to segments or access to dropped + // segments. + parent.implicitTrap = true; + } + void visitArrayNewElem(ArrayNewElem* curr) { // Traps on out of bounds access to segments or access to dropped // segments. parent.implicitTrap = true; @@ -808,7 +813,7 @@ private: // Traps when the destination is null or when out of bounds. parent.implicitTrap = true; } - void visitArrayInit(ArrayInit* curr) { + template<typename ArrayInit> void visitArrayInit(ArrayInit* curr) { if (curr->ref->type.isNull()) { parent.trap = true; return; @@ -818,6 +823,8 @@ private: // destination, or when the source segment has been dropped. parent.implicitTrap = true; } + void visitArrayInitData(ArrayInitData* curr) { visitArrayInit(curr); } + void visitArrayInitElem(ArrayInitElem* curr) { visitArrayInit(curr); } void visitRefAs(RefAs* curr) { if (curr->op == ExternInternalize || curr->op == ExternExternalize) { // These conversions are infallible. diff --git a/src/ir/memory-utils.cpp b/src/ir/memory-utils.cpp index 9ab0e33fc..49ec25529 100644 --- a/src/ir/memory-utils.cpp +++ b/src/ir/memory-utils.cpp @@ -39,10 +39,8 @@ bool flatten(Module& wasm) { void visitMemoryInit(MemoryInit* curr) { noticesSegmentIdentity = true; } void visitDataDrop(DataDrop* curr) { noticesSegmentIdentity = true; } - void visitArrayNewSeg(ArrayNewSeg* curr) { - if (curr->op == NewData) { - noticesSegmentIdentity = true; - } + void visitArrayNewData(ArrayNewData* curr) { + noticesSegmentIdentity = true; } }; diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp index ce6fadda7..d3ca1c192 100644 --- a/src/ir/module-utils.cpp +++ b/src/ir/module-utils.cpp @@ -70,7 +70,9 @@ struct CodeScanner counts.note(curr->type); } else if (curr->is<ArrayNew>()) { counts.note(curr->type); - } else if (curr->is<ArrayNewSeg>()) { + } else if (curr->is<ArrayNewData>()) { + counts.note(curr->type); + } else if (curr->is<ArrayNewElem>()) { counts.note(curr->type); } else if (curr->is<ArrayNewFixed>()) { counts.note(curr->type); @@ -79,7 +81,9 @@ struct CodeScanner counts.note(copy->srcRef->type); } else if (auto* fill = curr->dynCast<ArrayFill>()) { counts.note(fill->ref->type); - } else if (auto* init = curr->dynCast<ArrayInit>()) { + } else if (auto* init = curr->dynCast<ArrayInitData>()) { + counts.note(init->ref->type); + } else if (auto* init = curr->dynCast<ArrayInitElem>()) { counts.note(init->ref->type); } else if (auto* cast = curr->dynCast<RefCast>()) { counts.note(cast->type); diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index e991a68fd..db2655e8a 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -904,26 +904,24 @@ struct InfoCollector } addRoot(curr, PossibleContents::exactType(curr->type)); } - void visitArrayNewSeg(ArrayNewSeg* curr) { + void visitArrayNewData(ArrayNewData* curr) { if (curr->type == Type::unreachable) { return; } addRoot(curr, PossibleContents::exactType(curr->type)); auto heapType = curr->type.getHeapType(); - switch (curr->op) { - case NewData: { - Type elemType = heapType.getArray().element.type; - addRoot(DataLocation{heapType, 0}, - PossibleContents::fromType(elemType)); - return; - } - case NewElem: { - Type segType = getModule()->getElementSegment(curr->segment)->type; - addRoot(DataLocation{heapType, 0}, PossibleContents::fromType(segType)); - return; - } + Type elemType = heapType.getArray().element.type; + addRoot(DataLocation{heapType, 0}, PossibleContents::fromType(elemType)); + } + void visitArrayNewElem(ArrayNewElem* curr) { + if (curr->type == Type::unreachable) { + return; } - WASM_UNREACHABLE("unexpected op"); + addRoot(curr, PossibleContents::exactType(curr->type)); + auto heapType = curr->type.getHeapType(); + Type segType = getModule()->getElementSegment(curr->segment)->type; + addRoot(DataLocation{heapType, 0}, PossibleContents::fromType(segType)); + return; } void visitArrayNewFixed(ArrayNewFixed* curr) { if (curr->type == Type::unreachable) { @@ -1012,7 +1010,7 @@ struct InfoCollector auto* set = builder.makeArraySet(curr->ref, curr->index, curr->value); visitArraySet(set); } - void visitArrayInit(ArrayInit* curr) { + template<typename ArrayInit> void visitArrayInit(ArrayInit* curr) { // Check for both unreachability and a bottom type. In either case we have // no work to do, and would error on an assertion below in finding the array // type. @@ -1033,6 +1031,8 @@ struct InfoCollector auto* set = builder.makeArraySet(curr->ref, curr->index, get); visitArraySet(set); } + void visitArrayInitData(ArrayInitData* curr) { visitArrayInit(curr); } + void visitArrayInitElem(ArrayInitElem* curr) { visitArrayInit(curr); } void visitStringNew(StringNew* curr) { if (curr->type == Type::unreachable) { return; diff --git a/src/passes/MemoryPacking.cpp b/src/passes/MemoryPacking.cpp index b2798f4b6..08d1407f4 100644 --- a/src/passes/MemoryPacking.cpp +++ b/src/passes/MemoryPacking.cpp @@ -278,7 +278,7 @@ bool MemoryPacking::canSplit(const std::unique_ptr<DataSegment>& segment, return false; } } - } else if (referrer->is<ArrayNewSeg>() || referrer->is<ArrayInit>()) { + } else if (referrer->is<ArrayNewData>() || referrer->is<ArrayInitData>()) { // TODO: Split segments referenced by GC instructions. return false; } @@ -474,15 +474,11 @@ void MemoryPacking::getSegmentReferrers(Module* module, void visitDataDrop(DataDrop* curr) { referrers[curr->segment].push_back(curr); } - void visitArrayNewSeg(ArrayNewSeg* curr) { - if (curr->op == NewData) { - referrers[curr->segment].push_back(curr); - } + void visitArrayNewData(ArrayNewData* curr) { + referrers[curr->segment].push_back(curr); } - void visitArrayInit(ArrayInit* curr) { - if (curr->op == InitData) { - referrers[curr->segment].push_back(curr); - } + void visitArrayInitData(ArrayInitData* curr) { + referrers[curr->segment].push_back(curr); } } collector(referrers); collector.walkFunctionInModule(func, module); @@ -808,12 +804,10 @@ void MemoryPacking::replaceSegmentOps(Module* module, } } - void visitArrayNewSeg(ArrayNewSeg* curr) { - if (curr->op == NewData) { - if (auto replacement = replacements.find(curr); - replacement != replacements.end()) { - replaceCurrent(replacement->second(getFunction())); - } + void visitArrayNewData(ArrayNewData* curr) { + if (auto replacement = replacements.find(curr); + replacement != replacements.end()) { + replaceCurrent(replacement->second(getFunction())); } } } replacer(replacements); diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 650a17203..76fd53759 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2265,21 +2265,20 @@ struct PrintExpressionContents o << ' '; TypeNamePrinter(o, wasm).print(curr->type.getHeapType()); } - void visitArrayNewSeg(ArrayNewSeg* curr) { + void visitArrayNewData(ArrayNewData* curr) { if (printUnreachableReplacement(curr)) { return; } - printMedium(o, "array.new_"); - switch (curr->op) { - case NewData: - printMedium(o, "data"); - break; - case NewElem: - printMedium(o, "elem"); - break; - default: - WASM_UNREACHABLE("unexpected op"); + printMedium(o, "array.new_data"); + o << ' '; + TypeNamePrinter(o, wasm).print(curr->type.getHeapType()); + o << " $" << curr->segment; + } + void visitArrayNewElem(ArrayNewElem* curr) { + if (printUnreachableReplacement(curr)) { + return; } + printMedium(o, "array.new_elem"); o << ' '; TypeNamePrinter(o, wasm).print(curr->type.getHeapType()); o << " $" << curr->segment; @@ -2333,20 +2332,19 @@ struct PrintExpressionContents printMedium(o, "array.fill "); TypeNamePrinter(o, wasm).print(curr->ref->type.getHeapType()); } - void visitArrayInit(ArrayInit* curr) { + void visitArrayInitData(ArrayInitData* curr) { if (printUnreachableOrNullReplacement(curr->ref)) { return; } - switch (curr->op) { - case InitData: - printMedium(o, "array.init_data "); - break; - case InitElem: - printMedium(o, "array.init_elem "); - break; - default: - WASM_UNREACHABLE("unexpected op"); + printMedium(o, "array.init_data "); + TypeNamePrinter(o, wasm).print(curr->ref->type.getHeapType()); + o << " $" << curr->segment; + } + void visitArrayInitElem(ArrayInitElem* curr) { + if (printUnreachableOrNullReplacement(curr->ref)) { + return; } + printMedium(o, "array.init_elem "); TypeNamePrinter(o, wasm).print(curr->ref->type.getHeapType()); o << " $" << curr->segment; } @@ -2915,7 +2913,10 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> { void visitArrayNew(ArrayNew* curr) { maybePrintUnreachableReplacement(curr, curr->type); } - void visitArrayNewSeg(ArrayNewSeg* curr) { + void visitArrayNewData(ArrayNewData* curr) { + maybePrintUnreachableReplacement(curr, curr->type); + } + void visitArrayNewElem(ArrayNewElem* curr) { maybePrintUnreachableReplacement(curr, curr->type); } void visitArrayNewFixed(ArrayNewFixed* curr) { diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp index 6842c852e..725e292b2 100644 --- a/src/passes/RemoveUnusedModuleElements.cpp +++ b/src/passes/RemoveUnusedModuleElements.cpp @@ -203,28 +203,17 @@ struct ReferenceFinder : public PostWalker<ReferenceFinder> { auto type = curr->ref->type.getHeapType(); note(StructField{type, curr->index}); } - void visitArrayNewSeg(ArrayNewSeg* curr) { - switch (curr->op) { - case NewData: { - note({ModuleElementKind::DataSegment, curr->segment}); - return; - case NewElem: - note({ModuleElementKind::ElementSegment, curr->segment}); - return; - } - } - WASM_UNREACHABLE("unexpected op"); - } - void visitArrayInit(ArrayInit* curr) { - switch (curr->op) { - case InitData: - note({ModuleElementKind::DataSegment, curr->segment}); - return; - case InitElem: - note({ModuleElementKind::ElementSegment, curr->segment}); - return; - } - WASM_UNREACHABLE("unexpected op"); + void visitArrayNewData(ArrayNewData* curr) { + note({ModuleElementKind::DataSegment, curr->segment}); + } + void visitArrayNewElem(ArrayNewElem* curr) { + note({ModuleElementKind::ElementSegment, curr->segment}); + } + void visitArrayInitData(ArrayInitData* curr) { + note({ModuleElementKind::DataSegment, curr->segment}); + } + void visitArrayInitElem(ArrayInitElem* curr) { + note({ModuleElementKind::ElementSegment, curr->segment}); } }; diff --git a/src/passes/TypeSSA.cpp b/src/passes/TypeSSA.cpp index 9e3a57815..666eda942 100644 --- a/src/passes/TypeSSA.cpp +++ b/src/passes/TypeSSA.cpp @@ -67,7 +67,8 @@ struct NewFinder : public PostWalker<NewFinder> { void visitStructNew(StructNew* curr) { news.push_back(curr); } void visitArrayNew(ArrayNew* curr) { news.push_back(curr); } - void visitArrayNewSeg(ArrayNewSeg* curr) { news.push_back(curr); } + void visitArrayNewData(ArrayNewData* curr) { news.push_back(curr); } + void visitArrayNewElem(ArrayNewElem* curr) { news.push_back(curr); } void visitArrayNewFixed(ArrayNewFixed* curr) { news.push_back(curr); } }; @@ -286,8 +287,8 @@ struct TypeSSA : public Pass { if (isInterestingRelevantTo(arrayNew->init, element.type)) { return true; } - } else if (curr->is<ArrayNewSeg>()) { - // TODO: If the element segment is immutable perhaps we could inspect it. + } else if (curr->is<ArrayNewData>() || curr->is<ArrayNewElem>()) { + // TODO: If the segment is immutable perhaps we could inspect it. return true; } else if (auto* arrayInit = curr->dynCast<ArrayNewFixed>()) { // All the items must be interesting for us to consider this interesting, diff --git a/src/wasm-binary.h b/src/wasm-binary.h index e010135ee..395044c4d 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1727,8 +1727,8 @@ public: bool maybeVisitStructNew(Expression*& out, uint32_t code); bool maybeVisitStructGet(Expression*& out, uint32_t code); bool maybeVisitStructSet(Expression*& out, uint32_t code); - bool maybeVisitArrayNew(Expression*& out, uint32_t code); - bool maybeVisitArrayNewSeg(Expression*& out, uint32_t code); + bool maybeVisitArrayNewData(Expression*& out, uint32_t code); + bool maybeVisitArrayNewElem(Expression*& out, uint32_t code); bool maybeVisitArrayNewFixed(Expression*& out, uint32_t code); bool maybeVisitArrayGet(Expression*& out, uint32_t code); bool maybeVisitArraySet(Expression*& out, uint32_t code); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 020badf16..e870d6b63 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -928,13 +928,23 @@ public: ret->finalize(); return ret; } - ArrayNewSeg* makeArrayNewSeg(ArrayNewSegOp op, - HeapType type, - Name seg, - Expression* offset, - Expression* size) { - auto* ret = wasm.allocator.alloc<ArrayNewSeg>(); - ret->op = op; + ArrayNewData* makeArrayNewData(HeapType type, + Name seg, + Expression* offset, + Expression* size) { + auto* ret = wasm.allocator.alloc<ArrayNewData>(); + ret->segment = seg; + ret->offset = offset; + ret->size = size; + ret->type = Type(type, NonNullable); + ret->finalize(); + return ret; + } + ArrayNewElem* makeArrayNewElem(HeapType type, + Name seg, + Expression* offset, + Expression* size) { + auto* ret = wasm.allocator.alloc<ArrayNewElem>(); ret->segment = seg; ret->offset = offset; ret->size = size; @@ -1003,14 +1013,26 @@ public: ret->finalize(); return ret; } - ArrayInit* makeArrayInit(ArrayInitOp op, - Name seg, - Expression* ref, - Expression* index, - Expression* offset, - Expression* size) { - auto* ret = wasm.allocator.alloc<ArrayInit>(); - ret->op = op; + ArrayInitData* makeArrayInitData(Name seg, + Expression* ref, + Expression* index, + Expression* offset, + Expression* size) { + auto* ret = wasm.allocator.alloc<ArrayInitData>(); + ret->segment = seg; + ret->ref = ref; + ret->index = index; + ret->offset = offset; + ret->size = size; + ret->finalize(); + return ret; + } + ArrayInitElem* makeArrayInitElem(Name seg, + Expression* ref, + Expression* index, + Expression* offset, + Expression* size) { + auto* ret = wasm.allocator.alloc<ArrayInitElem>(); ret->segment = seg; ret->ref = ref; ret->index = index; diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index a4de0b2ad..4398ee5e3 100644 --- a/src/wasm-delegations-fields.def +++ b/src/wasm-delegations-fields.def @@ -663,13 +663,20 @@ switch (DELEGATE_ID) { DELEGATE_END(ArrayNew); break; } - case Expression::Id::ArrayNewSegId: { - DELEGATE_START(ArrayNewSeg); - DELEGATE_FIELD_INT(ArrayNewSeg, op); - DELEGATE_FIELD_NAME(ArrayNewSeg, segment); - DELEGATE_FIELD_CHILD(ArrayNewSeg, size); - DELEGATE_FIELD_CHILD(ArrayNewSeg, offset); - DELEGATE_END(ArrayNewSeg); + case Expression::Id::ArrayNewDataId: { + DELEGATE_START(ArrayNewData); + DELEGATE_FIELD_NAME(ArrayNewData, segment); + DELEGATE_FIELD_CHILD(ArrayNewData, size); + DELEGATE_FIELD_CHILD(ArrayNewData, offset); + DELEGATE_END(ArrayNewData); + break; + } + case Expression::Id::ArrayNewElemId: { + DELEGATE_START(ArrayNewElem); + DELEGATE_FIELD_NAME(ArrayNewElem, segment); + DELEGATE_FIELD_CHILD(ArrayNewElem, size); + DELEGATE_FIELD_CHILD(ArrayNewElem, offset); + DELEGATE_END(ArrayNewElem); break; } case Expression::Id::ArrayNewFixedId: { @@ -719,15 +726,24 @@ switch (DELEGATE_ID) { DELEGATE_END(ArrayFill); break; } - case Expression::Id::ArrayInitId: { - DELEGATE_START(ArrayInit); - DELEGATE_FIELD_INT(ArrayInit, op); - DELEGATE_FIELD_NAME(ArrayInit, segment); - DELEGATE_FIELD_CHILD(ArrayInit, size); - DELEGATE_FIELD_CHILD(ArrayInit, offset); - DELEGATE_FIELD_CHILD(ArrayInit, index); - DELEGATE_FIELD_CHILD(ArrayInit, ref); - DELEGATE_END(ArrayInit); + case Expression::Id::ArrayInitDataId: { + DELEGATE_START(ArrayInitData); + DELEGATE_FIELD_NAME(ArrayInitData, segment); + DELEGATE_FIELD_CHILD(ArrayInitData, size); + DELEGATE_FIELD_CHILD(ArrayInitData, offset); + DELEGATE_FIELD_CHILD(ArrayInitData, index); + DELEGATE_FIELD_CHILD(ArrayInitData, ref); + DELEGATE_END(ArrayInitData); + break; + } + case Expression::Id::ArrayInitElemId: { + DELEGATE_START(ArrayInitElem); + DELEGATE_FIELD_NAME(ArrayInitElem, segment); + DELEGATE_FIELD_CHILD(ArrayInitElem, size); + DELEGATE_FIELD_CHILD(ArrayInitElem, offset); + DELEGATE_FIELD_CHILD(ArrayInitElem, index); + DELEGATE_FIELD_CHILD(ArrayInitElem, ref); + DELEGATE_END(ArrayInitElem); break; } case Expression::Id::RefAsId: { diff --git a/src/wasm-delegations.def b/src/wasm-delegations.def index 0a6471f89..eecd981cd 100644 --- a/src/wasm-delegations.def +++ b/src/wasm-delegations.def @@ -77,14 +77,16 @@ DELEGATE(StructNew); DELEGATE(StructGet); DELEGATE(StructSet); DELEGATE(ArrayNew); -DELEGATE(ArrayNewSeg); +DELEGATE(ArrayNewData); +DELEGATE(ArrayNewElem); DELEGATE(ArrayNewFixed); DELEGATE(ArrayGet); DELEGATE(ArraySet); DELEGATE(ArrayLen); DELEGATE(ArrayCopy); DELEGATE(ArrayFill); -DELEGATE(ArrayInit); +DELEGATE(ArrayInitData); +DELEGATE(ArrayInitElem); DELEGATE(RefAs); DELEGATE(StringNew); DELEGATE(StringConst); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index a7d350abe..955671dcc 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1654,7 +1654,8 @@ public: } return makeGCData(data, curr->type); } - Flow visitArrayNewSeg(ArrayNewSeg* curr) { WASM_UNREACHABLE("unimp"); } + Flow visitArrayNewData(ArrayNewData* curr) { WASM_UNREACHABLE("unimp"); } + Flow visitArrayNewElem(ArrayNewElem* curr) { WASM_UNREACHABLE("unimp"); } Flow visitArrayNewFixed(ArrayNewFixed* curr) { NOTE_ENTER("ArrayNewFixed"); Index num = curr->values.size(); @@ -1831,7 +1832,8 @@ public: } return {}; } - Flow visitArrayInit(MemoryFill* curr) { WASM_UNREACHABLE("unimp"); } + Flow visitArrayInitData(ArrayInitData* curr) { WASM_UNREACHABLE("unimp"); } + Flow visitArrayInitElem(ArrayInitElem* curr) { WASM_UNREACHABLE("unimp"); } Flow visitRefAs(RefAs* curr) { NOTE_ENTER("RefAs"); Flow flow = visit(curr->value); @@ -2266,8 +2268,12 @@ public: NOTE_ENTER("SIMDLoadStoreLane"); return Flow(NONCONSTANT_FLOW); } - Flow visitArrayNewSeg(ArrayNewSeg* curr) { - NOTE_ENTER("ArrayNewSeg"); + Flow visitArrayNewData(ArrayNewData* curr) { + NOTE_ENTER("ArrayNewData"); + return Flow(NONCONSTANT_FLOW); + } + Flow visitArrayNewElem(ArrayNewElem* curr) { + NOTE_ENTER("ArrayNewElem"); return Flow(NONCONSTANT_FLOW); } Flow visitArrayCopy(ArrayCopy* curr) { @@ -2278,8 +2284,12 @@ public: NOTE_ENTER("ArrayFill"); return Flow(NONCONSTANT_FLOW); } - Flow visitArrayInit(ArrayInit* curr) { - NOTE_ENTER("ArrayInit"); + Flow visitArrayInitData(ArrayInitData* curr) { + NOTE_ENTER("ArrayInitData"); + return Flow(NONCONSTANT_FLOW); + } + Flow visitArrayInitElem(ArrayInitElem* curr) { + NOTE_ENTER("ArrayInitElem"); return Flow(NONCONSTANT_FLOW); } Flow visitPop(Pop* curr) { @@ -3586,8 +3596,8 @@ public: } return {}; } - Flow visitArrayNewSeg(ArrayNewSeg* curr) { - NOTE_ENTER("ArrayNewSeg"); + Flow visitArrayNewData(ArrayNewData* curr) { + NOTE_ENTER("ArrayNewData"); auto offsetFlow = self()->visit(curr->offset); if (offsetFlow.breaking()) { return offsetFlow; @@ -3602,47 +3612,52 @@ public: auto heapType = curr->type.getHeapType(); const auto& element = heapType.getArray().element; - [[maybe_unused]] auto elemType = heapType.getArray().element.type; + Literals contents; + + const auto& seg = *wasm.getDataSegment(curr->segment); + auto elemBytes = element.getByteSize(); + auto end = offset + size * elemBytes; + if ((size != 0ull && droppedSegments.count(curr->segment)) || + end > seg.data.size()) { + trap("out of bounds segment access in array.new_data"); + } + contents.reserve(size); + for (Index i = offset; i < end; i += elemBytes) { + auto addr = (void*)&seg.data[i]; + contents.push_back(Literal::makeFromMemory(addr, element)); + } + return self()->makeGCData(contents, curr->type); + } + Flow visitArrayNewElem(ArrayNewElem* curr) { + NOTE_ENTER("ArrayNewElem"); + auto offsetFlow = self()->visit(curr->offset); + if (offsetFlow.breaking()) { + return offsetFlow; + } + auto sizeFlow = self()->visit(curr->size); + if (sizeFlow.breaking()) { + return sizeFlow; + } + + uint64_t offset = offsetFlow.getSingleValue().getUnsigned(); + uint64_t size = sizeFlow.getSingleValue().getUnsigned(); Literals contents; - switch (curr->op) { - case NewData: { - assert(elemType.isNumber()); - const auto& seg = *wasm.getDataSegment(curr->segment); - auto elemBytes = element.getByteSize(); - auto end = offset + size * elemBytes; - if ((size != 0ull && droppedSegments.count(curr->segment)) || - end > seg.data.size()) { - trap("out of bounds segment access in array.new_data"); - } - contents.reserve(size); - for (Index i = offset; i < end; i += elemBytes) { - auto addr = (void*)&seg.data[i]; - contents.push_back(Literal::makeFromMemory(addr, element)); - } - break; - } - case NewElem: { - const auto& seg = *wasm.getElementSegment(curr->segment); - auto end = offset + size; - // TODO: Handle dropped element segments once we support those. - if (end > seg.data.size()) { - trap("out of bounds segment access in array.new_elem"); - } - contents.reserve(size); - for (Index i = offset; i < end; ++i) { - auto val = self()->visit(seg.data[i]).getSingleValue(); - contents.push_back(val); - } - break; - } - default: - WASM_UNREACHABLE("unexpected op"); + const auto& seg = *wasm.getElementSegment(curr->segment); + auto end = offset + size; + // TODO: Handle dropped element segments once we support those. + if (end > seg.data.size()) { + trap("out of bounds segment access in array.new_elem"); + } + contents.reserve(size); + for (Index i = offset; i < end; ++i) { + auto val = self()->visit(seg.data[i]).getSingleValue(); + contents.push_back(val); } return self()->makeGCData(contents, curr->type); } - Flow visitArrayInit(ArrayInit* curr) { + Flow visitArrayInitData(ArrayInitData* curr) { NOTE_ENTER("ArrayInit"); Flow ref = self()->visit(curr->ref); if (ref.breaking()) { @@ -3675,43 +3690,69 @@ public: Module& wasm = *self()->getModule(); - switch (curr->op) { - case InitData: { - auto* seg = wasm.getDataSegment(curr->segment); - auto elem = curr->ref->type.getHeapType().getArray().element; - size_t elemSize = elem.getByteSize(); - uint64_t readSize = (uint64_t)sizeVal * elemSize; - if (offsetVal + readSize > seg->data.size()) { - trap("out of bounds segment access in array.init_data"); - } - if (offsetVal + sizeVal > 0 && droppedSegments.count(curr->segment)) { - trap("out of bounds segment access in array.init_data"); - } - for (size_t i = 0; i < sizeVal; i++) { - void* addr = (void*)&seg->data[offsetVal + i * elemSize]; - data->values[indexVal + i] = Literal::makeFromMemory(addr, elem); - } - return {}; - } - case InitElem: { - auto* seg = wasm.getElementSegment(curr->segment); - if ((uint64_t)offsetVal + sizeVal > seg->data.size()) { - trap("out of bounds segment access in array.init"); - } - // TODO: Check whether the segment has been dropped once we support - // dropping element segments. - for (size_t i = 0; i < sizeVal; i++) { - // TODO: This is not correct because it does not preserve the identity - // of references in the table! ArrayNewSeg suffers the same problem. - // Fixing it will require changing how we represent segments, at least - // in the interpreter. - data->values[indexVal + i] = - self()->visit(seg->data[i]).getSingleValue(); - } - return {}; - } - }; - WASM_UNREACHABLE("unexpected op"); + auto* seg = wasm.getDataSegment(curr->segment); + auto elem = curr->ref->type.getHeapType().getArray().element; + size_t elemSize = elem.getByteSize(); + uint64_t readSize = (uint64_t)sizeVal * elemSize; + if (offsetVal + readSize > seg->data.size()) { + trap("out of bounds segment access in array.init_data"); + } + if (offsetVal + sizeVal > 0 && droppedSegments.count(curr->segment)) { + trap("out of bounds segment access in array.init_data"); + } + for (size_t i = 0; i < sizeVal; i++) { + void* addr = (void*)&seg->data[offsetVal + i * elemSize]; + data->values[indexVal + i] = Literal::makeFromMemory(addr, elem); + } + return {}; + } + Flow visitArrayInitElem(ArrayInitElem* curr) { + NOTE_ENTER("ArrayInit"); + Flow ref = self()->visit(curr->ref); + if (ref.breaking()) { + return ref; + } + Flow index = self()->visit(curr->index); + if (index.breaking()) { + return index; + } + Flow offset = self()->visit(curr->offset); + if (offset.breaking()) { + return offset; + } + Flow size = self()->visit(curr->size); + if (size.breaking()) { + return size; + } + auto data = ref.getSingleValue().getGCData(); + if (!data) { + trap("null ref"); + } + size_t indexVal = index.getSingleValue().getUnsigned(); + size_t offsetVal = offset.getSingleValue().getUnsigned(); + size_t sizeVal = size.getSingleValue().getUnsigned(); + + size_t arraySize = data->values.size(); + if ((uint64_t)indexVal + sizeVal > arraySize) { + trap("out of bounds array access in array.init"); + } + + Module& wasm = *self()->getModule(); + + auto* seg = wasm.getElementSegment(curr->segment); + if ((uint64_t)offsetVal + sizeVal > seg->data.size()) { + trap("out of bounds segment access in array.init"); + } + // TODO: Check whether the segment has been dropped once we support + // dropping element segments. + for (size_t i = 0; i < sizeVal; i++) { + // TODO: This is not correct because it does not preserve the identity + // of references in the table! ArrayNew suffers the same problem. + // Fixing it will require changing how we represent segments, at least + // in the interpreter. + data->values[indexVal + i] = self()->visit(seg->data[i]).getSingleValue(); + } + return {}; } Flow visitTry(Try* curr) { NOTE_ENTER("Try"); diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index c5598ef1e..f61a5000a 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -300,14 +300,16 @@ private: Expression* makeStructGet(Element& s, bool signed_ = false); Expression* makeStructSet(Element& s); Expression* makeArrayNew(Element& s, bool default_); - Expression* makeArrayNewSeg(Element& s, ArrayNewSegOp op); + Expression* makeArrayNewData(Element& s); + Expression* makeArrayNewElem(Element& s); Expression* makeArrayNewFixed(Element& s); Expression* makeArrayGet(Element& s, bool signed_ = false); Expression* makeArraySet(Element& s); Expression* makeArrayLen(Element& s); Expression* makeArrayCopy(Element& s); Expression* makeArrayFill(Element& s); - Expression* makeArrayInit(Element& s, ArrayInitOp op); + Expression* makeArrayInitData(Element& s); + Expression* makeArrayInitElem(Element& s); Expression* makeRefAs(Element& s, RefAsOp op); Expression* makeRefAsNonNull(Element& s); Expression* makeStringNew(Element& s, StringNewOp op, bool try_); diff --git a/src/wasm.h b/src/wasm.h index 07a2f6bf9..825f35099 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -563,17 +563,6 @@ enum RefAsOp { ExternExternalize, }; -enum ArrayNewSegOp { - NewData, - NewElem, -}; - -// TODO: Deduplicate with ArrayNewSegOp? -enum ArrayInitOp { - InitData, - InitElem, -}; - enum BrOnOp { BrOnNull, BrOnNonNull, @@ -722,14 +711,16 @@ public: StructGetId, StructSetId, ArrayNewId, - ArrayNewSegId, + ArrayNewDataId, + ArrayNewElemId, ArrayNewFixedId, ArrayGetId, ArraySetId, ArrayLenId, ArrayCopyId, ArrayFillId, - ArrayInitId, + ArrayInitDataId, + ArrayInitElemId, RefAsId, StringNewId, StringConstId, @@ -1611,11 +1602,21 @@ public: void finalize(); }; -class ArrayNewSeg : public SpecificExpression<Expression::ArrayNewSegId> { +class ArrayNewData : public SpecificExpression<Expression::ArrayNewDataId> { +public: + ArrayNewData(MixedArena& allocator) {} + + Name segment; + Expression* offset; + Expression* size; + + void finalize(); +}; + +class ArrayNewElem : public SpecificExpression<Expression::ArrayNewElemId> { public: - ArrayNewSeg(MixedArena& allocator) {} + ArrayNewElem(MixedArena& allocator) {} - ArrayNewSegOp op; Name segment; Expression* offset; Expression* size; @@ -1689,11 +1690,23 @@ public: void finalize(); }; -class ArrayInit : public SpecificExpression<Expression::ArrayInitId> { +class ArrayInitData : public SpecificExpression<Expression::ArrayInitDataId> { +public: + ArrayInitData(MixedArena& allocator) {} + + Name segment; + Expression* ref; + Expression* index; + Expression* offset; + Expression* size; + + void finalize(); +}; + +class ArrayInitElem : public SpecificExpression<Expression::ArrayInitElemId> { public: - ArrayInit(MixedArena& allocator) {} + ArrayInitElem(MixedArena& allocator) {} - ArrayInitOp op; Name segment; Expression* ref; Expression* index; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 3975dd390..981932470 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -4053,10 +4053,10 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { if (maybeVisitStructSet(curr, opcode)) { break; } - if (maybeVisitArrayNew(curr, opcode)) { + if (maybeVisitArrayNewData(curr, opcode)) { break; } - if (maybeVisitArrayNewSeg(curr, opcode)) { + if (maybeVisitArrayNewElem(curr, opcode)) { break; } if (maybeVisitArrayNewFixed(curr, opcode)) { @@ -7139,7 +7139,8 @@ bool WasmBinaryBuilder::maybeVisitStructSet(Expression*& out, uint32_t code) { return true; } -bool WasmBinaryBuilder::maybeVisitArrayNew(Expression*& out, uint32_t code) { +bool WasmBinaryBuilder::maybeVisitArrayNewData(Expression*& out, + uint32_t code) { if (code == BinaryConsts::ArrayNew || code == BinaryConsts::ArrayNewDefault) { auto heapType = getIndexedHeapType(); auto* size = popNonVoidExpression(); @@ -7153,22 +7154,26 @@ bool WasmBinaryBuilder::maybeVisitArrayNew(Expression*& out, uint32_t code) { return false; } -bool WasmBinaryBuilder::maybeVisitArrayNewSeg(Expression*& out, uint32_t code) { +bool WasmBinaryBuilder::maybeVisitArrayNewElem(Expression*& out, + uint32_t code) { if (code == BinaryConsts::ArrayNewData || code == BinaryConsts::ArrayNewElem) { - auto op = code == BinaryConsts::ArrayNewData ? NewData : NewElem; + auto isData = code == BinaryConsts::ArrayNewData; auto heapType = getIndexedHeapType(); auto segIdx = getU32LEB(); auto* size = popNonVoidExpression(); auto* offset = popNonVoidExpression(); - auto* built = - Builder(wasm).makeArrayNewSeg(op, heapType, Name(), offset, size); - if (op == NewData) { - dataRefs[segIdx].push_back(&built->segment); + if (isData) { + auto* curr = + Builder(wasm).makeArrayNewData(heapType, Name(), offset, size); + dataRefs[segIdx].push_back(&curr->segment); + out = curr; } else { - elemRefs[segIdx].push_back(&built->segment); + auto* curr = + Builder(wasm).makeArrayNewElem(heapType, Name(), offset, size); + elemRefs[segIdx].push_back(&curr->segment); + out = curr; } - out = built; return true; } return false; @@ -7271,13 +7276,12 @@ bool WasmBinaryBuilder::maybeVisitArrayFill(Expression*& out, uint32_t code) { } bool WasmBinaryBuilder::maybeVisitArrayInit(Expression*& out, uint32_t code) { - ArrayInitOp op; + bool isData = true; switch (code) { case BinaryConsts::ArrayInitData: - op = InitData; break; case BinaryConsts::ArrayInitElem: - op = InitElem; + isData = false; break; default: return false; @@ -7289,14 +7293,17 @@ bool WasmBinaryBuilder::maybeVisitArrayInit(Expression*& out, uint32_t code) { auto* index = popNonVoidExpression(); auto* ref = popNonVoidExpression(); validateHeapTypeUsingChild(ref, heapType); - auto* built = - Builder(wasm).makeArrayInit(op, Name(), ref, index, offset, size); - if (op == InitData) { - dataRefs[segIdx].push_back(&built->segment); + if (isData) { + auto* curr = + Builder(wasm).makeArrayInitData(Name(), ref, index, offset, size); + dataRefs[segIdx].push_back(&curr->segment); + out = curr; } else { - elemRefs[segIdx].push_back(&built->segment); + auto* curr = + Builder(wasm).makeArrayInitElem(Name(), ref, index, offset, size); + elemRefs[segIdx].push_back(&curr->segment); + out = curr; } - out = built; return true; } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 968c8bd45..44008bb75 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -2974,14 +2974,20 @@ Expression* SExpressionWasmBuilder::makeArrayNew(Element& s, bool default_) { return Builder(wasm).makeArrayNew(heapType, size, init); } -Expression* SExpressionWasmBuilder::makeArrayNewSeg(Element& s, - ArrayNewSegOp op) { +Expression* SExpressionWasmBuilder::makeArrayNewData(Element& s) { auto heapType = parseHeapType(*s[1]); - Name seg = - op == NewData ? getDataSegmentName(*s[2]) : getElemSegmentName(*s[2]); + Name seg = getDataSegmentName(*s[2]); Expression* offset = parseExpression(*s[3]); Expression* size = parseExpression(*s[4]); - return Builder(wasm).makeArrayNewSeg(op, heapType, seg, offset, size); + return Builder(wasm).makeArrayNewData(heapType, seg, offset, size); +} + +Expression* SExpressionWasmBuilder::makeArrayNewElem(Element& s) { + auto heapType = parseHeapType(*s[1]); + Name seg = getElemSegmentName(*s[2]); + Expression* offset = parseExpression(*s[3]); + Expression* size = parseExpression(*s[4]); + return Builder(wasm).makeArrayNewElem(heapType, seg, offset, size); } Expression* SExpressionWasmBuilder::makeArrayNewFixed(Element& s) { @@ -3051,16 +3057,26 @@ Expression* SExpressionWasmBuilder::makeArrayFill(Element& s) { return Builder(wasm).makeArrayFill(ref, index, value, size); } -Expression* SExpressionWasmBuilder::makeArrayInit(Element& s, ArrayInitOp op) { +Expression* SExpressionWasmBuilder::makeArrayInitData(Element& s) { + auto heapType = parseHeapType(*s[1]); + auto seg = getDataSegmentName(*s[2]); + auto ref = parseExpression(*s[3]); + validateHeapTypeUsingChild(ref, heapType, s); + auto index = parseExpression(*s[4]); + auto offset = parseExpression(*s[5]); + auto size = parseExpression(*s[6]); + return Builder(wasm).makeArrayInitData(seg, ref, index, offset, size); +} + +Expression* SExpressionWasmBuilder::makeArrayInitElem(Element& s) { auto heapType = parseHeapType(*s[1]); - auto seg = - op == InitData ? getDataSegmentName(*s[2]) : getElemSegmentName(*s[2]); + auto seg = getElemSegmentName(*s[2]); auto ref = parseExpression(*s[3]); validateHeapTypeUsingChild(ref, heapType, s); auto index = parseExpression(*s[4]); auto offset = parseExpression(*s[5]); auto size = parseExpression(*s[6]); - return Builder(wasm).makeArrayInit(op, seg, ref, index, offset, size); + return Builder(wasm).makeArrayInitElem(seg, ref, index, offset, size); } Expression* SExpressionWasmBuilder::makeRefAs(Element& s, RefAsOp op) { diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 286b049aa..14c24d807 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2118,22 +2118,18 @@ void BinaryInstWriter::visitArrayNew(ArrayNew* curr) { parent.writeIndexedHeapType(curr->type.getHeapType()); } -void BinaryInstWriter::visitArrayNewSeg(ArrayNewSeg* curr) { +void BinaryInstWriter::visitArrayNewData(ArrayNewData* curr) { o << int8_t(BinaryConsts::GCPrefix); - switch (curr->op) { - case NewData: - o << U32LEB(BinaryConsts::ArrayNewData); - parent.writeIndexedHeapType(curr->type.getHeapType()); - o << U32LEB(parent.getDataSegmentIndex(curr->segment)); - break; - case NewElem: - o << U32LEB(BinaryConsts::ArrayNewElem); - parent.writeIndexedHeapType(curr->type.getHeapType()); - o << U32LEB(parent.getElementSegmentIndex(curr->segment)); - break; - default: - WASM_UNREACHABLE("unexpected op"); - } + o << U32LEB(BinaryConsts::ArrayNewData); + parent.writeIndexedHeapType(curr->type.getHeapType()); + o << U32LEB(parent.getDataSegmentIndex(curr->segment)); +} + +void BinaryInstWriter::visitArrayNewElem(ArrayNewElem* curr) { + o << int8_t(BinaryConsts::GCPrefix); + o << U32LEB(BinaryConsts::ArrayNewElem); + parent.writeIndexedHeapType(curr->type.getHeapType()); + o << U32LEB(parent.getElementSegmentIndex(curr->segment)); } void BinaryInstWriter::visitArrayNewFixed(ArrayNewFixed* curr) { @@ -2194,26 +2190,26 @@ void BinaryInstWriter::visitArrayFill(ArrayFill* curr) { parent.writeIndexedHeapType(curr->ref->type.getHeapType()); } -void BinaryInstWriter::visitArrayInit(ArrayInit* curr) { +void BinaryInstWriter::visitArrayInitData(ArrayInitData* curr) { if (curr->ref->type.isNull()) { emitUnreachable(); return; } o << int8_t(BinaryConsts::GCPrefix); - switch (curr->op) { - case InitData: - o << U32LEB(BinaryConsts::ArrayInitData); - parent.writeIndexedHeapType(curr->ref->type.getHeapType()); - o << U32LEB(parent.getDataSegmentIndex(curr->segment)); - break; - case InitElem: - o << U32LEB(BinaryConsts::ArrayInitElem); - parent.writeIndexedHeapType(curr->ref->type.getHeapType()); - o << U32LEB(parent.getElementSegmentIndex(curr->segment)); - break; - default: - WASM_UNREACHABLE("unexpected op"); + o << U32LEB(BinaryConsts::ArrayInitData); + parent.writeIndexedHeapType(curr->ref->type.getHeapType()); + o << U32LEB(parent.getDataSegmentIndex(curr->segment)); +} + +void BinaryInstWriter::visitArrayInitElem(ArrayInitElem* curr) { + if (curr->ref->type.isNull()) { + emitUnreachable(); + return; } + o << int8_t(BinaryConsts::GCPrefix); + o << U32LEB(BinaryConsts::ArrayInitElem); + parent.writeIndexedHeapType(curr->ref->type.getHeapType()); + o << U32LEB(parent.getElementSegmentIndex(curr->segment)); } void BinaryInstWriter::visitRefAs(RefAs* curr) { diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 845f0f6b6..318657034 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -22,6 +22,7 @@ #include "ir/eh-utils.h" #include "ir/features.h" #include "ir/find_all.h" +#include "ir/gc-type-utils.h" #include "ir/global-utils.h" #include "ir/intrinsics.h" #include "ir/local-graph.h" @@ -456,14 +457,18 @@ public: void visitStructGet(StructGet* curr); void visitStructSet(StructSet* curr); void visitArrayNew(ArrayNew* curr); - void visitArrayNewSeg(ArrayNewSeg* curr); + template<typename ArrayNew> void visitArrayNew(ArrayNew* curr); + void visitArrayNewData(ArrayNewData* curr); + void visitArrayNewElem(ArrayNewElem* curr); void visitArrayNewFixed(ArrayNewFixed* curr); void visitArrayGet(ArrayGet* curr); void visitArraySet(ArraySet* curr); void visitArrayLen(ArrayLen* curr); void visitArrayCopy(ArrayCopy* curr); void visitArrayFill(ArrayFill* curr); - void visitArrayInit(ArrayInit* curr); + template<typename ArrayInit> void visitArrayInit(ArrayInit* curr); + void visitArrayInitData(ArrayInitData* curr); + void visitArrayInitElem(ArrayInitElem* curr); void visitFunction(Function* curr); // helpers @@ -2703,7 +2708,8 @@ void FunctionValidator::visitArrayNew(ArrayNew* curr) { } } -void FunctionValidator::visitArrayNewSeg(ArrayNewSeg* curr) { +template<typename ArrayNew> +void FunctionValidator::visitArrayNew(ArrayNew* curr) { shouldBeTrue(getModule()->features.hasGC(), curr, "array.new_{data, elem} requires gc [--enable-gc]"); @@ -2717,24 +2723,6 @@ void FunctionValidator::visitArrayNewSeg(ArrayNewSeg* curr) { Type(Type::i32), curr, "array.new_{data, elem} size must be an i32"); - switch (curr->op) { - case NewData: - if (!shouldBeTrue(getModule()->getDataSegment(curr->segment), - curr, - "array.new_data segment should exist")) { - return; - } - break; - case NewElem: - if (!shouldBeTrue(getModule()->getElementSegment(curr->segment), - curr, - "array.new_elem segment should exist")) { - return; - } - break; - default: - WASM_UNREACHABLE("unexpected op"); - } if (curr->type == Type::unreachable) { return; } @@ -2748,26 +2736,49 @@ void FunctionValidator::visitArrayNewSeg(ArrayNewSeg* curr) { if (!shouldBeTrue( heapType.isArray(), curr, - "array.new_{data, elem} type shoudl be an array reference")) { + "array.new_{data, elem} type should be an array reference")) { return; } - auto elemType = heapType.getArray().element.type; - switch (curr->op) { - case NewData: - shouldBeTrue(elemType.isNumber(), - curr, - "array.new_data result element type should be numeric"); - break; - case NewElem: - shouldBeSubType(getModule()->getElementSegment(curr->segment)->type, - elemType, - curr, - "array.new_elem segment type should be a subtype of the " - "result element type"); - break; - default: - WASM_UNREACHABLE("unexpected op"); +} + +void FunctionValidator::visitArrayNewData(ArrayNewData* curr) { + visitArrayNew(curr); + + if (!shouldBeTrue(getModule()->getDataSegment(curr->segment), + curr, + "array.new_data segment should exist")) { + return; } + + auto field = GCTypeUtils::getField(curr->type); + if (!field) { + // A bottom type, or unreachable. + return; + } + shouldBeTrue(field->type.isNumber(), + curr, + "array.new_data result element type should be numeric"); +} + +void FunctionValidator::visitArrayNewElem(ArrayNewElem* curr) { + visitArrayNew(curr); + + if (!shouldBeTrue(getModule()->getElementSegment(curr->segment), + curr, + "array.new_elem segment should exist")) { + return; + } + + auto field = GCTypeUtils::getField(curr->type); + if (!field) { + // A bottom type, or unreachable. + return; + } + shouldBeSubType(getModule()->getElementSegment(curr->segment)->type, + field->type, + curr, + "array.new_elem segment type should be a subtype of the " + "result element type"); } void FunctionValidator::visitArrayNewFixed(ArrayNewFixed* curr) { @@ -2956,6 +2967,7 @@ void FunctionValidator::visitArrayFill(ArrayFill* curr) { element.mutable_, curr, "array.fill destination must be mutable"); } +template<typename ArrayInit> void FunctionValidator::visitArrayInit(ArrayInit* curr) { shouldBeTrue(getModule()->features.hasGC(), curr, @@ -2991,24 +3003,43 @@ void FunctionValidator::visitArrayInit(ArrayInit* curr) { auto element = heapType.getArray().element; shouldBeTrue( element.mutable_, curr, "array.init_* destination must be mutable"); - if (curr->op == InitData) { - shouldBeTrue(getModule()->getDataSegmentOrNull(curr->segment), - curr, - "array.init_data segment must exist"); - shouldBeTrue(element.type.isNumber(), - curr, - "array.init_data destination must be numeric"); - } else { - assert(curr->op == InitElem); - auto* seg = getModule()->getElementSegmentOrNull(curr->segment); - if (!shouldBeTrue(seg, curr, "array.init_elem segment must exist")) { - return; - } - shouldBeSubType(seg->type, - element.type, - curr, - "array.init_elem segment type must match destination type"); +} + +void FunctionValidator::visitArrayInitData(ArrayInitData* curr) { + visitArrayInit(curr); + + shouldBeTrue(getModule()->getDataSegmentOrNull(curr->segment), + curr, + "array.init_data segment must exist"); + + auto field = GCTypeUtils::getField(curr->ref->type); + if (!field) { + // A bottom type, or unreachable. + return; } + shouldBeTrue(field->type.isNumber(), + curr, + "array.init_data destination must be numeric"); +} + +void FunctionValidator::visitArrayInitElem(ArrayInitElem* curr) { + visitArrayInit(curr); + + auto* seg = getModule()->getElementSegmentOrNull(curr->segment); + if (!shouldBeTrue(seg, curr, "array.init_elem segment must exist")) { + return; + } + + auto field = GCTypeUtils::getField(curr->ref->type); + if (!field) { + // A bottom type, or unreachable. + return; + } + + shouldBeSubType(seg->type, + field->type, + curr, + "array.init_elem segment type must match destination type"); } void FunctionValidator::visitFunction(Function* curr) { diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index f3e345895..c3f262998 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -1057,7 +1057,13 @@ void ArrayNew::finalize() { } } -void ArrayNewSeg::finalize() { +void ArrayNewData::finalize() { + if (offset->type == Type::unreachable || size->type == Type::unreachable) { + type = Type::unreachable; + } +} + +void ArrayNewElem::finalize() { if (offset->type == Type::unreachable || size->type == Type::unreachable) { type = Type::unreachable; } @@ -1118,7 +1124,16 @@ void ArrayFill::finalize() { } } -void ArrayInit::finalize() { +void ArrayInitData::finalize() { + if (ref->type == Type::unreachable || index->type == Type::unreachable || + offset->type == Type::unreachable || size->type == Type::unreachable) { + type = Type::unreachable; + } else { + type = Type::none; + } +} + +void ArrayInitElem::finalize() { if (ref->type == Type::unreachable || index->type == Type::unreachable || offset->type == Type::unreachable || size->type == Type::unreachable) { type = Type::unreachable; diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp index 51527b5e3..528d0d1af 100644 --- a/src/wasm/wat-parser.cpp +++ b/src/wasm/wat-parser.cpp @@ -789,6 +789,10 @@ struct NullInstrParserCtx { InstrT makeArrayNewData(Index, HeapTypeT, DataIdxT) { return Ok{}; } + template<typename HeapTypeT> + InstrT makeArrayNewElem(Index, HeapTypeT, DataIdxT) { + return Ok{}; + } template<typename HeapTypeT> InstrT makeArrayGet(Index, HeapTypeT, bool) { return Ok{}; } @@ -2156,8 +2160,18 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { CHECK_ERR(size); auto offset = pop(pos); CHECK_ERR(offset); - return push(pos, - builder.makeArrayNewSeg(NewData, type, data, *offset, *size)); + return push(pos, builder.makeArrayNewData(type, data, *offset, *size)); + } + + Result<> makeArrayNewElem(Index pos, HeapType type, Name data) { + if (!type.isArray()) { + return in.err(pos, "expected array type annotation"); + } + auto size = pop(pos); + CHECK_ERR(size); + auto offset = pop(pos); + CHECK_ERR(offset); + return push(pos, builder.makeArrayNewElem(type, data, *offset, *size)); } Result<> makeArrayGet(Index pos, HeapType type, bool signed_) { @@ -2380,7 +2394,9 @@ template<typename Ctx> Result<typename Ctx::InstrT> makeStructSet(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeArrayNew(Ctx&, Index, bool default_); template<typename Ctx> -Result<typename Ctx::InstrT> makeArrayNewSeg(Ctx&, Index, ArrayNewSegOp op); +Result<typename Ctx::InstrT> makeArrayNewData(Ctx&, Index); +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayNewElem(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeArrayNewFixed(Ctx&, Index); template<typename Ctx> @@ -2390,7 +2406,9 @@ template<typename Ctx> Result<typename Ctx::InstrT> makeArrayLen(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeArrayCopy(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeArrayFill(Ctx&, Index); template<typename Ctx> -Result<typename Ctx::InstrT> makeArrayInit(Ctx&, Index, ArrayInitOp); +Result<typename Ctx::InstrT> makeArrayInitData(Ctx&, Index); +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayInitElem(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeRefAs(Ctx&, Index, RefAsOp op); template<typename Ctx> @@ -3528,20 +3546,21 @@ Result<typename Ctx::InstrT> makeArrayNew(Ctx& ctx, Index pos, bool default_) { } template<typename Ctx> -Result<typename Ctx::InstrT> -makeArrayNewSeg(Ctx& ctx, Index pos, ArrayNewSegOp op) { +Result<typename Ctx::InstrT> makeArrayNewData(Ctx& ctx, Index pos) { auto type = typeidx(ctx); CHECK_ERR(type); - switch (op) { - case NewData: { - auto data = dataidx(ctx); - CHECK_ERR(data); - return ctx.makeArrayNewData(pos, *type, *data); - } - case NewElem: - return ctx.in.err("unimplemented instruction"); - } - WASM_UNREACHABLE("unexpected op"); + auto data = dataidx(ctx); + CHECK_ERR(data); + return ctx.makeArrayNewData(pos, *type, *data); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayNewElem(Ctx& ctx, Index pos) { + auto type = typeidx(ctx); + CHECK_ERR(type); + auto data = dataidx(ctx); + CHECK_ERR(data); + return ctx.makeArrayNewElem(pos, *type, *data); } template<typename Ctx> @@ -3585,8 +3604,12 @@ Result<typename Ctx::InstrT> makeArrayFill(Ctx& ctx, Index pos) { } template<typename Ctx> -Result<typename Ctx::InstrT> -makeArrayInit(Ctx& ctx, Index pos, ArrayInitOp op) { +Result<typename Ctx::InstrT> makeArrayInitData(Ctx& ctx, Index pos) { + return ctx.in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayInitElem(Ctx& ctx, Index pos) { return ctx.in.err("unimplemented instruction"); } diff --git a/src/wasm2js.h b/src/wasm2js.h index d33e45c4c..e12749836 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -2315,7 +2315,11 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, unimplemented(curr); WASM_UNREACHABLE("unimp"); } - Ref visitArrayNewSeg(ArrayNewSeg* curr) { + Ref visitArrayNewData(ArrayNewData* curr) { + unimplemented(curr); + WASM_UNREACHABLE("unimp"); + } + Ref visitArrayNewElem(ArrayNewElem* curr) { unimplemented(curr); WASM_UNREACHABLE("unimp"); } @@ -2343,7 +2347,11 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, unimplemented(curr); WASM_UNREACHABLE("unimp"); } - Ref visitArrayInit(ArrayInit* curr) { + Ref visitArrayInitData(ArrayInitData* curr) { + unimplemented(curr); + WASM_UNREACHABLE("unimp"); + } + Ref visitArrayInitElem(ArrayInitElem* curr) { unimplemented(curr); WASM_UNREACHABLE("unimp"); } |