diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.h | 3 | ||||
-rw-r--r-- | src/gen-s-parser.inc | 58 | ||||
-rw-r--r-- | src/ir/ReFinalize.cpp | 1 | ||||
-rw-r--r-- | src/ir/cost.h | 3 | ||||
-rw-r--r-- | src/ir/effects.h | 5 | ||||
-rw-r--r-- | src/ir/possible-contents.cpp | 20 | ||||
-rw-r--r-- | src/literal.h | 4 | ||||
-rw-r--r-- | src/passes/Print.cpp | 23 | ||||
-rw-r--r-- | src/passes/RemoveUnusedModuleElements.cpp | 19 | ||||
-rw-r--r-- | src/wasm-binary.h | 3 | ||||
-rw-r--r-- | src/wasm-builder.h | 14 | ||||
-rw-r--r-- | src/wasm-delegations-fields.def | 9 | ||||
-rw-r--r-- | src/wasm-delegations.def | 1 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 62 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 1 | ||||
-rw-r--r-- | src/wasm.h | 18 | ||||
-rw-r--r-- | src/wasm/literal.cpp | 51 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 32 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 12 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 16 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 68 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 7 | ||||
-rw-r--r-- | src/wasm/wat-parser.cpp | 8 | ||||
-rw-r--r-- | src/wasm2js.h | 4 |
24 files changed, 422 insertions, 20 deletions
diff --git a/src/binaryen-c.h b/src/binaryen-c.h index f5347a65b..8da248f07 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -1071,6 +1071,9 @@ BINARYEN_API BinaryenExpressionRef BinaryenArrayNew(BinaryenModuleRef module, BinaryenHeapType type, BinaryenExpressionRef size, BinaryenExpressionRef init); + +// TODO: BinaryenArrayNewSeg + BINARYEN_API BinaryenExpressionRef BinaryenArrayInit(BinaryenModuleRef module, BinaryenHeapType type, diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 67f58b5e6..929634c6c 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -47,9 +47,25 @@ switch (op[0]) { case '\0': if (op == "array.new"sv) { return makeArrayNewStatic(s, false); } goto parse_error; - case '_': - if (op == "array.new_default"sv) { return makeArrayNewStatic(s, true); } - goto parse_error; + case '_': { + switch (op[10]) { + case 'd': { + switch (op[11]) { + case 'a': + if (op == "array.new_data"sv) { return makeArrayNewSeg(s, NewData); } + goto parse_error; + case 'e': + if (op == "array.new_default"sv) { return makeArrayNewStatic(s, true); } + goto parse_error; + default: goto parse_error; + } + } + case 'e': + if (op == "array.new_elem"sv) { return makeArrayNewSeg(s, NewElem); } + goto parse_error; + default: goto parse_error; + } + } default: goto parse_error; } } @@ -3602,13 +3618,37 @@ switch (op[0]) { return *ret; } goto parse_error; - case '_': - if (op == "array.new_default"sv) { - auto ret = makeArrayNewStatic(ctx, pos, true); - CHECK_ERR(ret); - return *ret; + case '_': { + switch (op[10]) { + case 'd': { + switch (op[11]) { + case 'a': + if (op == "array.new_data"sv) { + auto ret = makeArrayNewSeg(ctx, pos, NewData); + CHECK_ERR(ret); + return *ret; + } + goto parse_error; + case 'e': + if (op == "array.new_default"sv) { + auto ret = makeArrayNewStatic(ctx, pos, true); + CHECK_ERR(ret); + return *ret; + } + goto parse_error; + default: goto parse_error; + } + } + case 'e': + if (op == "array.new_elem"sv) { + auto ret = makeArrayNewSeg(ctx, pos, NewElem); + CHECK_ERR(ret); + return *ret; + } + goto parse_error; + default: goto parse_error; } - goto parse_error; + } default: goto parse_error; } } diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 1e77630ab..5ae6a67ce 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -164,6 +164,7 @@ 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::visitArrayInit(ArrayInit* curr) { curr->finalize(); } void ReFinalize::visitArrayGet(ArrayGet* curr) { curr->finalize(); } void ReFinalize::visitArraySet(ArraySet* curr) { curr->finalize(); } diff --git a/src/ir/cost.h b/src/ir/cost.h index ff9bade10..59b738b1b 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -636,6 +636,9 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> { CostType visitArrayNew(ArrayNew* curr) { return 4 + visit(curr->size) + maybeVisit(curr->init); } + CostType visitArrayNewSeg(ArrayNewSeg* curr) { + return 4 + visit(curr->offset) + visit(curr->size); + } CostType visitArrayInit(ArrayInit* curr) { CostType ret = 4; for (auto* child : curr->values) { diff --git a/src/ir/effects.h b/src/ir/effects.h index 2dfe616f9..70e9192c0 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -755,6 +755,11 @@ private: } } void visitArrayNew(ArrayNew* curr) {} + void visitArrayNewSeg(ArrayNewSeg* curr) { + // Traps on out of bounds access to segments or access to dropped + // segments. + parent.implicitTrap = true; + } void visitArrayInit(ArrayInit* curr) {} void visitArrayGet(ArrayGet* curr) { if (curr->ref->type.isNull()) { diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 9c132fd0c..0c4e28568 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -896,6 +896,26 @@ struct InfoCollector } addRoot(curr, PossibleContents::exactType(curr->type)); } + void visitArrayNewSeg(ArrayNewSeg* curr) { + if (curr->type == Type::unreachable) { + return; + } + 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()->elementSegments[curr->segment]->type; + addRoot(DataLocation{heapType, 0}, PossibleContents::fromType(segType)); + return; + } + } + WASM_UNREACHABLE("unexpected op"); + } void visitArrayInit(ArrayInit* curr) { if (curr->type == Type::unreachable) { return; diff --git a/src/literal.h b/src/literal.h index 7d7c778bc..213713a1f 100644 --- a/src/literal.h +++ b/src/literal.h @@ -197,6 +197,10 @@ public: WASM_UNREACHABLE("unexpected type"); } } + + static Literal makeFromMemory(void* p, Type type); + static Literal makeFromMemory(void* p, const Field& field); + static Literal makeSignedMin(Type type) { switch (type.getBasic()) { case Type::i32: diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index d0f19f78e..6dbd54e73 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2205,6 +2205,26 @@ struct PrintExpressionContents o << ' '; TypeNamePrinter(o, wasm).print(curr->type.getHeapType()); } + void visitArrayNewSeg(ArrayNewSeg* 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"); + } + o << ' '; + TypeNamePrinter(o, wasm).print(curr->type.getHeapType()); + o << ' ' << curr->segment; + } void visitArrayInit(ArrayInit* curr) { if (printUnreachableReplacement(curr)) { return; @@ -2789,6 +2809,9 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> { void visitArrayNew(ArrayNew* curr) { maybePrintUnreachableReplacement(curr, curr->type); } + void visitArrayNewSeg(ArrayNewSeg* curr) { + maybePrintUnreachableReplacement(curr, curr->type); + } void visitArrayInit(ArrayInit* curr) { maybePrintUnreachableReplacement(curr, curr->type); } diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp index 0cafd9d9d..93cc33563 100644 --- a/src/passes/RemoveUnusedModuleElements.cpp +++ b/src/passes/RemoveUnusedModuleElements.cpp @@ -32,6 +32,7 @@ namespace wasm { +// TODO: Add data segment, multiple memories (#5224) enum class ModuleElementKind { Function, Global, Tag, Table, ElementSegment }; typedef std::pair<ModuleElementKind, Name> ModuleElement; @@ -195,7 +196,10 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> { void visitAtomicNotify(AtomicNotify* curr) { usesMemory = true; } void visitAtomicFence(AtomicFence* curr) { usesMemory = true; } void visitMemoryInit(MemoryInit* curr) { usesMemory = true; } - void visitDataDrop(DataDrop* curr) { usesMemory = true; } + void visitDataDrop(DataDrop* curr) { + // TODO: Replace this with a use of a data segment (#5224). + usesMemory = true; + } void visitMemoryCopy(MemoryCopy* curr) { usesMemory = true; } void visitMemoryFill(MemoryFill* curr) { usesMemory = true; } void visitMemorySize(MemorySize* curr) { usesMemory = true; } @@ -227,6 +231,19 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> { maybeAdd(ModuleElement(ModuleElementKind::Tag, tag)); } } + void visitArrayNewSeg(ArrayNewSeg* curr) { + switch (curr->op) { + case NewData: + // TODO: Replace this with a use of the specific data segment (#5224). + usesMemory = true; + return; + case NewElem: + auto segment = module->elementSegments[curr->segment]->name; + maybeAdd(ModuleElement(ModuleElementKind::ElementSegment, segment)); + return; + } + WASM_UNREACHABLE("unexpected op"); + } }; struct RemoveUnusedModuleElements : public Pass { diff --git a/src/wasm-binary.h b/src/wasm-binary.h index db123515a..b0128cbc5 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1107,6 +1107,7 @@ enum ASTNodes { StructSet = 0x06, StructNew = 0x07, StructNewDefault = 0x08, + ArrayNewElem = 0x10, ArrayGet = 0x13, ArrayGetS = 0x14, ArrayGetU = 0x15, @@ -1117,6 +1118,7 @@ enum ASTNodes { ArrayInitStatic = 0x1a, ArrayNew = 0x1b, ArrayNewDefault = 0x1c, + ArrayNewData = 0x1d, I31New = 0x20, I31GetS = 0x21, I31GetU = 0x22, @@ -1706,6 +1708,7 @@ public: 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 maybeVisitArrayInit(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 df036b3b4..1eb31157d 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -935,6 +935,20 @@ public: ret->finalize(); return ret; } + ArrayNewSeg* makeArrayNewSeg(ArrayNewSegOp op, + HeapType type, + Index seg, + Expression* offset, + Expression* size) { + auto* ret = wasm.allocator.alloc<ArrayNewSeg>(); + ret->op = op; + ret->segment = seg; + ret->offset = offset; + ret->size = size; + ret->type = Type(type, NonNullable); + ret->finalize(); + return ret; + } ArrayInit* makeArrayInit(HeapType type, const std::vector<Expression*>& values) { auto* ret = wasm.allocator.alloc<ArrayInit>(); diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index ff0f41d50..85a088dd8 100644 --- a/src/wasm-delegations-fields.def +++ b/src/wasm-delegations-fields.def @@ -664,6 +664,15 @@ switch (DELEGATE_ID) { DELEGATE_END(ArrayNew); break; } + case Expression::Id::ArrayNewSegId: { + DELEGATE_START(ArrayNewSeg); + DELEGATE_FIELD_INT(ArrayNewSeg, op); + DELEGATE_FIELD_INT(ArrayNewSeg, segment); + DELEGATE_FIELD_CHILD(ArrayNewSeg, size); + DELEGATE_FIELD_CHILD(ArrayNewSeg, offset); + DELEGATE_END(ArrayNewSeg); + break; + } case Expression::Id::ArrayInitId: { DELEGATE_START(ArrayInit); DELEGATE_FIELD_CHILD_VECTOR(ArrayInit, values); diff --git a/src/wasm-delegations.def b/src/wasm-delegations.def index b88a55556..dbdef3a86 100644 --- a/src/wasm-delegations.def +++ b/src/wasm-delegations.def @@ -77,6 +77,7 @@ DELEGATE(StructNew); DELEGATE(StructGet); DELEGATE(StructSet); DELEGATE(ArrayNew); +DELEGATE(ArrayNewSeg); DELEGATE(ArrayInit); DELEGATE(ArrayGet); DELEGATE(ArraySet); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 8f7418719..9599d81cd 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1700,6 +1700,7 @@ public: return Literal(std::make_shared<GCData>(curr->type.getHeapType(), data), curr->type.getHeapType()); } + Flow visitArrayNewSeg(ArrayNewSeg* curr) { WASM_UNREACHABLE("unimp"); } Flow visitArrayInit(ArrayInit* curr) { NOTE_ENTER("ArrayInit"); Index num = curr->values.size(); @@ -2187,6 +2188,10 @@ public: NOTE_ENTER("SIMDLoadStoreLane"); return Flow(NONCONSTANT_FLOW); } + Flow visitArrayNewSeg(ArrayNewSeg* curr) { + NOTE_ENTER("ArrayNewSeg"); + return Flow(NONCONSTANT_FLOW); + } Flow visitPop(Pop* curr) { NOTE_ENTER("Pop"); return Flow(NONCONSTANT_FLOW); @@ -3494,6 +3499,63 @@ public: } return {}; } + Flow visitArrayNewSeg(ArrayNewSeg* curr) { + NOTE_ENTER("ArrayNewSeg"); + auto offsetFlow = self()->visit(curr->offset); + if (offsetFlow.breaking()) { + return offsetFlow; + } + auto sizeFlow = self()->visit(curr->size); + if (sizeFlow.breaking()) { + return sizeFlow; + } + + auto offset = offsetFlow.getSingleValue().geti32(); + auto size = sizeFlow.getSingleValue().geti32(); + + auto heapType = curr->type.getHeapType(); + const auto& element = heapType.getArray().element; + auto elemType = heapType.getArray().element.type; + + Literals contents; + contents.reserve(size); + + switch (curr->op) { + case NewData: { + assert(curr->segment < wasm.dataSegments.size()); + assert(elemType.isNumber()); + const auto& seg = *wasm.dataSegments[curr->segment]; + auto elemBytes = element.getByteSize(); + auto end = (uint64_t)offset + size * elemBytes; + if ((size != 0ull && droppedSegments.count(curr->segment)) || + end > seg.data.size()) { + trap("out of bounds segment access in array.new_data"); + } + for (Index i = offset; i < end; i += elemBytes) { + auto addr = (void*)&seg.data[i]; + contents.push_back(Literal::makeFromMemory(addr, element)); + } + break; + } + case NewElem: { + assert(curr->segment < wasm.elementSegments.size()); + const auto& seg = *wasm.elementSegments[curr->segment]; + auto end = (uint64_t)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"); + } + 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"); + } + return Literal(std::make_shared<GCData>(heapType, contents), heapType); + } Flow visitTry(Try* curr) { NOTE_ENTER("Try"); try { diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index 888f7d009..67459dba9 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -293,6 +293,7 @@ private: Expression* makeStructGet(Element& s, bool signed_ = false); Expression* makeStructSet(Element& s); Expression* makeArrayNewStatic(Element& s, bool default_); + Expression* makeArrayNewSeg(Element& s, ArrayNewSegOp op); Expression* makeArrayInitStatic(Element& s); Expression* makeArrayGet(Element& s, bool signed_ = false); Expression* makeArraySet(Element& s); diff --git a/src/wasm.h b/src/wasm.h index 2b890177e..3daff2c4c 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -573,6 +573,11 @@ enum RefAsOp { ExternExternalize, }; +enum ArrayNewSegOp { + NewData, + NewElem, +}; + enum BrOnOp { BrOnNull, BrOnNonNull, @@ -719,6 +724,7 @@ public: StructGetId, StructSetId, ArrayNewId, + ArrayNewSegId, ArrayInitId, ArrayGetId, ArraySetId, @@ -1605,6 +1611,18 @@ public: void finalize(); }; +class ArrayNewSeg : public SpecificExpression<Expression::ArrayNewSegId> { +public: + ArrayNewSeg(MixedArena& allocator) {} + + ArrayNewSegOp op; + Index segment; + Expression* offset; + Expression* size; + + void finalize(); +}; + class ArrayInit : public SpecificExpression<Expression::ArrayInitId> { public: ArrayInit(MixedArena& allocator) : values(allocator) {} diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 8d60a4829..7890c7a42 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -235,6 +235,57 @@ Literal Literal::makeNegOne(Type type) { return makeFromInt32(-1, type); } +Literal Literal::makeFromMemory(void* p, Type type) { + assert(type.isNumber()); + switch (type.getBasic()) { + case Type::i32: { + int32_t i; + memcpy(&i, p, sizeof(i)); + return Literal(i); + } + case Type::i64: { + int64_t i; + memcpy(&i, p, sizeof(i)); + return Literal(i); + } + case Type::f32: { + int32_t i; + memcpy(&i, p, sizeof(i)); + return Literal(bit_cast<float>(i)); + } + case Type::f64: { + int64_t i; + memcpy(&i, p, sizeof(i)); + return Literal(bit_cast<double>(i)); + } + case Type::v128: { + uint8_t bytes[16]; + memcpy(bytes, p, sizeof(bytes)); + return Literal(bytes); + } + default: + WASM_UNREACHABLE("unexpected type"); + } +} + +Literal Literal::makeFromMemory(void* p, const Field& field) { + switch (field.packedType) { + case Field::not_packed: + return makeFromMemory(p, field.type); + case Field::i8: { + int8_t i; + memcpy(&i, p, sizeof(i)); + return Literal(int32_t(i)); + } + case Field::i16: { + int16_t i; + memcpy(&i, p, sizeof(i)); + return Literal(int32_t(i)); + } + } + WASM_UNREACHABLE("unexpected type"); +} + Literal Literal::standardizeNaN(const Literal& input) { if (!std::isnan(input.getFloat())) { return input; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index d023a56c6..e2bb0075b 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -3122,12 +3122,15 @@ void WasmBinaryBuilder::readDataSegments() { } curr->setName(Name::fromInt(i), false); curr->isPassive = flags & BinaryConsts::IsPassive; - Index memIdx = 0; - if (flags & BinaryConsts::HasIndex) { - memIdx = getU32LEB(); - } - memoryRefs[memIdx].push_back(&curr->memory); - if (!curr->isPassive) { + if (curr->isPassive) { + curr->memory = Name(); + curr->offset = nullptr; + } else { + Index memIdx = 0; + if (flags & BinaryConsts::HasIndex) { + memIdx = getU32LEB(); + } + memoryRefs[memIdx].push_back(&curr->memory); curr->offset = readExpression(); } auto size = getU32LEB(); @@ -3973,6 +3976,9 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { if (maybeVisitArrayNew(curr, opcode)) { break; } + if (maybeVisitArrayNewSeg(curr, opcode)) { + break; + } if (maybeVisitArrayInit(curr, opcode)) { break; } @@ -7058,6 +7064,20 @@ bool WasmBinaryBuilder::maybeVisitArrayNew(Expression*& out, uint32_t code) { return false; } +bool WasmBinaryBuilder::maybeVisitArrayNewSeg(Expression*& out, uint32_t code) { + if (code == BinaryConsts::ArrayNewData || + code == BinaryConsts::ArrayNewElem) { + auto op = code == BinaryConsts::ArrayNewData ? NewData : NewElem; + auto heapType = getIndexedHeapType(); + auto seg = getU32LEB(); + auto* size = popNonVoidExpression(); + auto* offset = popNonVoidExpression(); + out = Builder(wasm).makeArrayNewSeg(op, heapType, seg, offset, size); + return true; + } + return false; +} + bool WasmBinaryBuilder::maybeVisitArrayInit(Expression*& out, uint32_t code) { if (code == BinaryConsts::ArrayInitStatic) { auto heapType = getIndexedHeapType(); diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index a54226194..a9fd2de77 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -2892,6 +2892,15 @@ Expression* SExpressionWasmBuilder::makeArrayNewStatic(Element& s, return Builder(wasm).makeArrayNew(heapType, size, init); } +Expression* SExpressionWasmBuilder::makeArrayNewSeg(Element& s, + ArrayNewSegOp op) { + auto heapType = parseHeapType(*s[1]); + Index seg = parseIndex(*s[2]); + Expression* offset = parseExpression(*s[3]); + Expression* size = parseExpression(*s[4]); + return Builder(wasm).makeArrayNewSeg(op, heapType, seg, offset, size); +} + Expression* SExpressionWasmBuilder::makeArrayInitStatic(Element& s) { auto heapType = parseHeapType(*s[1]); size_t i = 2; @@ -3292,9 +3301,6 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) { } void SExpressionWasmBuilder::parseData(Element& s) { - if (wasm.memories.empty()) { - throw ParseException("data but no memory", s.line, s.col); - } Index i = 1; Name name = Name::fromInt(dataCounter++); bool hasExplicitName = false; diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index f30e4be82..daeac60d6 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2132,6 +2132,22 @@ void BinaryInstWriter::visitArrayNew(ArrayNew* curr) { parent.writeIndexedHeapType(curr->type.getHeapType()); } +void BinaryInstWriter::visitArrayNewSeg(ArrayNewSeg* curr) { + o << int8_t(BinaryConsts::GCPrefix); + switch (curr->op) { + case NewData: + o << U32LEB(BinaryConsts::ArrayNewData); + break; + case NewElem: + o << U32LEB(BinaryConsts::ArrayNewElem); + break; + default: + WASM_UNREACHABLE("unexpected op"); + } + parent.writeIndexedHeapType(curr->type.getHeapType()); + o << U32LEB(curr->segment); +} + void BinaryInstWriter::visitArrayInit(ArrayInit* curr) { o << int8_t(BinaryConsts::GCPrefix); o << U32LEB(BinaryConsts::ArrayInitStatic); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index cb3841197..c1316f283 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -451,6 +451,7 @@ public: void visitStructGet(StructGet* curr); void visitStructSet(StructSet* curr); void visitArrayNew(ArrayNew* curr); + void visitArrayNewSeg(ArrayNewSeg* curr); void visitArrayInit(ArrayInit* curr); void visitArrayGet(ArrayGet* curr); void visitArraySet(ArraySet* curr); @@ -2683,6 +2684,73 @@ void FunctionValidator::visitArrayNew(ArrayNew* curr) { } } +void FunctionValidator::visitArrayNewSeg(ArrayNewSeg* curr) { + shouldBeTrue(getModule()->features.hasGC(), + curr, + "array.new_{data, elem} requires gc [--enable-gc]"); + shouldBeEqualOrFirstIsUnreachable( + curr->offset->type, + Type(Type::i32), + curr, + "array.new_{data, elem} offset must be an i32"); + shouldBeEqualOrFirstIsUnreachable( + curr->size->type, + Type(Type::i32), + curr, + "array.new_{data, elem} size must be an i32"); + switch (curr->op) { + case NewData: + if (!shouldBeTrue(curr->segment < getModule()->dataSegments.size(), + curr, + "array.new_data segment index out of bounds")) { + return; + } + break; + case NewElem: + if (!shouldBeTrue(curr->segment < getModule()->elementSegments.size(), + curr, + "array.new_elem segment index out of bounds")) { + return; + } + break; + default: + WASM_UNREACHABLE("unexpected op"); + } + if (curr->type == Type::unreachable) { + return; + } + if (!shouldBeTrue( + curr->type.isRef(), + curr, + "array.new_{data, elem} type should be an array reference")) { + return; + } + auto heapType = curr->type.getHeapType(); + if (!shouldBeTrue( + heapType.isArray(), + curr, + "array.new_{data, elem} type shoudl 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()->elementSegments[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::visitArrayInit(ArrayInit* curr) { shouldBeTrue(getModule()->features.hasGC(), curr, diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 6347d83e5..a92b62343 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -1053,7 +1053,12 @@ void ArrayNew::finalize() { if (size->type == Type::unreachable || (init && init->type == Type::unreachable)) { type = Type::unreachable; - return; + } +} + +void ArrayNewSeg::finalize() { + if (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 1c1349e47..7705c9e5c 100644 --- a/src/wasm/wat-parser.cpp +++ b/src/wasm/wat-parser.cpp @@ -1907,6 +1907,8 @@ template<typename Ctx> Result<typename Ctx::InstrT> makeStructSet(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeArrayNewStatic(Ctx&, Index, bool default_); template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayNewSeg(Ctx&, Index, ArrayNewSegOp op); +template<typename Ctx> Result<typename Ctx::InstrT> makeArrayInitStatic(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeArrayGet(Ctx&, Index, bool signed_ = false); @@ -2892,6 +2894,12 @@ makeArrayNewStatic(Ctx& ctx, Index pos, bool default_) { } template<typename Ctx> +Result<typename Ctx::InstrT> +makeArrayNewSeg(Ctx& ctx, Index pos, ArrayNewSegOp op) { + return ctx.in.err("unimplemented instruction"); +} + +template<typename Ctx> Result<typename Ctx::InstrT> makeArrayInitStatic(Ctx& ctx, Index pos) { return ctx.in.err("unimplemented instruction"); } diff --git a/src/wasm2js.h b/src/wasm2js.h index 2ae22de09..982184510 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -2304,6 +2304,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, unimplemented(curr); WASM_UNREACHABLE("unimp"); } + Ref visitArrayNewSeg(ArrayNewSeg* curr) { + unimplemented(curr); + WASM_UNREACHABLE("unimp"); + } Ref visitArrayInit(ArrayInit* curr) { unimplemented(curr); WASM_UNREACHABLE("unimp"); |