Skip to content

Commit 916ce6f

Browse files
authored
Update reference types (#3084)
Align with the current state of the reference types proposal: * Remove `nullref` * Remove `externref` and `funcref` subtyping * A `Literal` of a nullable reference type can now represent `null` (previously was type `nullref`) * Update the tests and temporarily comment out those tests relying on subtyping
1 parent 0fdcf5b commit 916ce6f

File tree

87 files changed

+2060
-1864
lines changed

Some content is hidden

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

87 files changed

+2060
-1864
lines changed

scripts/gen-s-parser.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
("v128.pop", "makePop(Type::v128)"),
5151
("funcref.pop", "makePop(Type::funcref)"),
5252
("externref.pop", "makePop(Type::externref)"),
53-
("nullref.pop", "makePop(Type::nullref)"),
5453
("exnref.pop", "makePop(Type::exnref)"),
5554
("i32.load", "makeLoad(s, Type::i32, /*isAtomic=*/false)"),
5655
("i64.load", "makeLoad(s, Type::i64, /*isAtomic=*/false)"),

src/asmjs/asm_v_wasm.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ AsmType wasmToAsmType(Type type) {
5656
assert(false && "v128 not implemented yet");
5757
case Type::funcref:
5858
case Type::externref:
59-
case Type::nullref:
6059
case Type::exnref:
6160
assert(false && "reference types are not supported by asm2wasm");
6261
case Type::none:
@@ -84,8 +83,6 @@ char getSig(Type type) {
8483
return 'F';
8584
case Type::externref:
8685
return 'X';
87-
case Type::nullref:
88-
return 'N';
8986
case Type::exnref:
9087
return 'E';
9188
case Type::none:

src/binaryen-c.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ BinaryenLiteral toBinaryenLiteral(Literal x) {
6969
memcpy(&ret.v128, x.getv128Ptr(), 16);
7070
break;
7171
case Type::funcref:
72-
ret.func = x.getFunc().c_str();
73-
break;
74-
case Type::nullref:
72+
ret.func = x.isNull() ? nullptr : x.getFunc().c_str();
7573
break;
7674
case Type::externref:
7775
case Type::exnref:
76+
assert(x.isNull());
77+
break;
7878
case Type::none:
7979
case Type::unreachable:
8080
WASM_UNREACHABLE("unexpected type");
@@ -95,11 +95,10 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) {
9595
case Type::v128:
9696
return Literal(x.v128);
9797
case Type::funcref:
98-
return Literal::makeFuncref(x.func);
99-
case Type::nullref:
100-
return Literal::makeNullref();
98+
return Literal::makeFunc(x.func);
10199
case Type::externref:
102100
case Type::exnref:
101+
return Literal::makeNull(Type(x.type));
103102
case Type::none:
104103
case Type::unreachable:
105104
WASM_UNREACHABLE("unexpected type");
@@ -133,7 +132,6 @@ BinaryenType BinaryenTypeFloat64(void) { return Type::f64; }
133132
BinaryenType BinaryenTypeVec128(void) { return Type::v128; }
134133
BinaryenType BinaryenTypeFuncref(void) { return Type::funcref; }
135134
BinaryenType BinaryenTypeExternref(void) { return Type::externref; }
136-
BinaryenType BinaryenTypeNullref(void) { return Type::nullref; }
137135
BinaryenType BinaryenTypeExnref(void) { return Type::exnref; }
138136
BinaryenType BinaryenTypeUnreachable(void) { return Type::unreachable; }
139137
BinaryenType BinaryenTypeAuto(void) { return uintptr_t(-1); }
@@ -1264,8 +1262,11 @@ BinaryenExpressionRef BinaryenPop(BinaryenModuleRef module, BinaryenType type) {
12641262
Builder(*(Module*)module).makePop(Type(type)));
12651263
}
12661264

1267-
BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module) {
1268-
return static_cast<Expression*>(Builder(*(Module*)module).makeRefNull());
1265+
BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module,
1266+
BinaryenType type) {
1267+
Type type_(type);
1268+
assert(type_.isNullable());
1269+
return static_cast<Expression*>(Builder(*(Module*)module).makeRefNull(type_));
12691270
}
12701271

12711272
BinaryenExpressionRef BinaryenRefIsNull(BinaryenModuleRef module,

src/binaryen-c.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ BINARYEN_API BinaryenType BinaryenTypeFloat64(void);
100100
BINARYEN_API BinaryenType BinaryenTypeVec128(void);
101101
BINARYEN_API BinaryenType BinaryenTypeFuncref(void);
102102
BINARYEN_API BinaryenType BinaryenTypeExternref(void);
103-
BINARYEN_API BinaryenType BinaryenTypeNullref(void);
104103
BINARYEN_API BinaryenType BinaryenTypeExnref(void);
105104
BINARYEN_API BinaryenType BinaryenTypeUnreachable(void);
106105
// Not a real type. Used as the last parameter to BinaryenBlock to let
@@ -826,7 +825,8 @@ BinaryenMemoryFill(BinaryenModuleRef module,
826825
BinaryenExpressionRef dest,
827826
BinaryenExpressionRef value,
828827
BinaryenExpressionRef size);
829-
BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module);
828+
BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module,
829+
BinaryenType type);
830830
BINARYEN_API BinaryenExpressionRef
831831
BinaryenRefIsNull(BinaryenModuleRef module, BinaryenExpressionRef value);
832832
BINARYEN_API BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,

src/gen-s-parser.inc

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2560,17 +2560,9 @@ switch (op[0]) {
25602560
default: goto parse_error;
25612561
}
25622562
}
2563-
case 'n': {
2564-
switch (op[1]) {
2565-
case 'o':
2566-
if (strcmp(op, "nop") == 0) { return makeNop(); }
2567-
goto parse_error;
2568-
case 'u':
2569-
if (strcmp(op, "nullref.pop") == 0) { return makePop(Type::nullref); }
2570-
goto parse_error;
2571-
default: goto parse_error;
2572-
}
2573-
}
2563+
case 'n':
2564+
if (strcmp(op, "nop") == 0) { return makeNop(); }
2565+
goto parse_error;
25742566
case 'r': {
25752567
switch (op[2]) {
25762568
case 'f': {

src/ir/ExpressionManipulator.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,9 @@ flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) {
227227
builder.makeHost(curr->op, curr->nameOperand, std::move(operands));
228228
return ret;
229229
}
230-
Expression* visitRefNull(RefNull* curr) { return builder.makeRefNull(); }
230+
Expression* visitRefNull(RefNull* curr) {
231+
return builder.makeRefNull(curr->type);
232+
}
231233
Expression* visitRefIsNull(RefIsNull* curr) {
232234
return builder.makeRefIsNull(copy(curr->value));
233235
}

src/ir/abstract.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ inline UnaryOp getUnary(Type type, Op op) {
103103
}
104104
case Type::funcref:
105105
case Type::externref:
106-
case Type::nullref:
107106
case Type::exnref:
108107
case Type::none:
109108
case Type::unreachable: {
@@ -268,7 +267,6 @@ inline BinaryOp getBinary(Type type, Op op) {
268267
}
269268
case Type::funcref:
270269
case Type::externref:
271-
case Type::nullref:
272270
case Type::exnref:
273271
case Type::none:
274272
case Type::unreachable: {

src/ir/manipulation.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ template<typename InputType> inline Nop* nop(InputType* target) {
4040
return ret;
4141
}
4242

43-
template<typename InputType> inline RefNull* refNull(InputType* target) {
43+
template<typename InputType>
44+
inline RefNull* refNull(InputType* target, Type type) {
4445
auto* ret = convert<InputType, RefNull>(target);
45-
ret->finalize();
46+
ret->finalize(type);
4647
return ret;
4748
}
4849

src/ir/properties.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,10 @@ inline bool isConstantExpression(const Expression* curr) {
9393
inline Literal getSingleLiteral(const Expression* curr) {
9494
if (auto* c = curr->dynCast<Const>()) {
9595
return c->value;
96-
} else if (curr->is<RefNull>()) {
97-
return Literal(Type::nullref);
98-
} else if (auto* c = curr->dynCast<RefFunc>()) {
99-
return Literal(c->func);
96+
} else if (auto* n = curr->dynCast<RefNull>()) {
97+
return Literal(n->type);
98+
} else if (auto* r = curr->dynCast<RefFunc>()) {
99+
return Literal(r->func);
100100
} else {
101101
WASM_UNREACHABLE("non-constant expression");
102102
}

src/js/binaryen.js-post.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ function initializeConstants() {
3535
['v128', 'Vec128'],
3636
['funcref', 'Funcref'],
3737
['externref', 'Externref'],
38-
['nullref', 'Nullref'],
3938
['exnref', 'Exnref'],
4039
['unreachable', 'Unreachable'],
4140
['auto', 'Auto']
@@ -2058,21 +2057,15 @@ function wrapModule(module, self = {}) {
20582057
}
20592058
};
20602059

2061-
self['nullref'] = {
2062-
'pop'() {
2063-
return Module['_BinaryenPop'](module, Module['nullref']);
2064-
}
2065-
};
2066-
20672060
self['exnref'] = {
20682061
'pop'() {
20692062
return Module['_BinaryenPop'](module, Module['exnref']);
20702063
}
20712064
};
20722065

20732066
self['ref'] = {
2074-
'null'() {
2075-
return Module['_BinaryenRefNull'](module);
2067+
'null'(type) {
2068+
return Module['_BinaryenRefNull'](module, type);
20762069
},
20772070
'is_null'(value) {
20782071
return Module['_BinaryenRefIsNull'](module, value);

src/literal.h

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,22 @@ class Literal {
3939
int32_t i32;
4040
int64_t i64;
4141
uint8_t v128[16];
42-
Name func; // function name for funcref
42+
// funcref function name. `isNull()` indicates a `null` value.
43+
Name func;
44+
// exnref package. `nullptr` indicates a `null` value.
4345
std::unique_ptr<ExceptionPackage> exn;
46+
// TODO: Literals of type `externref` can only be `null` currently but we
47+
// will need to represent extern values eventually, to
48+
// 1) run the spec tests and fuzzer with reference types enabled and
49+
// 2) avoid bailing out when seeing a reference typed value in precompute
4450
};
4551

4652
public:
4753
// Type of the literal. Immutable because the literal's payload depends on it.
4854
const Type type;
4955

5056
Literal() : v128(), type(Type::none) {}
51-
explicit Literal(Type type) : v128(), type(type) {
52-
assert(type != Type::unreachable && type != Type::funcref &&
53-
type != Type::exnref);
54-
}
57+
explicit Literal(Type type);
5558
explicit Literal(Type::BasicID typeId) : Literal(Type(typeId)) {}
5659
explicit Literal(int32_t init) : i32(init), type(Type::i32) {}
5760
explicit Literal(uint32_t init) : i32(init), type(Type::i32) {}
@@ -74,13 +77,25 @@ class Literal {
7477
Literal(const Literal& other);
7578
Literal& operator=(const Literal& other);
7679
~Literal() {
77-
if (type == Type::exnref) {
80+
if (type.isException()) {
7881
exn.~unique_ptr();
7982
}
8083
}
8184

8285
bool isConcrete() const { return type != Type::none; }
8386
bool isNone() const { return type == Type::none; }
87+
bool isNull() const {
88+
if (type.isNullable()) {
89+
if (type.isFunction()) {
90+
return func.isNull();
91+
}
92+
if (type.isException()) {
93+
return !exn;
94+
}
95+
return true;
96+
}
97+
return false;
98+
}
8499

85100
static Literal makeFromInt32(int32_t x, Type type) {
86101
switch (type.getBasic()) {
@@ -105,9 +120,12 @@ class Literal {
105120
static Literals makeZero(Type type);
106121
static Literal makeSingleZero(Type type);
107122

108-
static Literal makeNullref() { return Literal(Type(Type::nullref)); }
109-
static Literal makeFuncref(Name func) { return Literal(func.c_str()); }
110-
static Literal makeExnref(std::unique_ptr<ExceptionPackage>&& exn) {
123+
static Literal makeNull(Type type) {
124+
assert(type.isNullable());
125+
return Literal(type);
126+
}
127+
static Literal makeFunc(Name func) { return Literal(func.c_str()); }
128+
static Literal makeExn(std::unique_ptr<ExceptionPackage>&& exn) {
111129
return Literal(std::move(exn));
112130
}
113131

@@ -134,7 +152,7 @@ class Literal {
134152
}
135153
std::array<uint8_t, 16> getv128() const;
136154
Name getFunc() const {
137-
assert(type == Type::funcref);
155+
assert(type.isFunction() && !func.isNull());
138156
return func;
139157
}
140158
ExceptionPackage getExceptionPackage() const;
@@ -502,6 +520,12 @@ class Literals : public SmallVector<Literal, 1> {
502520
struct ExceptionPackage {
503521
Name event;
504522
Literals values;
523+
bool operator==(const ExceptionPackage& other) const {
524+
return event == other.event && values == other.values;
525+
}
526+
bool operator!=(const ExceptionPackage& other) const {
527+
return !(*this == other);
528+
}
505529
};
506530

507531
std::ostream& operator<<(std::ostream& o, wasm::Literal literal);
@@ -554,7 +578,6 @@ template<> struct less<wasm::Literal> {
554578
return memcmp(a.getv128Ptr(), b.getv128Ptr(), 16) < 0;
555579
case wasm::Type::funcref:
556580
case wasm::Type::externref:
557-
case wasm::Type::nullref:
558581
case wasm::Type::exnref:
559582
case wasm::Type::none:
560583
case wasm::Type::unreachable:

src/parsing.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,6 @@ parseConst(cashew::IString s, Type type, MixedArena& allocator) {
265265
case Type::v128:
266266
case Type::funcref:
267267
case Type::externref:
268-
case Type::nullref:
269268
case Type::exnref:
270269
WASM_UNREACHABLE("unexpected const type");
271270
case Type::none:

src/passes/ConstHoisting.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ struct ConstHoisting : public WalkerPass<PostWalker<ConstHoisting>> {
9696
case Type::v128:
9797
case Type::funcref:
9898
case Type::externref:
99-
case Type::nullref:
10099
case Type::exnref: {
101100
return false;
102101
}

src/passes/Flatten.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,19 +211,19 @@ struct Flatten
211211
// the return type of the block this branch is targetting, which may
212212
// not be the same with the innermost block's return type. For
213213
// example,
214-
// (block $any (result externref)
215-
// (block (result nullref)
214+
// (block $any (result anyref)
215+
// (block (result funcref)
216216
// (local.tee $0
217217
// (br_if $any
218-
// (ref.null)
218+
// (ref.null func)
219219
// (i32.const 0)
220220
// )
221221
// )
222222
// )
223223
// )
224224
// In this case we need two locals to store (ref.null); one with
225-
// externref type that's for the target block ($label0) and one more
226-
// with nullref type in case for flowing out. Here we create the
225+
// funcref type that's for the target block ($label0) and one more
226+
// with anyref type in case for flowing out. Here we create the
227227
// second 'flowing out' local in case two block's types are
228228
// different.
229229
if (type != blockType) {

src/passes/FuncCastEmulation.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ static Expression* toABI(Expression* value, Module* module) {
6767
}
6868
case Type::funcref:
6969
case Type::externref:
70-
case Type::nullref:
7170
case Type::exnref: {
7271
WASM_UNREACHABLE("reference types cannot be converted to i64");
7372
}
@@ -111,7 +110,6 @@ static Expression* fromABI(Expression* value, Type type, Module* module) {
111110
}
112111
case Type::funcref:
113112
case Type::externref:
114-
case Type::nullref:
115113
case Type::exnref: {
116114
WASM_UNREACHABLE("reference types cannot be converted from i64");
117115
}

0 commit comments

Comments
 (0)