Skip to content

Commit da5035f

Browse files
authored
Remove basic reference types (WebAssembly#4802)
Basic reference types like `Type::funcref`, `Type::anyref`, etc. made it easy to accidentally forget to handle reference types with the same basic HeapTypes but the opposite nullability. In principle there is nothing special about the types with shorthands except in the binary and text formats. Removing these shorthands from the internal type representation by removing all basic reference types makes some code more complicated locally, but simplifies code globally and encourages properly handling both nullable and non-nullable reference types.
1 parent 1c53f7d commit da5035f

46 files changed

Lines changed: 591 additions & 871 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/asmjs/asm_v_wasm.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,6 @@ JsType wasmToJsType(Type type) {
3333
return JS_INT64;
3434
case Type::v128:
3535
WASM_UNREACHABLE("v128 not implemented yet");
36-
case Type::funcref:
37-
case Type::anyref:
38-
case Type::eqref:
39-
case Type::i31ref:
40-
case Type::dataref:
41-
WASM_UNREACHABLE("reference types are not supported by wasm2js");
4236
case Type::none:
4337
return JS_NONE;
4438
case Type::unreachable:
@@ -60,16 +54,6 @@ char getSig(Type type) {
6054
return 'd';
6155
case Type::v128:
6256
return 'V';
63-
case Type::funcref:
64-
return 'F';
65-
case Type::anyref:
66-
return 'A';
67-
case Type::eqref:
68-
return 'Q';
69-
case Type::i31ref:
70-
return 'I';
71-
case Type::dataref:
72-
return 'D';
7357
case Type::none:
7458
return 'v';
7559
case Type::unreachable:

src/binaryen-c.cpp

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,29 @@ static_assert(sizeof(BinaryenLiteral) == sizeof(Literal),
5151
BinaryenLiteral toBinaryenLiteral(Literal x) {
5252
BinaryenLiteral ret;
5353
ret.type = x.type.getID();
54+
if (x.type.isRef()) {
55+
auto heapType = x.type.getHeapType();
56+
if (heapType.isBasic()) {
57+
switch (heapType.getBasic()) {
58+
case HeapType::func:
59+
ret.func = x.isNull() ? nullptr : x.getFunc().c_str();
60+
break;
61+
case HeapType::any:
62+
case HeapType::eq:
63+
assert(x.isNull() && "unexpected non-null reference type literal");
64+
break;
65+
case HeapType::i31:
66+
case HeapType::data:
67+
case HeapType::string:
68+
case HeapType::stringview_wtf8:
69+
case HeapType::stringview_wtf16:
70+
case HeapType::stringview_iter:
71+
WASM_UNREACHABLE("TODO: reftypes");
72+
}
73+
return ret;
74+
}
75+
WASM_UNREACHABLE("TODO: reftypes");
76+
}
5477
TODO_SINGLE_COMPOUND(x.type);
5578
switch (x.type.getBasic()) {
5679
case Type::i32:
@@ -68,16 +91,6 @@ BinaryenLiteral toBinaryenLiteral(Literal x) {
6891
case Type::v128:
6992
memcpy(&ret.v128, x.getv128Ptr(), 16);
7093
break;
71-
case Type::funcref:
72-
ret.func = x.isNull() ? nullptr : x.getFunc().c_str();
73-
break;
74-
case Type::anyref:
75-
case Type::eqref:
76-
assert(x.isNull() && "unexpected non-null reference type literal");
77-
break;
78-
case Type::i31ref:
79-
case Type::dataref:
80-
WASM_UNREACHABLE("TODO: reftypes");
8194
case Type::none:
8295
case Type::unreachable:
8396
WASM_UNREACHABLE("unexpected type");
@@ -86,7 +99,30 @@ BinaryenLiteral toBinaryenLiteral(Literal x) {
8699
}
87100

88101
Literal fromBinaryenLiteral(BinaryenLiteral x) {
89-
switch (x.type) {
102+
auto type = Type(x.type);
103+
if (type.isRef()) {
104+
auto heapType = type.getHeapType();
105+
if (type.isNullable()) {
106+
return Literal::makeNull(heapType);
107+
}
108+
if (heapType.isBasic()) {
109+
switch (heapType.getBasic()) {
110+
case HeapType::func:
111+
return Literal::makeFunc(x.func);
112+
case HeapType::any:
113+
case HeapType::eq:
114+
case HeapType::i31:
115+
case HeapType::data:
116+
case HeapType::string:
117+
case HeapType::stringview_wtf8:
118+
case HeapType::stringview_wtf16:
119+
case HeapType::stringview_iter:
120+
WASM_UNREACHABLE("TODO: reftypes");
121+
}
122+
}
123+
}
124+
assert(type.isBasic());
125+
switch (type.getBasic()) {
90126
case Type::i32:
91127
return Literal(x.i32);
92128
case Type::i64:
@@ -97,14 +133,6 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) {
97133
return Literal(x.i64).castToF64();
98134
case Type::v128:
99135
return Literal(x.v128);
100-
case Type::funcref:
101-
return Literal::makeFunc(x.func);
102-
case Type::anyref:
103-
case Type::eqref:
104-
return Literal::makeNull(Type(x.type).getHeapType());
105-
case Type::i31ref:
106-
case Type::dataref:
107-
WASM_UNREACHABLE("TODO: reftypes");
108136
case Type::none:
109137
case Type::unreachable:
110138
WASM_UNREACHABLE("unexpected type");
@@ -137,12 +165,24 @@ BinaryenType BinaryenTypeInt64(void) { return Type::i64; }
137165
BinaryenType BinaryenTypeFloat32(void) { return Type::f32; }
138166
BinaryenType BinaryenTypeFloat64(void) { return Type::f64; }
139167
BinaryenType BinaryenTypeVec128(void) { return Type::v128; }
140-
BinaryenType BinaryenTypeFuncref(void) { return Type::funcref; }
141-
BinaryenType BinaryenTypeExternref(void) { return Type::anyref; }
142-
BinaryenType BinaryenTypeAnyref(void) { return Type::anyref; }
143-
BinaryenType BinaryenTypeEqref(void) { return Type::eqref; }
144-
BinaryenType BinaryenTypeI31ref(void) { return Type::i31ref; }
145-
BinaryenType BinaryenTypeDataref(void) { return Type::dataref; }
168+
BinaryenType BinaryenTypeFuncref(void) {
169+
return Type(HeapType::func, Nullable).getID();
170+
}
171+
BinaryenType BinaryenTypeExternref(void) {
172+
return Type(HeapType::any, Nullable).getID();
173+
}
174+
BinaryenType BinaryenTypeAnyref(void) {
175+
return Type(HeapType::any, Nullable).getID();
176+
}
177+
BinaryenType BinaryenTypeEqref(void) {
178+
return Type(HeapType::eq, Nullable).getID();
179+
}
180+
BinaryenType BinaryenTypeI31ref(void) {
181+
return Type(HeapType::i31, NonNullable).getID();
182+
}
183+
BinaryenType BinaryenTypeDataref(void) {
184+
return Type(HeapType::data, NonNullable).getID();
185+
}
146186
BinaryenType BinaryenTypeUnreachable(void) { return Type::unreachable; }
147187
BinaryenType BinaryenTypeAuto(void) { return uintptr_t(-1); }
148188

src/ir/abstract.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,6 @@ inline UnaryOp getUnary(Type type, Op op) {
121121
break;
122122
}
123123
case Type::v128:
124-
case Type::funcref:
125-
case Type::anyref:
126-
case Type::eqref:
127-
case Type::i31ref:
128-
case Type::dataref:
129124
case Type::none:
130125
case Type::unreachable: {
131126
return InvalidUnary;
@@ -293,11 +288,6 @@ inline BinaryOp getBinary(Type type, Op op) {
293288
break;
294289
}
295290
case Type::v128:
296-
case Type::funcref:
297-
case Type::anyref:
298-
case Type::eqref:
299-
case Type::i31ref:
300-
case Type::dataref:
301291
case Type::none:
302292
case Type::unreachable: {
303293
return InvalidBinary;

src/ir/module-splitting.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,11 @@ void TableSlotManager::addSlot(Name func, Slot slot) {
143143

144144
TableSlotManager::TableSlotManager(Module& module) : module(module) {
145145
// TODO: Reject or handle passive element segments
146-
auto it = std::find_if(module.tables.begin(),
147-
module.tables.end(),
148-
[&](std::unique_ptr<Table>& table) {
149-
return table->type == Type::funcref;
150-
});
146+
auto funcref = Type(HeapType::func, Nullable);
147+
auto it = std::find_if(
148+
module.tables.begin(),
149+
module.tables.end(),
150+
[&](std::unique_ptr<Table>& table) { return table->type == funcref; });
151151
if (it == module.tables.end()) {
152152
return;
153153
}
@@ -163,7 +163,7 @@ TableSlotManager::TableSlotManager(Module& module) : module(module) {
163163
// append new items at constant offsets after all existing items at constant
164164
// offsets.
165165
if (activeTableSegments.size() == 1 &&
166-
activeTableSegments[0]->type == Type::funcref &&
166+
activeTableSegments[0]->type == funcref &&
167167
!activeTableSegments[0]->offset->is<Const>()) {
168168
assert(activeTableSegments[0]->offset->is<GlobalGet>() &&
169169
"Unexpected initializer instruction");

src/ir/table-utils.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ bool usesExpressions(ElementSegment* curr, Module* module) {
7676
// declare a type that is a subtype of that, so it must use the post-MVP form
7777
// of using expressions.
7878
bool hasTableOfSpecializedType =
79-
curr->table.is() && module->getTable(curr->table)->type != Type::funcref;
79+
curr->table.is() &&
80+
module->getTable(curr->table)->type != Type(HeapType::func, Nullable);
8081

8182
return !allElementsRefFunc || hasTableOfSpecializedType;
8283
}

src/literal.h

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,12 @@ class Literal {
251251
static Literal makeNull(HeapType type) {
252252
return Literal(Type(type, Nullable));
253253
}
254-
static Literal makeFunc(Name func, Type type = Type::funcref) {
254+
static Literal makeFunc(Name func,
255+
Type type = Type(HeapType::func, Nullable)) {
255256
return Literal(func, type);
256257
}
257258
static Literal makeI31(int32_t value) {
258-
auto lit = Literal(Type::i31ref);
259+
auto lit = Literal(Type(HeapType::i31, NonNullable));
259260
lit.i32 = value & 0x7fffffff;
260261
return lit;
261262
}
@@ -753,20 +754,7 @@ struct RttSupers : std::vector<RttSuper> {};
753754
namespace std {
754755
template<> struct hash<wasm::Literal> {
755756
size_t operator()(const wasm::Literal& a) const {
756-
auto digest = wasm::hash(a.type.getID());
757-
auto hashRef = [&]() {
758-
assert(a.type.isRef());
759-
if (a.isNull()) {
760-
return digest;
761-
}
762-
if (a.type.isFunction()) {
763-
wasm::rehash(digest, a.getFunc());
764-
return digest;
765-
}
766-
// other non-null reference type literals cannot represent concrete
767-
// values, i.e. there is no concrete anyref or eqref other than null.
768-
WASM_UNREACHABLE("unexpected type");
769-
};
757+
auto digest = wasm::hash(a.type);
770758
if (a.type.isBasic()) {
771759
switch (a.type.getBasic()) {
772760
case wasm::Type::i32:
@@ -787,20 +775,25 @@ template<> struct hash<wasm::Literal> {
787775
wasm::rehash(digest, chunks[0]);
788776
wasm::rehash(digest, chunks[1]);
789777
return digest;
790-
case wasm::Type::funcref:
791-
case wasm::Type::anyref:
792-
case wasm::Type::eqref:
793-
case wasm::Type::dataref:
794-
return hashRef();
795-
case wasm::Type::i31ref:
796-
wasm::rehash(digest, a.geti31(true));
797-
return digest;
798778
case wasm::Type::none:
799779
case wasm::Type::unreachable:
800780
break;
801781
}
802782
} else if (a.type.isRef()) {
803-
return hashRef();
783+
if (a.isNull()) {
784+
return digest;
785+
}
786+
if (a.type.isFunction()) {
787+
wasm::rehash(digest, a.getFunc());
788+
return digest;
789+
}
790+
if (a.type.getHeapType() == wasm::HeapType::i31) {
791+
wasm::rehash(digest, a.geti31(true));
792+
return digest;
793+
}
794+
// other non-null reference type literals cannot represent concrete
795+
// values, i.e. there is no concrete anyref or eqref other than null.
796+
WASM_UNREACHABLE("unexpected type");
804797
} else if (a.type.isRtt()) {
805798
const auto& supers = a.getRttSupers();
806799
wasm::rehash(digest, supers.size());

src/passes/ConstHoisting.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,9 @@ struct ConstHoisting : public WalkerPass<PostWalker<ConstHoisting>> {
8989
size = value.type.getByteSize();
9090
break;
9191
}
92-
// not implemented yet
92+
// not implemented yet
9393
case Type::v128:
94-
case Type::funcref:
95-
case Type::anyref:
96-
case Type::eqref:
97-
case Type::i31ref:
98-
case Type::dataref: {
9994
return false;
100-
}
10195
case Type::none:
10296
case Type::unreachable:
10397
WASM_UNREACHABLE("unexpected type");

src/passes/FuncCastEmulation.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,6 @@ static Expression* toABI(Expression* value, Module* module) {
6262
case Type::v128: {
6363
WASM_UNREACHABLE("v128 not implemented yet");
6464
}
65-
case Type::funcref:
66-
case Type::anyref:
67-
case Type::eqref:
68-
case Type::i31ref:
69-
case Type::dataref: {
70-
WASM_UNREACHABLE("reference types cannot be converted to i64");
71-
}
7265
case Type::none: {
7366
// the value is none, but we need a value here
7467
value =
@@ -107,13 +100,6 @@ static Expression* fromABI(Expression* value, Type type, Module* module) {
107100
case Type::v128: {
108101
WASM_UNREACHABLE("v128 not implemented yet");
109102
}
110-
case Type::funcref:
111-
case Type::anyref:
112-
case Type::eqref:
113-
case Type::i31ref:
114-
case Type::dataref: {
115-
WASM_UNREACHABLE("reference types cannot be converted from i64");
116-
}
117103
case Type::none: {
118104
value = builder.makeDrop(value);
119105
break;

0 commit comments

Comments
 (0)