summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gen-s-parser.inc70
-rw-r--r--src/ir/ExpressionAnalyzer.cpp3
-rw-r--r--src/ir/ExpressionManipulator.cpp1
-rw-r--r--src/ir/branch-utils.h2
-rw-r--r--src/ir/cost.h7
-rw-r--r--src/ir/iteration.h1
-rw-r--r--src/ir/module-utils.h28
-rw-r--r--src/ir/properties.h1
-rw-r--r--src/literal.h10
-rw-r--r--src/passes/Heap2Local.cpp4
-rw-r--r--src/passes/Print.cpp38
-rw-r--r--src/wasm-binary.h5
-rw-r--r--src/wasm-builder.h24
-rw-r--r--src/wasm-delegations-fields.def7
-rw-r--r--src/wasm-interpreter.h95
-rw-r--r--src/wasm-s-parser.h3
-rw-r--r--src/wasm.h15
-rw-r--r--src/wasm/wasm-binary.cpp111
-rw-r--r--src/wasm/wasm-s-parser.cpp37
-rw-r--r--src/wasm/wasm-stack.cpp41
-rw-r--r--src/wasm/wasm-validator.cpp48
-rw-r--r--src/wasm/wasm.cpp25
22 files changed, 451 insertions, 125 deletions
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc
index c7c521a21..69ce0dbbc 100644
--- a/src/gen-s-parser.inc
+++ b/src/gen-s-parser.inc
@@ -33,20 +33,44 @@ switch (op[0]) {
default: goto parse_error;
}
}
- case 'i':
- if (strcmp(op, "array.init") == 0) { return makeArrayInit(s); }
- goto parse_error;
+ case 'i': {
+ switch (op[10]) {
+ case '\0':
+ if (strcmp(op, "array.init") == 0) { return makeArrayInit(s); }
+ goto parse_error;
+ case '_':
+ if (strcmp(op, "array.init_static") == 0) { return makeArrayInitStatic(s); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
case 'l':
if (strcmp(op, "array.len") == 0) { return makeArrayLen(s); }
goto parse_error;
case 'n': {
- switch (op[10]) {
- case 'd':
- if (strcmp(op, "array.new_default_with_rtt") == 0) { return makeArrayNew(s, true); }
- goto parse_error;
- case 'w':
- if (strcmp(op, "array.new_with_rtt") == 0) { return makeArrayNew(s, false); }
+ switch (op[9]) {
+ case '\0':
+ if (strcmp(op, "array.new") == 0) { return makeArrayNewStatic(s, false); }
goto parse_error;
+ case '_': {
+ switch (op[10]) {
+ case 'd': {
+ switch (op[17]) {
+ case '\0':
+ if (strcmp(op, "array.new_default") == 0) { return makeArrayNewStatic(s, true); }
+ goto parse_error;
+ case '_':
+ if (strcmp(op, "array.new_default_with_rtt") == 0) { return makeArrayNew(s, true); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case 'w':
+ if (strcmp(op, "array.new_with_rtt") == 0) { return makeArrayNew(s, false); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
default: goto parse_error;
}
}
@@ -2980,13 +3004,29 @@ switch (op[0]) {
}
}
case 'n': {
- switch (op[11]) {
- case 'd':
- if (strcmp(op, "struct.new_default_with_rtt") == 0) { return makeStructNew(s, true); }
- goto parse_error;
- case 'w':
- if (strcmp(op, "struct.new_with_rtt") == 0) { return makeStructNew(s, false); }
+ switch (op[10]) {
+ case '\0':
+ if (strcmp(op, "struct.new") == 0) { return makeStructNewStatic(s, false); }
goto parse_error;
+ case '_': {
+ switch (op[11]) {
+ case 'd': {
+ switch (op[18]) {
+ case '\0':
+ if (strcmp(op, "struct.new_default") == 0) { return makeStructNewStatic(s, true); }
+ goto parse_error;
+ case '_':
+ if (strcmp(op, "struct.new_default_with_rtt") == 0) { return makeStructNew(s, true); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case 'w':
+ if (strcmp(op, "struct.new_with_rtt") == 0) { return makeStructNew(s, false); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
default: goto parse_error;
}
}
diff --git a/src/ir/ExpressionAnalyzer.cpp b/src/ir/ExpressionAnalyzer.cpp
index e98b14777..db972e707 100644
--- a/src/ir/ExpressionAnalyzer.cpp
+++ b/src/ir/ExpressionAnalyzer.cpp
@@ -194,6 +194,7 @@ bool ExpressionAnalyzer::flexibleEqual(Expression* left,
#define DELEGATE_FIELD_NAME(id, name) COMPARE_FIELD(name)
#define DELEGATE_FIELD_SIGNATURE(id, name) COMPARE_FIELD(name)
#define DELEGATE_FIELD_TYPE(id, name) COMPARE_FIELD(name)
+#define DELEGATE_FIELD_HEAPTYPE(id, name) COMPARE_FIELD(name)
#define DELEGATE_FIELD_ADDRESS(id, name) COMPARE_FIELD(name)
#define COMPARE_LIST(name) \
@@ -317,6 +318,7 @@ struct Hasher {
#define DELEGATE_FIELD_NAME(id, name) visitNonScopeName(cast->name)
#define DELEGATE_FIELD_TYPE(id, name) visitType(cast->name);
+#define DELEGATE_FIELD_HEAPTYPE(id, name) visitHeapType(cast->name);
#define DELEGATE_FIELD_ADDRESS(id, name) visitAddress(cast->name);
// Note that we only note the scope name, but do not also visit it. That means
@@ -359,6 +361,7 @@ struct Hasher {
}
void visitNonScopeName(Name curr) { rehash(digest, uint64_t(curr.str)); }
void visitType(Type curr) { rehash(digest, curr.getID()); }
+ void visitHeapType(HeapType curr) { rehash(digest, curr.getID()); }
void visitAddress(Address curr) { rehash(digest, curr.addr); }
};
diff --git a/src/ir/ExpressionManipulator.cpp b/src/ir/ExpressionManipulator.cpp
index 0bb94a66d..8ae3ddc1c 100644
--- a/src/ir/ExpressionManipulator.cpp
+++ b/src/ir/ExpressionManipulator.cpp
@@ -81,6 +81,7 @@ flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) {
#define DELEGATE_FIELD_SCOPE_NAME_USE(id, name) COPY_FIELD(name)
#define DELEGATE_FIELD_SIGNATURE(id, name) COPY_FIELD(name)
#define DELEGATE_FIELD_TYPE(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_HEAPTYPE(id, name) COPY_FIELD(name)
#define DELEGATE_FIELD_ADDRESS(id, name) COPY_FIELD(name)
#define COPY_FIELD_LIST(name) \
diff --git a/src/ir/branch-utils.h b/src/ir/branch-utils.h
index 54a3f1c16..f2fa43f18 100644
--- a/src/ir/branch-utils.h
+++ b/src/ir/branch-utils.h
@@ -62,6 +62,7 @@ template<typename T> void operateOnScopeNameUses(Expression* expr, T func) {
#define DELEGATE_FIELD_SCOPE_NAME_DEF(id, name)
#define DELEGATE_FIELD_SIGNATURE(id, name)
#define DELEGATE_FIELD_TYPE(id, name)
+#define DELEGATE_FIELD_HEAPTYPE(id, name)
#define DELEGATE_FIELD_ADDRESS(id, name)
#define DELEGATE_FIELD_CHILD_VECTOR(id, name)
#define DELEGATE_FIELD_INT_ARRAY(id, name)
@@ -125,6 +126,7 @@ template<typename T> void operateOnScopeNameDefs(Expression* expr, T func) {
#define DELEGATE_FIELD_NAME_VECTOR(id, name)
#define DELEGATE_FIELD_SIGNATURE(id, name)
#define DELEGATE_FIELD_TYPE(id, name)
+#define DELEGATE_FIELD_HEAPTYPE(id, name)
#define DELEGATE_FIELD_ADDRESS(id, name)
#define DELEGATE_FIELD_CHILD_VECTOR(id, name)
#define DELEGATE_FIELD_INT_ARRAY(id, name)
diff --git a/src/ir/cost.h b/src/ir/cost.h
index 086b7b9af..29fcb8dd4 100644
--- a/src/ir/cost.h
+++ b/src/ir/cost.h
@@ -593,7 +593,7 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
// at least some baseline cost, plus writing the fields. (If we use default
// values for the fields, then it is possible they are all 0 and if so, we
// can get that almost for free as well, so don't add anything there.)
- CostType ret = 4 + visit(curr->rtt) + curr->operands.size();
+ CostType ret = 4 + maybeVisit(curr->rtt) + curr->operands.size();
for (auto* child : curr->operands) {
ret += visit(child);
}
@@ -606,10 +606,11 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
return 2 + nullCheckCost(curr->ref) + visit(curr->ref) + visit(curr->value);
}
CostType visitArrayNew(ArrayNew* curr) {
- return 4 + visit(curr->rtt) + visit(curr->size) + maybeVisit(curr->init);
+ return 4 + maybeVisit(curr->rtt) + visit(curr->size) +
+ maybeVisit(curr->init);
}
CostType visitArrayInit(ArrayInit* curr) {
- CostType ret = 4 + visit(curr->rtt);
+ CostType ret = 4 + maybeVisit(curr->rtt);
for (auto* child : curr->values) {
ret += visit(child);
}
diff --git a/src/ir/iteration.h b/src/ir/iteration.h
index 3de6d1435..19bc44af1 100644
--- a/src/ir/iteration.h
+++ b/src/ir/iteration.h
@@ -98,6 +98,7 @@ public:
#define DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name)
#define DELEGATE_FIELD_SIGNATURE(id, name)
#define DELEGATE_FIELD_TYPE(id, name)
+#define DELEGATE_FIELD_HEAPTYPE(id, name)
#define DELEGATE_FIELD_ADDRESS(id, name)
#include "wasm-delegations-fields.def"
diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h
index d191a35f1..5d23278fa 100644
--- a/src/ir/module-utils.h
+++ b/src/ir/module-utils.h
@@ -497,6 +497,34 @@ inline void collectHeapTypes(Module& wasm,
counts.note(curr->type);
} else if (curr->is<RttCanon>() || curr->is<RttSub>()) {
counts.note(curr->type.getRtt().heapType);
+ } else if (auto* make = curr->dynCast<StructNew>()) {
+ // Some operations emit a HeapType in the binary format, if they are
+ // static and not dynamic (if dynamic, the RTT provides the heap type).
+ if (!make->rtt && make->type != Type::unreachable) {
+ counts.note(make->type.getHeapType());
+ }
+ } else if (auto* make = curr->dynCast<ArrayNew>()) {
+ if (!make->rtt && make->type != Type::unreachable) {
+ counts.note(make->type.getHeapType());
+ }
+ } else if (auto* make = curr->dynCast<ArrayInit>()) {
+ if (!make->rtt && make->type != Type::unreachable) {
+ counts.note(make->type.getHeapType());
+ }
+ } else if (auto* cast = curr->dynCast<RefCast>()) {
+ if (!cast->rtt && cast->type != Type::unreachable) {
+ counts.note(cast->getIntendedType());
+ }
+ } else if (auto* cast = curr->dynCast<RefTest>()) {
+ if (!cast->rtt && cast->type != Type::unreachable) {
+ counts.note(cast->getIntendedType());
+ }
+ } else if (auto* cast = curr->dynCast<BrOn>()) {
+ if (cast->op == BrOnCast || cast->op == BrOnCastFail) {
+ if (!cast->rtt && cast->type != Type::unreachable) {
+ counts.note(cast->getIntendedType());
+ }
+ }
} else if (auto* get = curr->dynCast<StructGet>()) {
counts.note(get->ref->type);
} else if (auto* set = curr->dynCast<StructSet>()) {
diff --git a/src/ir/properties.h b/src/ir/properties.h
index f3cab1fdc..841d154f7 100644
--- a/src/ir/properties.h
+++ b/src/ir/properties.h
@@ -340,6 +340,7 @@ inline Index getNumChildren(Expression* curr) {
#define DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name)
#define DELEGATE_FIELD_SIGNATURE(id, name)
#define DELEGATE_FIELD_TYPE(id, name)
+#define DELEGATE_FIELD_HEAPTYPE(id, name)
#define DELEGATE_FIELD_ADDRESS(id, name)
#include "wasm-delegations-fields.def"
diff --git a/src/literal.h b/src/literal.h
index f7ce78f7a..6f2267752 100644
--- a/src/literal.h
+++ b/src/literal.h
@@ -61,6 +61,8 @@ class Literal {
// as the Literal class itself.
// To support the experimental RttFreshSub instruction, we not only store
// the type, but also a reference to an allocation.
+ // The above describes dynamic data, that is with an actual RTT. The static
+ // case just has a static type in its GCData.
// See struct RttSuper below for more details.
std::unique_ptr<RttSupers> rttSupers;
// TODO: Literals of type `externref` can only be `null` currently but we
@@ -694,10 +696,16 @@ std::ostream& operator<<(std::ostream& o, wasm::Literal literal);
std::ostream& operator<<(std::ostream& o, wasm::Literals literals);
// A GC Struct or Array is a set of values with a run-time type saying what it
-// is.
+// is. In the case of static (rtt-free) typing, the rtt is not present and
+// instead we have a static type.
struct GCData {
+ // Either the RTT or the type must be present, but not both.
Literal rtt;
+ HeapType type;
+
Literals values;
+
+ GCData(HeapType type, Literals values) : type(type), values(values) {}
GCData(Literal rtt, Literals values) : rtt(rtt), values(values) {}
};
diff --git a/src/passes/Heap2Local.cpp b/src/passes/Heap2Local.cpp
index f2846671c..796e0fa05 100644
--- a/src/passes/Heap2Local.cpp
+++ b/src/passes/Heap2Local.cpp
@@ -402,7 +402,9 @@ struct Heap2LocalOptimizer {
}
// Drop the RTT (as it may have side effects; leave it to other passes).
- contents.push_back(builder.makeDrop(allocation->rtt));
+ if (allocation->rtt) {
+ contents.push_back(builder.makeDrop(allocation->rtt));
+ }
// Replace the allocation with a null reference. This changes the type
// from non-nullable to nullable, but as we optimize away the code that
// the allocation reaches, we will handle that.
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 6198218d8..6a41961a2 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -1985,15 +1985,18 @@ struct PrintExpressionContents
}
void visitStructNew(StructNew* curr) {
- if (printUnreachableReplacement(curr->rtt)) {
+ if (printUnreachableReplacement(curr)) {
return;
}
- printMedium(o, "struct.new_");
+ printMedium(o, "struct.new");
if (curr->isWithDefault()) {
- o << "default_";
+ printMedium(o, "_default");
}
- o << "with_rtt ";
- TypeNamePrinter(o, wasm).print(curr->rtt->type.getHeapType());
+ if (curr->rtt) {
+ printMedium(o, "_with_rtt");
+ }
+ o << ' ';
+ TypeNamePrinter(o, wasm).print(curr->type.getHeapType());
}
void printFieldName(HeapType type, Index index) {
@@ -2035,16 +2038,29 @@ struct PrintExpressionContents
printFieldName(heapType, curr->index);
}
void visitArrayNew(ArrayNew* curr) {
- printMedium(o, "array.new_");
+ if (printUnreachableReplacement(curr)) {
+ return;
+ }
+ printMedium(o, "array.new");
if (curr->isWithDefault()) {
- o << "default_";
+ printMedium(o, "_default");
+ }
+ if (curr->rtt) {
+ printMedium(o, "_with_rtt");
}
- o << "with_rtt ";
- TypeNamePrinter(o, wasm).print(curr->rtt->type.getHeapType());
+ o << ' ';
+ TypeNamePrinter(o, wasm).print(curr->type.getHeapType());
}
void visitArrayInit(ArrayInit* curr) {
- printMedium(o, "array.init ");
- TypeNamePrinter(o, wasm).print(curr->rtt->type.getHeapType());
+ if (printUnreachableReplacement(curr)) {
+ return;
+ }
+ printMedium(o, "array.init");
+ if (!curr->rtt) {
+ printMedium(o, "_static");
+ }
+ o << ' ';
+ TypeNamePrinter(o, wasm).print(curr->type.getHeapType());
}
void visitArrayGet(ArrayGet* curr) {
if (printUnreachableReplacement(curr->ref)) {
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 0e4b4b873..057a2a981 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -1052,6 +1052,8 @@ enum ASTNodes {
StructGetS = 0x04,
StructGetU = 0x05,
StructSet = 0x06,
+ StructNew = 0x07,
+ StructNewDefault = 0x08,
ArrayNewWithRtt = 0x11,
ArrayNewDefaultWithRtt = 0x12,
ArrayGet = 0x13,
@@ -1061,6 +1063,9 @@ enum ASTNodes {
ArrayLen = 0x17,
ArrayCopy = 0x18,
ArrayInit = 0x19,
+ ArrayInitStatic = 0x1a,
+ ArrayNew = 0x1b,
+ ArrayNewDefault = 0x1c,
I31New = 0x20,
I31GetS = 0x21,
I31GetU = 0x22,
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 346f2f5ba..f992b1e03 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -836,6 +836,13 @@ public:
ret->finalize();
return ret;
}
+ template<typename T> StructNew* makeStructNew(HeapType type, const T& args) {
+ auto* ret = wasm.allocator.alloc<StructNew>();
+ ret->operands.set(args);
+ ret->type = Type(type, NonNullable);
+ ret->finalize();
+ return ret;
+ }
StructGet*
makeStructGet(Index index, Expression* ref, Type type, bool signed_ = false) {
auto* ret = wasm.allocator.alloc<StructGet>();
@@ -863,6 +870,15 @@ public:
ret->finalize();
return ret;
}
+ ArrayNew*
+ makeArrayNew(HeapType type, Expression* size, Expression* init = nullptr) {
+ auto* ret = wasm.allocator.alloc<ArrayNew>();
+ ret->size = size;
+ ret->init = init;
+ ret->type = Type(type, NonNullable);
+ ret->finalize();
+ return ret;
+ }
ArrayInit* makeArrayInit(Expression* rtt,
const std::vector<Expression*>& values) {
auto* ret = wasm.allocator.alloc<ArrayInit>();
@@ -871,6 +887,14 @@ public:
ret->finalize();
return ret;
}
+ ArrayInit* makeArrayInit(HeapType type,
+ const std::vector<Expression*>& values) {
+ auto* ret = wasm.allocator.alloc<ArrayInit>();
+ ret->values.set(values);
+ ret->type = Type(type, NonNullable);
+ ret->finalize();
+ return ret;
+ }
ArrayGet*
makeArrayGet(Expression* ref, Expression* index, bool signed_ = false) {
auto* ret = wasm.allocator.alloc<ArrayGet>();
diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def
index 459f80afb..f5524d181 100644
--- a/src/wasm-delegations-fields.def
+++ b/src/wasm-delegations-fields.def
@@ -614,7 +614,7 @@ switch (DELEGATE_ID) {
}
case Expression::Id::StructNewId: {
DELEGATE_START(StructNew);
- DELEGATE_FIELD_CHILD(StructNew, rtt);
+ DELEGATE_FIELD_OPTIONAL_CHILD(StructNew, rtt);
DELEGATE_FIELD_CHILD_VECTOR(StructNew, operands);
DELEGATE_END(StructNew);
break;
@@ -637,7 +637,7 @@ switch (DELEGATE_ID) {
}
case Expression::Id::ArrayNewId: {
DELEGATE_START(ArrayNew);
- DELEGATE_FIELD_CHILD(ArrayNew, rtt);
+ DELEGATE_FIELD_OPTIONAL_CHILD(ArrayNew, rtt);
DELEGATE_FIELD_CHILD(ArrayNew, size);
DELEGATE_FIELD_OPTIONAL_CHILD(ArrayNew, init);
DELEGATE_END(ArrayNew);
@@ -645,7 +645,7 @@ switch (DELEGATE_ID) {
}
case Expression::Id::ArrayInitId: {
DELEGATE_START(ArrayInit);
- DELEGATE_FIELD_CHILD(ArrayInit, rtt);
+ DELEGATE_FIELD_OPTIONAL_CHILD(ArrayInit, rtt);
DELEGATE_FIELD_CHILD_VECTOR(ArrayInit, values);
DELEGATE_END(ArrayInit);
break;
@@ -707,5 +707,6 @@ switch (DELEGATE_ID) {
#undef DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR
#undef DELEGATE_FIELD_SIGNATURE
#undef DELEGATE_FIELD_TYPE
+#undef DELEGATE_FIELD_HEAPTYPE
#undef DELEGATE_FIELD_ADDRESS
#undef DELEGATE_GET_FIELD
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 53d3048b7..4e2d40e08 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1483,8 +1483,8 @@ public:
// GC data store an RTT in each instance.
assert(cast.originalRef.isData());
auto gcData = cast.originalRef.getGCData();
- Literal seenRtt = gcData->rtt;
if (curr->rtt) {
+ Literal seenRtt = gcData->rtt;
if (!seenRtt.isSubRtt(intendedRtt)) {
cast.outcome = cast.Failure;
return cast;
@@ -1492,7 +1492,7 @@ public:
cast.castRef =
Literal(gcData, Type(intendedRtt.type.getHeapType(), NonNullable));
} else {
- auto seenType = seenRtt.type.getHeapType();
+ auto seenType = gcData->type;
if (!HeapType::isSubType(seenType, curr->intendedType)) {
cast.outcome = cast.Failure;
return cast;
@@ -1628,13 +1628,42 @@ public:
}
return Literal(std::move(newSupers), curr->type);
}
+
+ // Generates GC data for either dynamic (with an RTT) or static (with a type)
+ // typing. Dynamic typing will provide an rtt expression and an rtt flow with
+ // the value, while static typing only provides a heap type directly.
+ template<typename T>
+ std::shared_ptr<GCData>
+ makeGCData(Expression* rttExpr, Flow& rttFlow, HeapType type, T& data) {
+ if (rttExpr) {
+ return std::make_shared<GCData>(rttFlow.getSingleValue(), data);
+ } else {
+ return std::make_shared<GCData>(type, data);
+ }
+ }
+
Flow visitStructNew(StructNew* curr) {
NOTE_ENTER("StructNew");
- auto rtt = this->visit(curr->rtt);
- if (rtt.breaking()) {
- return rtt;
+ Flow rtt;
+ if (curr->rtt) {
+ rtt = this->visit(curr->rtt);
+ if (rtt.breaking()) {
+ return rtt;
+ }
+ }
+ if (curr->type == Type::unreachable) {
+ // We cannot proceed to compute the heap type, as there isn't one. Just
+ // find why we are unreachable, and stop there.
+ for (auto* operand : curr->operands) {
+ auto value = this->visit(operand);
+ if (value.breaking()) {
+ return value;
+ }
+ }
+ WASM_UNREACHABLE("unreachable but no unreachable child");
}
- const auto& fields = curr->rtt->type.getHeapType().getStruct().fields;
+ auto heapType = curr->type.getHeapType();
+ const auto& fields = heapType.getStruct().fields;
Literals data(fields.size());
for (Index i = 0; i < fields.size(); i++) {
if (curr->isWithDefault()) {
@@ -1647,8 +1676,8 @@ public:
data[i] = value.getSingleValue();
}
}
- return Flow(Literal(std::make_shared<GCData>(rtt.getSingleValue(), data),
- curr->type));
+ return Flow(
+ Literal(makeGCData(curr->rtt, rtt, heapType, data), curr->type));
}
Flow visitStructGet(StructGet* curr) {
NOTE_ENTER("StructGet");
@@ -1691,15 +1720,26 @@ public:
Flow visitArrayNew(ArrayNew* curr) {
NOTE_ENTER("ArrayNew");
- auto rtt = this->visit(curr->rtt);
- if (rtt.breaking()) {
- return rtt;
+ Flow rtt;
+ if (curr->rtt) {
+ rtt = this->visit(curr->rtt);
+ if (rtt.breaking()) {
+ return rtt;
+ }
}
auto size = this->visit(curr->size);
if (size.breaking()) {
return size;
}
- const auto& element = curr->rtt->type.getHeapType().getArray().element;
+ if (curr->type == Type::unreachable) {
+ // We cannot proceed to compute the heap type, as there isn't one. Just
+ // visit the unreachable child, and stop there.
+ auto init = this->visit(curr->init);
+ assert(init.breaking());
+ return init;
+ }
+ auto heapType = curr->type.getHeapType();
+ const auto& element = heapType.getArray().element;
Index num = size.getSingleValue().geti32();
if (num >= ArrayLimit) {
hostLimit("allocation failure");
@@ -1720,20 +1760,35 @@ public:
data[i] = value;
}
}
- return Flow(Literal(std::make_shared<GCData>(rtt.getSingleValue(), data),
- curr->type));
+ return Flow(
+ Literal(makeGCData(curr->rtt, rtt, heapType, data), curr->type));
}
Flow visitArrayInit(ArrayInit* curr) {
NOTE_ENTER("ArrayInit");
- auto rtt = this->visit(curr->rtt);
- if (rtt.breaking()) {
- return rtt;
+ Flow rtt;
+ if (curr->rtt) {
+ rtt = this->visit(curr->rtt);
+ if (rtt.breaking()) {
+ return rtt;
+ }
}
Index num = curr->values.size();
if (num >= ArrayLimit) {
hostLimit("allocation failure");
}
- auto field = curr->type.getHeapType().getArray().element;
+ if (curr->type == Type::unreachable) {
+ // We cannot proceed to compute the heap type, as there isn't one. Just
+ // find why we are unreachable, and stop there.
+ for (auto* value : curr->values) {
+ auto result = this->visit(value);
+ if (result.breaking()) {
+ return result;
+ }
+ }
+ WASM_UNREACHABLE("unreachable but no unreachable child");
+ }
+ auto heapType = curr->type.getHeapType();
+ auto field = heapType.getArray().element;
Literals data(num);
for (Index i = 0; i < num; i++) {
auto value = this->visit(curr->values[i]);
@@ -1742,8 +1797,8 @@ public:
}
data[i] = truncateForPacking(value.getSingleValue(), field);
}
- return Flow(Literal(std::make_shared<GCData>(rtt.getSingleValue(), data),
- curr->type));
+ return Flow(
+ Literal(makeGCData(curr->rtt, rtt, heapType, data), curr->type));
}
Flow visitArrayGet(ArrayGet* curr) {
NOTE_ENTER("ArrayGet");
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index f195314b1..ef677cbf7 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -284,11 +284,14 @@ private:
Expression* makeRttSub(Element& s);
Expression* makeRttFreshSub(Element& s);
Expression* makeStructNew(Element& s, bool default_);
+ Expression* makeStructNewStatic(Element& s, bool default_);
Index getStructIndex(Element& type, Element& field);
Expression* makeStructGet(Element& s, bool signed_ = false);
Expression* makeStructSet(Element& s);
Expression* makeArrayNew(Element& s, bool default_);
+ Expression* makeArrayNewStatic(Element& s, bool default_);
Expression* makeArrayInit(Element& s);
+ Expression* makeArrayInitStatic(Element& s);
Expression* makeArrayGet(Element& s, bool signed_ = false);
Expression* makeArraySet(Element& s);
Expression* makeArrayLen(Element& s);
diff --git a/src/wasm.h b/src/wasm.h
index ffc97f71e..9c6062e48 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -1438,7 +1438,10 @@ class StructNew : public SpecificExpression<Expression::StructNewId> {
public:
StructNew(MixedArena& allocator) : operands(allocator) {}
- Expression* rtt;
+ // A dynamic StructNew has an rtt, while a static one declares the type using
+ // the type field.
+ Expression* rtt = nullptr;
+
// A struct.new_with_default has empty operands. This does leave the case of a
// struct with no fields ambiguous, but it doesn't make a difference in that
// case, and binaryen doesn't guarantee roundtripping binaries anyhow.
@@ -1481,7 +1484,10 @@ public:
// used.
Expression* init = nullptr;
Expression* size;
- Expression* rtt;
+
+ // A dynamic ArrayNew has an rtt, while a static one declares the type using
+ // the type field.
+ Expression* rtt = nullptr;
bool isWithDefault() { return !init; }
@@ -1493,7 +1499,10 @@ public:
ArrayInit(MixedArena& allocator) : values(allocator) {}
ExpressionList values;
- Expression* rtt;
+
+ // A dynamic ArrayInit has an rtt, while a static one declares the type using
+ // the type field.
+ Expression* rtt = nullptr;
void finalize();
};
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index e1ff43988..74895c868 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -6527,23 +6527,36 @@ bool WasmBinaryBuilder::maybeVisitRttSub(Expression*& out, uint32_t code) {
}
bool WasmBinaryBuilder::maybeVisitStructNew(Expression*& out, uint32_t code) {
- if (code != BinaryConsts::StructNewWithRtt &&
- code != BinaryConsts::StructNewDefaultWithRtt) {
- return false;
- }
- auto heapType = getIndexedHeapType();
- auto* rtt = popNonVoidExpression();
- validateHeapTypeUsingChild(rtt, heapType);
- std::vector<Expression*> operands;
- if (code == BinaryConsts::StructNewWithRtt) {
- auto numOperands = heapType.getStruct().fields.size();
- operands.resize(numOperands);
- for (Index i = 0; i < numOperands; i++) {
- operands[numOperands - i - 1] = popNonVoidExpression();
+ if (code == BinaryConsts::StructNew ||
+ code == BinaryConsts::StructNewDefault) {
+ auto heapType = getIndexedHeapType();
+ std::vector<Expression*> operands;
+ if (code == BinaryConsts::StructNew) {
+ auto numOperands = heapType.getStruct().fields.size();
+ operands.resize(numOperands);
+ for (Index i = 0; i < numOperands; i++) {
+ operands[numOperands - i - 1] = popNonVoidExpression();
+ }
+ }
+ out = Builder(wasm).makeStructNew(heapType, operands);
+ return true;
+ } else if (code == BinaryConsts::StructNewWithRtt ||
+ code == BinaryConsts::StructNewDefaultWithRtt) {
+ auto heapType = getIndexedHeapType();
+ auto* rtt = popNonVoidExpression();
+ validateHeapTypeUsingChild(rtt, heapType);
+ std::vector<Expression*> operands;
+ if (code == BinaryConsts::StructNewWithRtt) {
+ auto numOperands = heapType.getStruct().fields.size();
+ operands.resize(numOperands);
+ for (Index i = 0; i < numOperands; i++) {
+ operands[numOperands - i - 1] = popNonVoidExpression();
+ }
}
+ out = Builder(wasm).makeStructNew(rtt, operands);
+ return true;
}
- out = Builder(wasm).makeStructNew(rtt, operands);
- return true;
+ return false;
}
bool WasmBinaryBuilder::maybeVisitStructGet(Expression*& out, uint32_t code) {
@@ -6588,36 +6601,54 @@ bool WasmBinaryBuilder::maybeVisitStructSet(Expression*& out, uint32_t code) {
}
bool WasmBinaryBuilder::maybeVisitArrayNew(Expression*& out, uint32_t code) {
- if (code != BinaryConsts::ArrayNewWithRtt &&
- code != BinaryConsts::ArrayNewDefaultWithRtt) {
- return false;
+ if (code == BinaryConsts::ArrayNew || code == BinaryConsts::ArrayNewDefault) {
+ auto heapType = getIndexedHeapType();
+ auto* size = popNonVoidExpression();
+ Expression* init = nullptr;
+ if (code == BinaryConsts::ArrayNew) {
+ init = popNonVoidExpression();
+ }
+ out = Builder(wasm).makeArrayNew(heapType, size, init);
+ return true;
+ } else if (code == BinaryConsts::ArrayNewWithRtt ||
+ code == BinaryConsts::ArrayNewDefaultWithRtt) {
+ auto heapType = getIndexedHeapType();
+ auto* rtt = popNonVoidExpression();
+ validateHeapTypeUsingChild(rtt, heapType);
+ auto* size = popNonVoidExpression();
+ Expression* init = nullptr;
+ if (code == BinaryConsts::ArrayNewWithRtt) {
+ init = popNonVoidExpression();
+ }
+ out = Builder(wasm).makeArrayNew(rtt, size, init);
+ return true;
}
- auto heapType = getIndexedHeapType();
- auto* rtt = popNonVoidExpression();
- validateHeapTypeUsingChild(rtt, heapType);
- auto* size = popNonVoidExpression();
- Expression* init = nullptr;
- if (code == BinaryConsts::ArrayNewWithRtt) {
- init = popNonVoidExpression();
- }
- out = Builder(wasm).makeArrayNew(rtt, size, init);
- return true;
+ return false;
}
bool WasmBinaryBuilder::maybeVisitArrayInit(Expression*& out, uint32_t code) {
- if (code != BinaryConsts::ArrayInit) {
- return false;
- }
- auto heapType = getIndexedHeapType();
- auto size = getU32LEB();
- auto* rtt = popNonVoidExpression();
- validateHeapTypeUsingChild(rtt, heapType);
- std::vector<Expression*> values(size);
- for (size_t i = 0; i < size; i++) {
- values[size - i - 1] = popNonVoidExpression();
+ if (code == BinaryConsts::ArrayInitStatic) {
+ auto heapType = getIndexedHeapType();
+ auto size = getU32LEB();
+ std::vector<Expression*> values(size);
+ for (size_t i = 0; i < size; i++) {
+ values[size - i - 1] = popNonVoidExpression();
+ }
+ out = Builder(wasm).makeArrayInit(heapType, values);
+ return true;
+ } else if (code == BinaryConsts::ArrayInit) {
+ auto heapType = getIndexedHeapType();
+ auto size = getU32LEB();
+ auto* rtt = popNonVoidExpression();
+ validateHeapTypeUsingChild(rtt, heapType);
+ std::vector<Expression*> values(size);
+ for (size_t i = 0; i < size; i++) {
+ values[size - i - 1] = popNonVoidExpression();
+ }
+ out = Builder(wasm).makeArrayInit(rtt, values);
+ return true;
}
- out = Builder(wasm).makeArrayInit(rtt, values);
- return true;
+ return false;
}
bool WasmBinaryBuilder::maybeVisitArrayGet(Expression*& out, uint32_t code) {
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 697e4e58d..e9ea6aaa5 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -2652,6 +2652,21 @@ Expression* SExpressionWasmBuilder::makeStructNew(Element& s, bool default_) {
return Builder(wasm).makeStructNew(rtt, operands);
}
+Expression* SExpressionWasmBuilder::makeStructNewStatic(Element& s,
+ bool default_) {
+ auto heapType = parseHeapType(*s[1]);
+ auto numOperands = s.size() - 2;
+ if (default_ && numOperands > 0) {
+ throw ParseException("arguments provided for struct.new", s.line, s.col);
+ }
+ std::vector<Expression*> operands;
+ operands.resize(numOperands);
+ for (Index i = 0; i < numOperands; i++) {
+ operands[i] = parseExpression(*s[i + 2]);
+ }
+ return Builder(wasm).makeStructNew(heapType, operands);
+}
+
Index SExpressionWasmBuilder::getStructIndex(Element& type, Element& field) {
if (field.dollared()) {
auto name = field.str();
@@ -2708,6 +2723,18 @@ Expression* SExpressionWasmBuilder::makeArrayNew(Element& s, bool default_) {
return Builder(wasm).makeArrayNew(rtt, size, init);
}
+Expression* SExpressionWasmBuilder::makeArrayNewStatic(Element& s,
+ bool default_) {
+ auto heapType = parseHeapType(*s[1]);
+ Expression* init = nullptr;
+ size_t i = 2;
+ if (!default_) {
+ init = parseExpression(*s[i++]);
+ }
+ auto* size = parseExpression(*s[i++]);
+ return Builder(wasm).makeArrayNew(heapType, size, init);
+}
+
Expression* SExpressionWasmBuilder::makeArrayInit(Element& s) {
auto heapType = parseHeapType(*s[1]);
size_t i = 2;
@@ -2720,6 +2747,16 @@ Expression* SExpressionWasmBuilder::makeArrayInit(Element& s) {
return Builder(wasm).makeArrayInit(rtt, values);
}
+Expression* SExpressionWasmBuilder::makeArrayInitStatic(Element& s) {
+ auto heapType = parseHeapType(*s[1]);
+ size_t i = 2;
+ std::vector<Expression*> values;
+ while (i < s.size()) {
+ values.push_back(parseExpression(*s[i++]));
+ }
+ return Builder(wasm).makeArrayInit(heapType, values);
+}
+
Expression* SExpressionWasmBuilder::makeArrayGet(Element& s, bool signed_) {
auto heapType = parseHeapType(*s[1]);
auto ref = parseExpression(*s[2]);
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index b6424cdde..70b52cfbb 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -2025,12 +2025,20 @@ void BinaryInstWriter::visitRttSub(RttSub* curr) {
void BinaryInstWriter::visitStructNew(StructNew* curr) {
o << int8_t(BinaryConsts::GCPrefix);
- if (curr->isWithDefault()) {
- o << U32LEB(BinaryConsts::StructNewDefaultWithRtt);
+ if (curr->rtt) {
+ if (curr->isWithDefault()) {
+ o << U32LEB(BinaryConsts::StructNewDefaultWithRtt);
+ } else {
+ o << U32LEB(BinaryConsts::StructNewWithRtt);
+ }
} else {
- o << U32LEB(BinaryConsts::StructNewWithRtt);
+ if (curr->isWithDefault()) {
+ o << U32LEB(BinaryConsts::StructNewDefault);
+ } else {
+ o << U32LEB(BinaryConsts::StructNew);
+ }
}
- parent.writeIndexedHeapType(curr->rtt->type.getHeapType());
+ parent.writeIndexedHeapType(curr->type.getHeapType());
}
void BinaryInstWriter::visitStructGet(StructGet* curr) {
@@ -2057,17 +2065,30 @@ void BinaryInstWriter::visitStructSet(StructSet* curr) {
void BinaryInstWriter::visitArrayNew(ArrayNew* curr) {
o << int8_t(BinaryConsts::GCPrefix);
- if (curr->isWithDefault()) {
- o << U32LEB(BinaryConsts::ArrayNewDefaultWithRtt);
+ if (curr->rtt) {
+ if (curr->isWithDefault()) {
+ o << U32LEB(BinaryConsts::ArrayNewDefaultWithRtt);
+ } else {
+ o << U32LEB(BinaryConsts::ArrayNewWithRtt);
+ }
} else {
- o << U32LEB(BinaryConsts::ArrayNewWithRtt);
+ if (curr->isWithDefault()) {
+ o << U32LEB(BinaryConsts::ArrayNewDefault);
+ } else {
+ o << U32LEB(BinaryConsts::ArrayNew);
+ }
}
- parent.writeIndexedHeapType(curr->rtt->type.getHeapType());
+ parent.writeIndexedHeapType(curr->type.getHeapType());
}
void BinaryInstWriter::visitArrayInit(ArrayInit* curr) {
- o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::ArrayInit);
- parent.writeIndexedHeapType(curr->rtt->type.getHeapType());
+ o << int8_t(BinaryConsts::GCPrefix);
+ if (curr->rtt) {
+ o << U32LEB(BinaryConsts::ArrayInit);
+ } else {
+ o << U32LEB(BinaryConsts::ArrayInitStatic);
+ }
+ parent.writeIndexedHeapType(curr->type.getHeapType());
o << U32LEB(curr->values.size());
}
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 1f6421609..d03fc2446 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2332,11 +2332,19 @@ void FunctionValidator::visitStructNew(StructNew* curr) {
if (curr->type == Type::unreachable) {
return;
}
- if (!shouldBeTrue(
- curr->rtt->type.isRtt(), curr, "struct.new rtt must be rtt")) {
- return;
+ if (curr->rtt) {
+ if (!shouldBeTrue(
+ curr->rtt->type.isRtt(), curr, "struct.new rtt must be rtt")) {
+ return;
+ }
+ }
+ auto heapType = curr->type.getHeapType();
+ if (curr->rtt) {
+ shouldBeEqual(curr->rtt->type.getHeapType(),
+ heapType,
+ curr,
+ "struct.new heap type must match rtt");
}
- auto heapType = curr->rtt->type.getHeapType();
if (!shouldBeTrue(
heapType.isStruct(), curr, "struct.new heap type must be struct")) {
return;
@@ -2428,11 +2436,19 @@ void FunctionValidator::visitArrayNew(ArrayNew* curr) {
if (curr->type == Type::unreachable) {
return;
}
- if (!shouldBeTrue(
- curr->rtt->type.isRtt(), curr, "array.new rtt must be rtt")) {
- return;
+ if (curr->rtt) {
+ if (!shouldBeTrue(
+ curr->rtt->type.isRtt(), curr, "array.new rtt must be rtt")) {
+ return;
+ }
+ }
+ auto heapType = curr->type.getHeapType();
+ if (curr->rtt) {
+ shouldBeEqual(curr->rtt->type.getHeapType(),
+ heapType,
+ curr,
+ "array.new heap type must match rtt");
}
- auto heapType = curr->rtt->type.getHeapType();
if (!shouldBeTrue(
heapType.isArray(), curr, "array.new heap type must be array")) {
return;
@@ -2462,11 +2478,19 @@ void FunctionValidator::visitArrayInit(ArrayInit* curr) {
if (curr->type == Type::unreachable) {
return;
}
- if (!shouldBeTrue(
- curr->rtt->type.isRtt(), curr, "array.init rtt must be rtt")) {
- return;
+ if (curr->rtt) {
+ if (!shouldBeTrue(
+ curr->rtt->type.isRtt(), curr, "array.init rtt must be rtt")) {
+ return;
+ }
+ }
+ auto heapType = curr->type.getHeapType();
+ if (curr->rtt) {
+ shouldBeEqual(curr->rtt->type.getHeapType(),
+ heapType,
+ curr,
+ "array.init heap type must match rtt");
}
- auto heapType = curr->rtt->type.getHeapType();
if (!shouldBeTrue(
heapType.isArray(), curr, "array.init heap type must be array")) {
return;
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 0f1017e00..792e43cbe 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -1018,14 +1018,18 @@ void RttSub::finalize() {
}
void StructNew::finalize() {
- if (rtt->type == Type::unreachable) {
+ if (rtt && rtt->type == Type::unreachable) {
type = Type::unreachable;
return;
}
if (handleUnreachableOperands(this)) {
return;
}
- type = Type(rtt->type.getHeapType(), NonNullable);
+ // A dynamic StructNew infers the type from the rtt. A static one has the type
+ // already in the type field.
+ if (rtt) {
+ type = Type(rtt->type.getHeapType(), NonNullable);
+ }
}
void StructGet::finalize() {
@@ -1045,16 +1049,21 @@ void StructSet::finalize() {
}
void ArrayNew::finalize() {
- if (rtt->type == Type::unreachable || size->type == Type::unreachable ||
+ if ((rtt && rtt->type == Type::unreachable) ||
+ size->type == Type::unreachable ||
(init && init->type == Type::unreachable)) {
type = Type::unreachable;
return;
}
- type = Type(rtt->type.getHeapType(), NonNullable);
+ // A dynamic ArrayNew infers the type from the rtt. A static one has the type
+ // already in the type field.
+ if (rtt) {
+ type = Type(rtt->type.getHeapType(), NonNullable);
+ }
}
void ArrayInit::finalize() {
- if (rtt->type == Type::unreachable) {
+ if (rtt && rtt->type == Type::unreachable) {
type = Type::unreachable;
return;
}
@@ -1064,7 +1073,11 @@ void ArrayInit::finalize() {
return;
}
}
- type = Type(rtt->type.getHeapType(), NonNullable);
+ // A dynamic ArrayInit infers the type from the rtt. A static one has the type
+ // already in the type field.
+ if (rtt) {
+ type = Type(rtt->type.getHeapType(), NonNullable);
+ }
}
void ArrayGet::finalize() {