summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-05-04 16:44:09 -0700
committerGitHub <noreply@github.com>2023-05-04 16:44:09 -0700
commit7f8e4cbf6273c9b13b3a1a42f5e2833ea0d0f686 (patch)
treecc0343495b994c67a01b5143e6345d45a1c3587d /src
parent09fe432c0d3cb7562767a8e06d4e918beb5990c2 (diff)
downloadbinaryen-7f8e4cbf6273c9b13b3a1a42f5e2833ea0d0f686.tar.gz
binaryen-7f8e4cbf6273c9b13b3a1a42f5e2833ea0d0f686.tar.bz2
binaryen-7f8e4cbf6273c9b13b3a1a42f5e2833ea0d0f686.zip
[NFC] Refactor each of ArrayNewSeg and ArrayInit into subclasses for Data/Elem (#5692)
ArrayNewSeg => ArrayNewSegData, ArrayNewSegElem ArrayInit => ArrayInitData, ArrayInitElem Basically we remove the opcode and use the class type to differentiate them. This adds some code but it makes the representation simpler and more compact in memory, and it will help with #5690
Diffstat (limited to 'src')
-rw-r--r--src/gen-s-parser.inc16
-rw-r--r--src/ir/ReFinalize.cpp6
-rw-r--r--src/ir/cost.h11
-rw-r--r--src/ir/effects.h11
-rw-r--r--src/ir/memory-utils.cpp6
-rw-r--r--src/ir/module-utils.cpp8
-rw-r--r--src/ir/possible-contents.cpp30
-rw-r--r--src/passes/MemoryPacking.cpp24
-rw-r--r--src/passes/Print.cpp45
-rw-r--r--src/passes/RemoveUnusedModuleElements.cpp33
-rw-r--r--src/passes/TypeSSA.cpp7
-rw-r--r--src/wasm-binary.h4
-rw-r--r--src/wasm-builder.h52
-rw-r--r--src/wasm-delegations-fields.def48
-rw-r--r--src/wasm-delegations.def6
-rw-r--r--src/wasm-interpreter.h201
-rw-r--r--src/wasm-s-parser.h6
-rw-r--r--src/wasm.h51
-rw-r--r--src/wasm/wasm-binary.cpp47
-rw-r--r--src/wasm/wasm-s-parser.cpp34
-rw-r--r--src/wasm/wasm-stack.cpp54
-rw-r--r--src/wasm/wasm-validator.cpp141
-rw-r--r--src/wasm/wasm.cpp19
-rw-r--r--src/wasm/wat-parser.cpp59
-rw-r--r--src/wasm2js.h12
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");
}