Skip to content

Commit 3e90ff5

Browse files
committed
Add support for reference types proposal
1 parent fbce98c commit 3e90ff5

File tree

88 files changed

+10737
-2145
lines changed

Some content is hidden

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

88 files changed

+10737
-2145
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ full changeset diff at the end of each section.
1515
Current Trunk
1616
-------------
1717

18+
- Reference type support is added. Supported instructions are `ref.null`,
19+
`ref.is_null`, `ref.func`, and typed `select`. Table instructions are not
20+
supported yet.
1821
- `local.tee`'s C/Binaryen.js API now takes an additional type parameter for its
1922
local type, like `local.get`. This is required to handle subtypes.
2023
- Added load_splat SIMD instructions

check.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,10 @@ def check():
152152

153153
shared.fail_if_not_identical_to_file(actual, f)
154154

155-
shared.binary_format_check(t, wasm_as_args=['-g']) # test with debuginfo
156-
shared.binary_format_check(t, wasm_as_args=[], binary_suffix='.fromBinary.noDebugInfo') # test without debuginfo
155+
# HACK Remove this condition after nullref is implemented in V8
156+
if 'reference_types.wast' in t:
157+
shared.binary_format_check(t, wasm_as_args=['-g']) # test with debuginfo
158+
shared.binary_format_check(t, wasm_as_args=[], binary_suffix='.fromBinary.noDebugInfo') # test without debuginfo
157159

158160
shared.minify_check(t)
159161

scripts/fuzz_opt.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ def compare_vs(self, before, after):
228228
break
229229

230230
def can_run_on_feature_opts(self, feature_opts):
231-
return all([x in feature_opts for x in ['--disable-simd']])
231+
return all([x in feature_opts for x in ['--disable-simd', '--disable-reference-types']])
232232

233233

234234
# Fuzz the interpreter with --fuzz-exec. This tests everything in a single command (no
@@ -294,7 +294,7 @@ def run(self, wasm):
294294
return out
295295

296296
def can_run_on_feature_opts(self, feature_opts):
297-
return all([x in feature_opts for x in ['--disable-exception-handling', '--disable-simd', '--disable-threads', '--disable-bulk-memory', '--disable-nontrapping-float-to-int', '--disable-tail-call', '--disable-sign-ext']])
297+
return all([x in feature_opts for x in ['--disable-exception-handling', '--disable-simd', '--disable-threads', '--disable-bulk-memory', '--disable-nontrapping-float-to-int', '--disable-tail-call', '--disable-sign-ext', '--disable-reference-types']])
298298

299299

300300
class Asyncify(TestCaseHandler):
@@ -339,7 +339,7 @@ def do_asyncify(wasm):
339339
compare(before, after_asyncify, 'Asyncify (before/after_asyncify)')
340340

341341
def can_run_on_feature_opts(self, feature_opts):
342-
return all([x in feature_opts for x in ['--disable-exception-handling', '--disable-simd', '--disable-tail-call']])
342+
return all([x in feature_opts for x in ['--disable-exception-handling', '--disable-simd', '--disable-tail-call', '--disable-reference-types']])
343343

344344

345345
# The global list of all test case handlers

scripts/gen-s-parser.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@
4949
("f32.pop", "makePop(f32)"),
5050
("f64.pop", "makePop(f64)"),
5151
("v128.pop", "makePop(v128)"),
52+
("funcref.pop", "makePop(funcref)"),
5253
("anyref.pop", "makePop(anyref)"),
54+
("nullref.pop", "makePop(nullref)"),
5355
("exnref.pop", "makePop(exnref)"),
5456
("i32.load", "makeLoad(s, i32, /*isAtomic=*/false)"),
5557
("i64.load", "makeLoad(s, i64, /*isAtomic=*/false)"),
@@ -467,6 +469,11 @@
467469
("i32x4.widen_low_i16x8_u", "makeUnary(s, UnaryOp::WidenLowUVecI16x8ToVecI32x4)"),
468470
("i32x4.widen_high_i16x8_u", "makeUnary(s, UnaryOp::WidenHighUVecI16x8ToVecI32x4)"),
469471
("v8x16.swizzle", "makeBinary(s, BinaryOp::SwizzleVec8x16)"),
472+
# reference types instructions
473+
# TODO Add table instructions
474+
("ref.null", "makeRefNull(s)"),
475+
("ref.is_null", "makeRefIsNull(s)"),
476+
("ref.func", "makeRefFunc(s)"),
470477
# exception handling instructions
471478
("try", "makeTry(s)"),
472479
("throw", "makeThrow(s)"),

