summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gen-s-parser.inc3
-rw-r--r--src/ir/ReFinalize.cpp1
-rw-r--r--src/ir/cost.h7
-rw-r--r--src/ir/effects.h1
-rw-r--r--src/ir/global-utils.h2
-rw-r--r--src/ir/properties.cpp1
-rw-r--r--src/js/binaryen.js-post.js1
-rw-r--r--src/passes/Precompute.cpp1
-rw-r--r--src/passes/Print.cpp4
-rw-r--r--src/wasm-binary.h2
-rw-r--r--src/wasm-builder.h8
-rw-r--r--src/wasm-delegations-fields.def7
-rw-r--r--src/wasm-delegations.def1
-rw-r--r--src/wasm-interpreter.h21
-rw-r--r--src/wasm-s-parser.h1
-rw-r--r--src/wasm.h11
-rw-r--r--src/wasm/wasm-binary.cpp19
-rw-r--r--src/wasm/wasm-s-parser.cpp12
-rw-r--r--src/wasm/wasm-stack.cpp6
-rw-r--r--src/wasm/wasm-validator.cpp26
-rw-r--r--src/wasm/wasm.cpp14
-rw-r--r--src/wasm2js.h4
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");