summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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");
}