Skip to content

Commit 4ff8de8

Browse files
committed
Add support for reference types proposal
1 parent d113083 commit 4ff8de8

File tree

91 files changed

+7232
-2768
lines changed

Some content is hidden

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

91 files changed

+7232
-2768
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: 15 additions & 6 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:
@@ -109,9 +114,13 @@ Type sigToType(char sig) {
109114
return f64;
110115
case 'V':
111116
return v128;
112-
case 'a':
117+
case 'F':
118+
return funcref;
119+
case 'A':
113120
return anyref;
114-
case 'e':
121+
case 'N':
122+
return nullref;
123+
case 'E':
115124
return exnref;
116125
case 'v':
117126
return none;

src/binaryen-c.cpp

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

4747
// Literal utilities
4848

49-
static_assert(sizeof(BinaryenLiteral) == sizeof(Literal),
50-
"Binaryen C API literal must match wasm.h");
51-
5249
BinaryenLiteral toBinaryenLiteral(Literal x) {
5350
BinaryenLiteral ret;
5451
ret.type = x.type;
@@ -65,15 +62,15 @@ BinaryenLiteral toBinaryenLiteral(Literal x) {
6562
case Type::f64:
6663
ret.i64 = x.reinterpreti64();
6764
break;
68-
case Type::v128: {
65+
case Type::v128:
6966
memcpy(&ret.v128, x.getv128Ptr(), 16);
7067
break;
71-
}
72-
73-
case Type::anyref: // there's no anyref literals
74-
case Type::exnref: // there's no exnref literals
75-
case Type::none:
76-
case Type::unreachable:
68+
case Type::nullref:
69+
break;
70+
case Type::funcref:
71+
ret.func = x.func.c_str();
72+
break;
73+
default:
7774
WASM_UNREACHABLE("unexpected type");
7875
}
7976
return ret;
@@ -91,10 +88,7 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) {
9188
return Literal(x.i64).castToF64();
9289
case Type::v128:
9390
return Literal(x.v128);
94-
case Type::anyref: // there's no anyref literals
95-
case Type::exnref: // there's no exnref literals
96-
case Type::none:
97-
case Type::unreachable:
91+
default:
9892
WASM_UNREACHABLE("unexpected type");
9993
}
10094
WASM_UNREACHABLE("invalid type");
@@ -212,10 +206,7 @@ void printArg(std::ostream& setup, std::ostream& out, BinaryenLiteral arg) {
212206
out << "BinaryenLiteralVec128(" << array << ")";
213207
break;
214208
}
215-
case Type::anyref: // there's no anyref literals
216-
case Type::exnref: // there's no exnref literals
217-
case Type::none:
218-
case Type::unreachable:
209+
default:
219210
WASM_UNREACHABLE("unexpected type");
220211
}
221212
}
@@ -268,7 +259,9 @@ BinaryenType BinaryenTypeInt64(void) { return i64; }
268259
BinaryenType BinaryenTypeFloat32(void) { return f32; }
269260
BinaryenType BinaryenTypeFloat64(void) { return f64; }
270261
BinaryenType BinaryenTypeVec128(void) { return v128; }
262+
BinaryenType BinaryenTypeFuncref(void) { return funcref; }
271263
BinaryenType BinaryenTypeAnyref(void) { return anyref; }
264+
BinaryenType BinaryenTypeNullref(void) { return nullref; }
272265
BinaryenType BinaryenTypeExnref(void) { return exnref; }
273266
BinaryenType BinaryenTypeUnreachable(void) { return unreachable; }
274267
BinaryenType BinaryenTypeAuto(void) { return uint32_t(-1); }
@@ -400,6 +393,15 @@ BinaryenExpressionId BinaryenMemoryCopyId(void) {
400393
BinaryenExpressionId BinaryenMemoryFillId(void) {
401394
return Expression::Id::MemoryFillId;
402395
}
396+
BinaryenExpressionId BinaryenRefNullId(void) {
397+
return Expression::Id::RefNullId;
398+
}
399+
BinaryenExpressionId BinaryenRefIsNullId(void) {
400+
return Expression::Id::RefIsNullId;
401+
}
402+
BinaryenExpressionId BinaryenRefFuncId(void) {
403+
return Expression::Id::RefFuncId;
404+
}
403405
BinaryenExpressionId BinaryenTryId(void) { return Expression::Id::TryId; }
404406
BinaryenExpressionId BinaryenThrowId(void) { return Expression::Id::ThrowId; }
405407
BinaryenExpressionId BinaryenRethrowId(void) {
@@ -1392,17 +1394,22 @@ BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module,
13921394
BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module,
13931395
BinaryenExpressionRef condition,
13941396
BinaryenExpressionRef ifTrue,
1395-
BinaryenExpressionRef ifFalse) {
1397+
BinaryenExpressionRef ifFalse,
1398+
BinaryenType type) {
13961399
auto* ret = ((Module*)module)->allocator.alloc<Select>();
13971400

13981401
if (tracing) {
1399-
traceExpression(ret, "BinaryenSelect", condition, ifTrue, ifFalse);
1402+
traceExpression(ret, "BinaryenSelect", condition, ifTrue, ifFalse, type);
14001403
}
14011404

14021405
ret->condition = (Expression*)condition;
14031406
ret->ifTrue = (Expression*)ifTrue;
14041407
ret->ifFalse = (Expression*)ifFalse;
1405-
ret->finalize();
1408+
if (type != BinaryenTypeAuto()) {
1409+
ret->finalize(Type(type));
1410+
} else {
1411+
ret->finalize();
1412+
}
14061413
return static_cast<Expression*>(ret);
14071414
}
14081415
BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module,
@@ -1757,6 +1764,32 @@ BinaryenExpressionRef BinaryenPop(BinaryenModuleRef module, BinaryenType type) {
17571764
return static_cast<Expression*>(ret);
17581765
}
17591766

1767+
BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module) {
1768+
auto* ret = Builder(*(Module*)module).makeRefNull();
1769+
if (tracing) {
1770+
traceExpression(ret, "BinaryenRefNull");
1771+
}
1772+
return static_cast<Expression*>(ret);
1773+
}
1774+
1775+
BinaryenExpressionRef BinaryenRefIsNull(BinaryenModuleRef module,
1776+
BinaryenExpressionRef anyref) {
1777+
auto* ret = Builder(*(Module*)module).makeRefIsNull((Expression*)anyref);
1778+
if (tracing) {
1779+
traceExpression(ret, "BinaryenRefIsNull", anyref);
1780+
}
1781+
return static_cast<Expression*>(ret);
1782+
}
1783+
1784+
BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
1785+
const char* func) {
1786+
auto* ret = Builder(*(Module*)module).makeRefFunc(func);
1787+
if (tracing) {
1788+
traceExpression(ret, "BinaryenRefFunc", StringLit(func));
1789+
}
1790+
return static_cast<Expression*>(ret);
1791+
}
1792+
17601793
BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module,
17611794
BinaryenExpressionRef body,
17621795
BinaryenExpressionRef catchBody) {
@@ -3026,6 +3059,28 @@ BinaryenExpressionRef BinaryenPushGetValue(BinaryenExpressionRef expr) {
30263059
assert(expression->is<Push>());
30273060
return static_cast<Push*>(expression)->value;
30283061
}
3062+
// RefIsNull
3063+
BinaryenExpressionRef BinaryenRefIsNullGetAnyref(BinaryenExpressionRef expr) {
3064+
if (tracing) {
3065+
std::cout << " BinaryenRefIsNullGetAnyref(expressions["
3066+
<< expressions[expr] << "]);\n";
3067+
}
3068+
3069+
auto* expression = (Expression*)expr;
3070+
assert(expression->is<RefIsNull>());
3071+
return static_cast<RefIsNull*>(expression)->anyref;
3072+
}
3073+
// RefFunc
3074+
const char* BinaryenRefFuncGetFunc(BinaryenExpressionRef expr) {
3075+
if (tracing) {
3076+
std::cout << " BinaryenRefFuncGetFunc(expressions[" << expressions[expr]
3077+
<< "]);\n";
3078+
}
3079+
3080+
auto* expression = (Expression*)expr;
3081+
assert(expression->is<RefFunc>());
3082+
return static_cast<RefFunc*>(expression)->func.c_str();
3083+
}
30293084
// Try
30303085
BinaryenExpressionRef BinaryenTryGetBody(BinaryenExpressionRef expr) {
30313086
if (tracing) {

src/binaryen-c.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ BINARYEN_API BinaryenType BinaryenTypeInt64(void);
9999
BINARYEN_API BinaryenType BinaryenTypeFloat32(void);
100100
BINARYEN_API BinaryenType BinaryenTypeFloat64(void);
101101
BINARYEN_API BinaryenType BinaryenTypeVec128(void);
102+
BINARYEN_API BinaryenType BinaryenTypeFuncref(void);
102103
BINARYEN_API BinaryenType BinaryenTypeAnyref(void);
104+
BINARYEN_API BinaryenType BinaryenTypeNullref(void);
103105
BINARYEN_API BinaryenType BinaryenTypeExnref(void);
104106
BINARYEN_API BinaryenType BinaryenTypeUnreachable(void);
105107
// Not a real type. Used as the last parameter to BinaryenBlock to let
@@ -159,6 +161,9 @@ BINARYEN_API BinaryenExpressionId BinaryenMemoryInitId(void);
159161
BINARYEN_API BinaryenExpressionId BinaryenDataDropId(void);
160162
BINARYEN_API BinaryenExpressionId BinaryenMemoryCopyId(void);
161163
BINARYEN_API BinaryenExpressionId BinaryenMemoryFillId(void);
164+
BINARYEN_API BinaryenExpressionId BinaryenRefNullId(void);
165+
BINARYEN_API BinaryenExpressionId BinaryenRefIsNullId(void);
166+
BINARYEN_API BinaryenExpressionId BinaryenRefFuncId(void);
162167
BINARYEN_API BinaryenExpressionId BinaryenTryId(void);
163168
BINARYEN_API BinaryenExpressionId BinaryenThrowId(void);
164169
BINARYEN_API BinaryenExpressionId BinaryenRethrowId(void);
@@ -240,6 +245,7 @@ struct BinaryenLiteral {
240245
double f64;
241246
uint8_t v128[16];
242247
};
248+
const char* func;
243249
};
244250

245251
BINARYEN_API struct BinaryenLiteral BinaryenLiteralInt32(int32_t x);
@@ -705,7 +711,8 @@ BINARYEN_API BinaryenExpressionRef
705711
BinaryenSelect(BinaryenModuleRef module,
706712
BinaryenExpressionRef condition,
707713
BinaryenExpressionRef ifTrue,
708-
BinaryenExpressionRef ifFalse);
714+
BinaryenExpressionRef ifFalse,
715+
BinaryenType type);
709716
BINARYEN_API BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module,
710717
BinaryenExpressionRef value);
711718
// Return: value can be NULL
@@ -810,6 +817,11 @@ BinaryenMemoryFill(BinaryenModuleRef module,
810817
BinaryenExpressionRef dest,
811818
BinaryenExpressionRef value,
812819
BinaryenExpressionRef size);
820+
BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module);
821+
BINARYEN_API BinaryenExpressionRef
822+
BinaryenRefIsNull(BinaryenModuleRef module, BinaryenExpressionRef anyref);
823+
BINARYEN_API BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
824+
const char* func);
813825
BINARYEN_API BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module,
814826
BinaryenExpressionRef body,
815827
BinaryenExpressionRef catchBody);
@@ -1048,6 +1060,11 @@ BinaryenMemoryFillGetValue(BinaryenExpressionRef expr);
10481060
BINARYEN_API BinaryenExpressionRef
10491061
BinaryenMemoryFillGetSize(BinaryenExpressionRef expr);
10501062

1063+
BINARYEN_API BinaryenExpressionRef
1064+
BinaryenRefIsNullGetAnyref(BinaryenExpressionRef expr);
1065+
1066+
BINARYEN_API const char* BinaryenRefFuncGetFunc(BinaryenExpressionRef expr);
1067+
10511068
BINARYEN_API BinaryenExpressionRef
10521069
BinaryenTryGetBody(BinaryenExpressionRef expr);
10531070
BINARYEN_API BinaryenExpressionRef

0 commit comments

Comments
 (0)