diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gen-s-parser.inc | 3 | ||||
-rw-r--r-- | src/ir/ReFinalize.cpp | 1 | ||||
-rw-r--r-- | src/ir/cost.h | 7 | ||||
-rw-r--r-- | src/ir/effects.h | 1 | ||||
-rw-r--r-- | src/ir/global-utils.h | 2 | ||||
-rw-r--r-- | src/ir/properties.cpp | 1 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 1 | ||||
-rw-r--r-- | src/passes/Precompute.cpp | 1 | ||||
-rw-r--r-- | src/passes/Print.cpp | 4 | ||||
-rw-r--r-- | src/wasm-binary.h | 2 | ||||
-rw-r--r-- | src/wasm-builder.h | 8 | ||||
-rw-r--r-- | src/wasm-delegations-fields.def | 7 | ||||
-rw-r--r-- | src/wasm-delegations.def | 1 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 21 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 1 | ||||
-rw-r--r-- | src/wasm.h | 11 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 19 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 12 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 6 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 26 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 14 | ||||
-rw-r--r-- | src/wasm2js.h | 4 |
22 files changed, 152 insertions, 1 deletions
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 9cb1962e8..7374e630a 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -33,6 +33,9 @@ switch (op[0]) { default: goto parse_error; } } + case 'i': + if (strcmp(op, "array.init") == 0) { return makeArrayInit(s); } + goto parse_error; case 'l': if (strcmp(op, "array.len") == 0) { return makeArrayLen(s); } goto parse_error; diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 419b83cc2..0d089a7ce 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -162,6 +162,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::visitArrayInit(ArrayInit* curr) { curr->finalize(); } void ReFinalize::visitArrayGet(ArrayGet* curr) { curr->finalize(); } void ReFinalize::visitArraySet(ArraySet* curr) { curr->finalize(); } void ReFinalize::visitArrayLen(ArrayLen* curr) { curr->finalize(); } diff --git a/src/ir/cost.h b/src/ir/cost.h index 63424c8b3..e3e6aebf3 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -606,6 +606,13 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> { CostType visitArrayNew(ArrayNew* curr) { return 4 + visit(curr->rtt) + visit(curr->size) + maybeVisit(curr->init); } + CostType visitArrayInit(ArrayInit* curr) { + CostType ret = 4 + visit(curr->rtt); + for (auto* child : curr->values) { + ret += visit(child); + } + return ret; + } CostType visitArrayGet(ArrayGet* curr) { return 1 + nullCheckCost(curr->ref) + visit(curr->ref) + visit(curr->index); } diff --git a/src/ir/effects.h b/src/ir/effects.h index 475e6f2b1..ad8f68efa 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -642,6 +642,7 @@ private: } } void visitArrayNew(ArrayNew* curr) {} + void visitArrayInit(ArrayInit* curr) {} void visitArrayGet(ArrayGet* curr) { parent.readsArray = true; // traps when the arg is null or the index out of bounds diff --git a/src/ir/global-utils.h b/src/ir/global-utils.h index cf0c8e1a9..34c0e56cf 100644 --- a/src/ir/global-utils.h +++ b/src/ir/global-utils.h @@ -65,7 +65,7 @@ inline bool canInitializeGlobal(Expression* curr) { } if (Properties::isSingleConstantExpression(curr) || curr->is<GlobalGet>() || curr->is<RttCanon>() || curr->is<RttSub>() || curr->is<StructNew>() || - curr->is<ArrayNew>() || curr->is<I31New>()) { + curr->is<ArrayNew>() || curr->is<ArrayInit>() || curr->is<I31New>()) { for (auto* child : ChildIterator(curr)) { if (!canInitializeGlobal(child)) { return false; diff --git a/src/ir/properties.cpp b/src/ir/properties.cpp index fa4f299b3..4739fcaaf 100644 --- a/src/ir/properties.cpp +++ b/src/ir/properties.cpp @@ -32,6 +32,7 @@ bool isGenerative(Expression* curr, FeatureSet features) { bool generative = false; void visitStructNew(StructNew* curr) { generative = true; } void visitArrayNew(ArrayNew* curr) { generative = true; } + void visitArrayInit(ArrayInit* curr) { generative = true; } } scanner; scanner.walk(curr); return scanner.generative; diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index a91d5af31..94f2d446c 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -109,6 +109,7 @@ function initializeConstants() { 'StructGet', 'StructSet', 'ArrayNew', + 'ArrayInit', 'ArrayGet', 'ArraySet', 'ArrayLen' diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp index 1ba298605..76ed547c1 100644 --- a/src/passes/Precompute.cpp +++ b/src/passes/Precompute.cpp @@ -94,6 +94,7 @@ public: Flow visitStructNew(StructNew* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitStructGet(StructGet* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitArrayNew(ArrayNew* curr) { return Flow(NONCONSTANT_FLOW); } + Flow visitArrayInit(ArrayInit* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitArrayGet(ArrayGet* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitArrayLen(ArrayLen* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitArrayCopy(ArrayCopy* curr) { return Flow(NONCONSTANT_FLOW); } diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 616ce9759..00b09dea4 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2006,6 +2006,10 @@ struct PrintExpressionContents o << "with_rtt "; TypeNamePrinter(o, wasm).print(curr->rtt->type.getHeapType()); } + void visitArrayInit(ArrayInit* curr) { + printMedium(o, "array.init "); + TypeNamePrinter(o, wasm).print(curr->rtt->type.getHeapType()); + } void visitArrayGet(ArrayGet* curr) { if (printUnreachableReplacement(curr->ref)) { return; diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 13925f5e1..0c95f2b44 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1056,6 +1056,7 @@ enum ASTNodes { ArraySet = 0x16, ArrayLen = 0x17, ArrayCopy = 0x18, + ArrayInit = 0x19, I31New = 0x20, I31GetS = 0x21, I31GetU = 0x22, @@ -1626,6 +1627,7 @@ public: bool maybeVisitStructGet(Expression*& out, uint32_t code); bool maybeVisitStructSet(Expression*& out, uint32_t code); bool maybeVisitArrayNew(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); bool maybeVisitArrayLen(Expression*& out, uint32_t code); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 3eb263580..018b0bf8b 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -840,6 +840,14 @@ public: ret->finalize(); return ret; } + ArrayInit* makeArrayInit(Expression* rtt, + const std::vector<Expression*>& values) { + auto* ret = wasm.allocator.alloc<ArrayInit>(); + ret->rtt = rtt; + ret->values.set(values); + ret->finalize(); + return ret; + } ArrayGet* makeArrayGet(Expression* ref, Expression* index, bool signed_ = false) { auto* ret = wasm.allocator.alloc<ArrayGet>(); diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index ab68b5206..b94aa5599 100644 --- a/src/wasm-delegations-fields.def +++ b/src/wasm-delegations-fields.def @@ -634,6 +634,13 @@ switch (DELEGATE_ID) { DELEGATE_END(ArrayNew); break; } + case Expression::Id::ArrayInitId: { + DELEGATE_START(ArrayInit); + DELEGATE_FIELD_CHILD(ArrayInit, rtt); + DELEGATE_FIELD_CHILD_VECTOR(ArrayInit, values); + DELEGATE_END(ArrayInit); + break; + } case Expression::Id::ArrayGetId: { DELEGATE_START(ArrayGet); DELEGATE_FIELD_CHILD(ArrayGet, index); diff --git a/src/wasm-delegations.def b/src/wasm-delegations.def index 358a04dcd..2579ac621 100644 --- a/src/wasm-delegations.def +++ b/src/wasm-delegations.def @@ -75,6 +75,7 @@ DELEGATE(StructNew); DELEGATE(StructGet); DELEGATE(StructSet); DELEGATE(ArrayNew); +DELEGATE(ArrayInit); DELEGATE(ArrayGet); DELEGATE(ArraySet); DELEGATE(ArrayLen); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 77e432436..9fc11de76 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1702,6 +1702,27 @@ public: return Flow(Literal(std::make_shared<GCData>(rtt.getSingleValue(), data), curr->type)); } + Flow visitArrayInit(ArrayInit* curr) { + NOTE_ENTER("ArrayInit"); + auto rtt = this->visit(curr->rtt); + if (rtt.breaking()) { + return rtt; + } + Index num = curr->values.size(); + if (num >= ArrayLimit) { + hostLimit("allocation failure"); + } + Literals data(num); + for (Index i = 0; i < num; i++) { + auto value = this->visit(curr->values[i]); + if (value.breaking()) { + return value; + } + data[i] = value.getSingleValue(); + } + return Flow(Literal(std::make_shared<GCData>(rtt.getSingleValue(), data), + curr->type)); + } Flow visitArrayGet(ArrayGet* curr) { NOTE_ENTER("ArrayGet"); Flow ref = this->visit(curr->ref); diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index e5ba2996e..03462a7cb 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -284,6 +284,7 @@ private: Expression* makeStructGet(Element& s, bool signed_ = false); Expression* makeStructSet(Element& s); Expression* makeArrayNew(Element& s, bool default_); + Expression* makeArrayInit(Element& s); Expression* makeArrayGet(Element& s, bool signed_ = false); Expression* makeArraySet(Element& s); Expression* makeArrayLen(Element& s); diff --git a/src/wasm.h b/src/wasm.h index c4a58f3a4..2efbbfd9c 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -641,6 +641,7 @@ public: StructGetId, StructSetId, ArrayNewId, + ArrayInitId, ArrayGetId, ArraySetId, ArrayLenId, @@ -1468,6 +1469,16 @@ public: void finalize(); }; +class ArrayInit : public SpecificExpression<Expression::ArrayInitId> { +public: + ArrayInit(MixedArena& allocator) : values(allocator) {} + + ExpressionList values; + Expression* rtt; + + void finalize(); +}; + class ArrayGet : public SpecificExpression<Expression::ArrayGetId> { public: ArrayGet(MixedArena& allocator) {} diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index ee3c1a6fa..b6a5daf14 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -3574,6 +3574,9 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { if (maybeVisitArrayNew(curr, opcode)) { break; } + if (maybeVisitArrayInit(curr, opcode)) { + break; + } if (maybeVisitArrayGet(curr, opcode)) { break; } @@ -6508,6 +6511,22 @@ bool WasmBinaryBuilder::maybeVisitArrayNew(Expression*& out, uint32_t code) { return true; } +bool WasmBinaryBuilder::maybeVisitArrayInit(Expression*& out, uint32_t code) { + if (code != BinaryConsts::ArrayInit) { + return false; + } + auto heapType = getIndexedHeapType(); + auto size = getU32LEB(); + auto* rtt = popNonVoidExpression(); + validateHeapTypeUsingChild(rtt, heapType); + std::vector<Expression*> values(size); + for (size_t i = 0; i < size; i++) { + values[size - i - 1] = popNonVoidExpression(); + } + out = Builder(wasm).makeArrayInit(rtt, values); + return true; +} + bool WasmBinaryBuilder::maybeVisitArrayGet(Expression*& out, uint32_t code) { bool signed_ = false; switch (code) { diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index c9ca71a6d..28028c459 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -2680,6 +2680,18 @@ Expression* SExpressionWasmBuilder::makeArrayNew(Element& s, bool default_) { return Builder(wasm).makeArrayNew(rtt, size, init); } +Expression* SExpressionWasmBuilder::makeArrayInit(Element& s) { + auto heapType = parseHeapType(*s[1]); + size_t i = 2; + std::vector<Expression*> values; + while (i < s.size() - 1) { + values.push_back(parseExpression(*s[i++])); + } + auto* rtt = parseExpression(*s[i++]); + validateHeapTypeUsingChild(rtt, heapType, s); + return Builder(wasm).makeArrayInit(rtt, values); +} + Expression* SExpressionWasmBuilder::makeArrayGet(Element& s, bool signed_) { auto heapType = parseHeapType(*s[1]); auto ref = parseExpression(*s[2]); diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 7b682a264..e5460cf6f 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2040,6 +2040,12 @@ void BinaryInstWriter::visitArrayNew(ArrayNew* curr) { parent.writeIndexedHeapType(curr->rtt->type.getHeapType()); } +void BinaryInstWriter::visitArrayInit(ArrayInit* curr) { + o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::ArrayInit); + parent.writeIndexedHeapType(curr->rtt->type.getHeapType()); + o << U32LEB(curr->values.size()); +} + void BinaryInstWriter::visitArrayGet(ArrayGet* curr) { auto heapType = curr->ref->type.getHeapType(); const auto& field = heapType.getArray().element; diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 450a7b956..eaeea7f1a 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -382,6 +382,7 @@ public: void visitStructGet(StructGet* curr); void visitStructSet(StructSet* curr); void visitArrayNew(ArrayNew* curr); + void visitArrayInit(ArrayInit* curr); void visitArrayGet(ArrayGet* curr); void visitArraySet(ArraySet* curr); void visitArrayLen(ArrayLen* curr); @@ -2416,6 +2417,31 @@ void FunctionValidator::visitArrayNew(ArrayNew* curr) { } } +void FunctionValidator::visitArrayInit(ArrayInit* curr) { + shouldBeTrue(getModule()->features.hasGC(), + curr, + "array.init requires gc to be enabled"); + if (curr->type == Type::unreachable) { + return; + } + if (!shouldBeTrue( + curr->rtt->type.isRtt(), curr, "array.init rtt must be rtt")) { + return; + } + auto heapType = curr->rtt->type.getHeapType(); + if (!shouldBeTrue( + heapType.isArray(), curr, "array.init heap type must be array")) { + return; + } + const auto& element = heapType.getArray().element; + for (auto* value : curr->values) { + shouldBeSubType(value->type, + element.type, + curr, + "array.init value must have proper type"); + } +} + void FunctionValidator::visitArrayGet(ArrayGet* curr) { shouldBeTrue( getModule()->features.hasGC(), curr, "array.get requires gc to be enabled"); diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 0dfcf5c2e..761c17116 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -1035,6 +1035,20 @@ void ArrayNew::finalize() { type = Type(rtt->type.getHeapType(), NonNullable); } +void ArrayInit::finalize() { + if (rtt->type == Type::unreachable) { + type = Type::unreachable; + return; + } + for (auto* value : values) { + if (value->type == Type::unreachable) { + type = Type::unreachable; + return; + } + } + type = Type(rtt->type.getHeapType(), NonNullable); +} + void ArrayGet::finalize() { if (ref->type == Type::unreachable || index->type == Type::unreachable) { type = Type::unreachable; diff --git a/src/wasm2js.h b/src/wasm2js.h index e2b95f114..370546134 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -2239,6 +2239,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, unimplemented(curr); WASM_UNREACHABLE("unimp"); } + Ref visitArrayInit(ArrayInit* curr) { + unimplemented(curr); + WASM_UNREACHABLE("unimp"); + } Ref visitArrayGet(ArrayGet* curr) { unimplemented(curr); WASM_UNREACHABLE("unimp"); |