src/asmjs/asm_v_wasm.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,11 @@ AsmType wasmToAsmType(Type type) {
5353
return ASM_INT64;
5454
case v128:
5555
assert(false && "v128 not implemented yet");
56+
case funcref:
5657
case anyref:
57-
assert(false && "anyref is not supported by asm2wasm");
58+
case nullref:
5859
case exnref:
59-
assert(false && "exnref is not supported by asm2wasm");
60+
assert(false && "reference types are not supported by asm2wasm");
6061
case none:
6162
return ASM_NONE;
6263
case unreachable:
@@ -77,10 +78,14 @@ char getSig(Type type) {
7778
return 'd';
7879
case v128:
7980
return 'V';
81+
case funcref:
82+
return 'F';
8083
case anyref:
81-
return 'a';
84+
return 'A';
85+
case nullref:
86+
return 'N';
8287
case exnref:
83-
return 'e';
88+
return 'E';
8489
case none:
8590
return 'v';
8691
case unreachable:

src/binaryen-c.cpp

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@ using namespace wasm;
4545

4646
// Literal utilities
4747

48-
static_assert(sizeof(BinaryenLiteral) == sizeof(Literal),
49-
"Binaryen C API literal must match wasm.h");
50-
5148
BinaryenLiteral toBinaryenLiteral(Literal x) {
5249
BinaryenLiteral ret;
5350
ret.type = x.type;
@@ -64,15 +61,15 @@ BinaryenLiteral toBinaryenLiteral(Literal x) {
6461
case Type::f64:
6562
ret.i64 = x.reinterpreti64();
6663
break;
67-
case Type::v128: {
64+
case Type::v128:
6865
memcpy(&ret.v128, x.getv128Ptr(), 16);
6966
break;
70-
}
71-
72-
case Type::anyref: // there's no anyref literals
73-
case Type::exnref: // there's no exnref literals
74-
case Type::none:
75-
case Type::unreachable:
67+
case Type::nullref:
68+
break;
69+
case Type::funcref:
70+
ret.func = x.func.c_str();
71+
break;
72+
default:
7673
WASM_UNREACHABLE("unexpected type");
7774
}
7875
return ret;
@@ -90,10 +87,7 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) {
9087
return Literal(x.i64).castToF64();
9188
case Type::v128:
9289
return Literal(x.v128);
93-
case Type::anyref: // there's no anyref literals
94-
case Type::exnref: // there's no exnref literals
95-
case Type::none:
96-
case Type::unreachable:
90+
default:
9791
WASM_UNREACHABLE("unexpected type");
9892
}
9993
WASM_UNREACHABLE("invalid type");
@@ -209,10 +203,7 @@ void printArg(std::ostream& setup, std::ostream& out, BinaryenLiteral arg) {
209203
out << "BinaryenLiteralVec128(" << array << ")";
210204
break;
211205
}
212-
case Type::anyref: // there's no anyref literals
213-
case Type::exnref: // there's no exnref literals
214-
case Type::none:
215-
case Type::unreachable:
206+
default:
216207
WASM_UNREACHABLE("unexpected type");
217208
}
218209
}
@@ -265,7 +256,9 @@ BinaryenType BinaryenTypeInt64(void) { return i64; }
265256
BinaryenType BinaryenTypeFloat32(void) { return f32; }
266257
BinaryenType BinaryenTypeFloat64(void) { return f64; }
267258
BinaryenType BinaryenTypeVec128(void) { return v128; }
259+
BinaryenType BinaryenTypeFuncref(void) { return funcref; }
268260
BinaryenType BinaryenTypeAnyref(void) { return anyref; }
261+
BinaryenType BinaryenTypeNullref(void) { return nullref; }
269262
BinaryenType BinaryenTypeExnref(void) { return exnref; }
270263
BinaryenType BinaryenTypeUnreachable(void) { return unreachable; }
271264
BinaryenType BinaryenTypeAuto(void) { return uint32_t(-1); }
@@ -397,6 +390,15 @@ BinaryenExpressionId BinaryenMemoryCopyId(void) {
397390
BinaryenExpressionId BinaryenMemoryFillId(void) {
398391
return Expression::Id::MemoryFillId;
399392
}
393+
BinaryenExpressionId BinaryenRefNullId(void) {
394+
return Expression::Id::RefNullId;
395+
}
396+
BinaryenExpressionId BinaryenRefIsNullId(void) {
397+
return Expression::Id::RefIsNullId;
398+
}
399+
BinaryenExpressionId BinaryenRefFuncId(void) {
400+
return Expression::Id::RefFuncId;
401+
}
400402
BinaryenExpressionId BinaryenTryId(void) { return Expression::Id::TryId; }
401403
BinaryenExpressionId BinaryenThrowId(void) { return Expression::Id::ThrowId; }
402404
BinaryenExpressionId BinaryenRethrowId(void) {
@@ -1328,17 +1330,22 @@ BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module,
13281330
BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module,
13291331
BinaryenExpressionRef condition,
13301332
BinaryenExpressionRef ifTrue,
1331-
BinaryenExpressionRef ifFalse) {
1333+
BinaryenExpressionRef ifFalse,
1334+
BinaryenType type) {
13321335
auto* ret = ((Module*)module)->allocator.alloc<Select>();
13331336

13341337
if (tracing) {
1335-
traceExpression(ret, "BinaryenSelect", condition, ifTrue, ifFalse);
1338+
traceExpression(ret, "BinaryenSelect", condition, ifTrue, ifFalse, type);
13361339
}
13371340

13381341
ret->condition = (Expression*)condition;
13391342
ret->ifTrue = (Expression*)ifTrue;
13401343
ret->ifFalse = (Expression*)ifFalse;
1341-
ret->finalize();
1344+
if (type != BinaryenTypeAuto()) {
1345+
ret->finalize(Type(type));
1346+
} else {
1347+
ret->finalize();
1348+
}
13421349
return static_cast<Expression*>(ret);
13431350
}
13441351
BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module,
@@ -1693,6 +1700,32 @@ BinaryenExpressionRef BinaryenPop(BinaryenModuleRef module, BinaryenType type) {
16931700
return static_cast<Expression*>(ret);
16941701
}
16951702

1703+
BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module) {
1704+
auto* ret = Builder(*(Module*)module).makeRefNull();
1705+
if (tracing) {
1706+
traceExpression(ret, "BinaryenRefNull");
1707+
}
1708+
return static_cast<Expression*>(ret);
1709+
}
1710+
1711+
BinaryenExpressionRef BinaryenRefIsNull(BinaryenModuleRef module,
1712+
BinaryenExpressionRef anyref) {
1713+
auto* ret = Builder(*(Module*)module).makeRefIsNull((Expression*)anyref);
1714+
if (tracing) {
1715+
traceExpression(ret, "BinaryenRefIsNull", anyref);
1716+
}
1717+
return static_cast<Expression*>(ret);
1718+
}
1719+
1720+
BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
1721+
const char* func) {
1722+
auto* ret = Builder(*(Module*)module).makeRefFunc(func);
1723+
if (tracing) {
1724+
traceExpression(ret, "BinaryenRefFunc", StringLit(func));
1725+
}
1726+
return static_cast<Expression*>(ret);
1727+
}
1728+
16961729
BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module,
16971730
BinaryenExpressionRef body,
16981731
BinaryenExpressionRef catchBody) {
@@ -2962,6 +2995,28 @@ BinaryenExpressionRef BinaryenPushGetValue(BinaryenExpressionRef expr) {
29622995
assert(expression->is<Push>());
29632996
return static_cast<Push*>(expression)->value;
29642997
}
2998+
// RefIsNull
2999+
BinaryenExpressionRef BinaryenRefIsNullGetAnyref(BinaryenExpressionRef expr) {
3000+
if (tracing) {
3001+
std::cout << " BinaryenRefIsNullGetAnyref(expressions["
3002+
<< expressions[expr] << "]);\n";
3003+
}
3004+
3005+
auto* expression = (Expression*)expr;
3006+
assert(expression->is<RefIsNull>());
3007+
return static_cast<RefIsNull*>(expression)->anyref;
3008+
}
3009+
// RefFunc
3010+
const char* BinaryenRefFuncGetFunc(BinaryenExpressionRef expr) {
3011+
if (tracing) {
3012+
std::cout << " BinaryenRefFuncGetFunc(expressions[" << expressions[expr]
3013+
<< "]);\n";
3014+
}
3015+
3016+
auto* expression = (Expression*)expr;
3017+
assert(expression->is<RefFunc>());
3018+
return static_cast<RefFunc*>(expression)->func.c_str();
3019+
}
29653020
// Try
29663021
BinaryenExpressionRef BinaryenTryGetBody(BinaryenExpressionRef expr) {
29673022
if (tracing) {

src/binaryen-c.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ BINARYEN_API BinaryenType BinaryenTypeInt64(void);
9898
BINARYEN_API BinaryenType BinaryenTypeFloat32(void);
9999
BINARYEN_API BinaryenType BinaryenTypeFloat64(void);
100100
BINARYEN_API BinaryenType BinaryenTypeVec128(void);
101+
BINARYEN_API BinaryenType BinaryenTypeFuncref(void);
101102
BINARYEN_API BinaryenType BinaryenTypeAnyref(void);
103+
BINARYEN_API BinaryenType BinaryenTypeNullref(void);
102104
BINARYEN_API BinaryenType BinaryenTypeExnref(void);
103105
BINARYEN_API BinaryenType BinaryenTypeUnreachable(void);
104106
// Not a real type. Used as the last parameter to BinaryenBlock to let
@@ -158,6 +160,9 @@ BINARYEN_API BinaryenExpressionId BinaryenMemoryInitId(void);
158160
BINARYEN_API BinaryenExpressionId BinaryenDataDropId(void);
159161
BINARYEN_API BinaryenExpressionId BinaryenMemoryCopyId(void);
160162
BINARYEN_API BinaryenExpressionId BinaryenMemoryFillId(void);
163+
BINARYEN_API BinaryenExpressionId BinaryenRefNullId(void);
164+
BINARYEN_API BinaryenExpressionId BinaryenRefIsNullId(void);
165+
BINARYEN_API BinaryenExpressionId BinaryenRefFuncId(void);
161166
BINARYEN_API BinaryenExpressionId BinaryenTryId(void);
162167
BINARYEN_API BinaryenExpressionId BinaryenThrowId(void);
163168
BINARYEN_API BinaryenExpressionId BinaryenRethrowId(void);
@@ -223,6 +228,7 @@ struct BinaryenLiteral {
223228
double f64;
224229
uint8_t v128[16];
225230
};
231+
const char* func;
226232
};
227233

228234
BINARYEN_API struct BinaryenLiteral BinaryenLiteralInt32(int32_t x);
@@ -690,7 +696,8 @@ BINARYEN_API BinaryenExpressionRef
690696
BinaryenSelect(BinaryenModuleRef module,
691697
BinaryenExpressionRef condition,
692698
BinaryenExpressionRef ifTrue,
693-
BinaryenExpressionRef ifFalse);
699+
BinaryenExpressionRef ifFalse,
700+
BinaryenType type);
694701
BINARYEN_API BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module,
695702
BinaryenExpressionRef value);
696703
// Return: value can be NULL
@@ -795,6 +802,11 @@ BinaryenMemoryFill(BinaryenModuleRef module,
795802
BinaryenExpressionRef dest,
796803
BinaryenExpressionRef value,
797804
BinaryenExpressionRef size);
805+
BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module);
806+
BINARYEN_API BinaryenExpressionRef
807+
BinaryenRefIsNull(BinaryenModuleRef module, BinaryenExpressionRef anyref);
808+
BINARYEN_API BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
809+
const char* func);
798810
BINARYEN_API BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module,
799811
BinaryenExpressionRef body,
800812
BinaryenExpressionRef catchBody);
@@ -1033,6 +1045,11 @@ BinaryenMemoryFillGetValue(BinaryenExpressionRef expr);
10331045
BINARYEN_API BinaryenExpressionRef
10341046
BinaryenMemoryFillGetSize(BinaryenExpressionRef expr);
10351047

1048+
BINARYEN_API BinaryenExpressionRef
1049+
BinaryenRefIsNullGetAnyref(BinaryenExpressionRef expr);
1050+
1051+
BINARYEN_API const char* BinaryenRefFuncGetFunc(BinaryenExpressionRef expr);
1052+
10361053
BINARYEN_API BinaryenExpressionRef
10371054
BinaryenTryGetBody(BinaryenExpressionRef expr);
10381055
BINARYEN_API BinaryenExpressionRef

0 commit comments

Comments
 (0)