Skip to content

Commit

Permalink
Add support for reference types proposal (#2451)
Browse files Browse the repository at this point in the history
This adds support for the reference type proposal. This includes support
for all reference types (`anyref`, `funcref`(=`anyfunc`), and `nullref`)
and four new instructions: `ref.null`, `ref.is_null`, `ref.func`, and
new typed `select`. This also adds subtype relationship support between
reference types.

This does not include table instructions yet. This also does not include
wasm2js support.

Fixes #2444 and fixes #2447.
  • Loading branch information
aheejin authored Dec 31, 2019
1 parent a30f1df commit bcc7614
Show file tree
Hide file tree
Showing 118 changed files with 7,083 additions and 2,284 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ full changeset diff at the end of each section.
Current Trunk
-------------

- Reference type support is added. Supported instructions are `ref.null`,
`ref.is_null`, `ref.func`, and typed `select`. Table instructions are not
supported yet. For typed `select`, C/JS API can take an additional 'type'
parameter.

v90
---

Expand Down
17 changes: 11 additions & 6 deletions check.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,10 @@ def check():

shared.fail_if_not_identical_to_file(actual, f)

shared.binary_format_check(t, wasm_as_args=['-g']) # test with debuginfo
shared.binary_format_check(t, wasm_as_args=[], binary_suffix='.fromBinary.noDebugInfo') # test without debuginfo
# FIXME Remove this condition after nullref is implemented in V8
if 'reference-types.wast' not in t:
shared.binary_format_check(t, wasm_as_args=['-g']) # test with debuginfo
shared.binary_format_check(t, wasm_as_args=[], binary_suffix='.fromBinary.noDebugInfo') # test without debuginfo

shared.minify_check(t)

Expand Down Expand Up @@ -271,9 +273,9 @@ def run_wasm_reduce_tests():
before = os.stat('a.wasm').st_size
support.run_command(shared.WASM_REDUCE + ['a.wasm', '--command=%s b.wasm --fuzz-exec -all' % shared.WASM_OPT[0], '-t', 'b.wasm', '-w', 'c.wasm'])
after = os.stat('c.wasm').st_size
# 0.65 is a custom threshold to check if we have shrunk the output
# sufficiently
assert after < 0.7 * before, [before, after]
# This number is a custom threshold to check if we have shrunk the
# output sufficiently
assert after < 0.75 * before, [before, after]


def run_spec_tests():
Expand Down Expand Up @@ -323,7 +325,10 @@ def check_expected(actual, expected):
# some wast files cannot be split:
# * comments.wast: contains characters that are not valid utf-8,
# so our string splitting code fails there
if os.path.basename(wast) not in ['comments.wast']:

# FIXME Remove reference type tests from this list after nullref is
# implemented in V8
if os.path.basename(wast) not in ['comments.wast', 'ref_null.wast', 'ref_is_null.wast', 'ref_func.wast', 'old_select.wast']:
split_num = 0
actual = ''
for module, asserts in support.split_wast(wast):
Expand Down
6 changes: 3 additions & 3 deletions scripts/fuzz_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def compare_vs(self, before, after):
break

def can_run_on_feature_opts(self, feature_opts):
return all([x in feature_opts for x in ['--disable-simd']])
return all([x in feature_opts for x in ['--disable-simd', '--disable-reference-types', '--disable-exception-handling']])


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

def can_run_on_feature_opts(self, feature_opts):
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']])
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']])


class Asyncify(TestCaseHandler):
Expand Down Expand Up @@ -339,7 +339,7 @@ def do_asyncify(wasm):
compare(before, after_asyncify, 'Asyncify (before/after_asyncify)')

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


# The global list of all test case handlers
Expand Down
7 changes: 7 additions & 0 deletions scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@
("f32.pop", "makePop(f32)"),
("f64.pop", "makePop(f64)"),
("v128.pop", "makePop(v128)"),
("funcref.pop", "makePop(funcref)"),
("anyref.pop", "makePop(anyref)"),
("nullref.pop", "makePop(nullref)"),
("exnref.pop", "makePop(exnref)"),
("i32.load", "makeLoad(s, i32, /*isAtomic=*/false)"),
("i64.load", "makeLoad(s, i64, /*isAtomic=*/false)"),
Expand Down Expand Up @@ -469,6 +471,11 @@
("i32x4.widen_low_i16x8_u", "makeUnary(s, UnaryOp::WidenLowUVecI16x8ToVecI32x4)"),
("i32x4.widen_high_i16x8_u", "makeUnary(s, UnaryOp::WidenHighUVecI16x8ToVecI32x4)"),
("v8x16.swizzle", "makeBinary(s, BinaryOp::SwizzleVec8x16)"),
# reference types instructions
# TODO Add table instructions
("ref.null", "makeRefNull(s)"),
("ref.is_null", "makeRefIsNull(s)"),
("ref.func", "makeRefFunc(s)"),
# exception handling instructions
("try", "makeTry(s)"),
("throw", "makeThrow(s)"),
Expand Down
13 changes: 9 additions & 4 deletions src/asmjs/asm_v_wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ AsmType wasmToAsmType(Type type) {
return ASM_INT64;
case v128:
assert(false && "v128 not implemented yet");
case funcref:
case anyref:
assert(false && "anyref is not supported by asm2wasm");
case nullref:
case exnref:
assert(false && "exnref is not supported by asm2wasm");
assert(false && "reference types are not supported by asm2wasm");
case none:
return ASM_NONE;
case unreachable:
Expand All @@ -77,10 +78,14 @@ char getSig(Type type) {
return 'd';
case v128:
return 'V';
case funcref:
return 'F';
case anyref:
return 'a';
return 'A';
case nullref:
return 'N';
case exnref:
return 'e';
return 'E';
case none:
return 'v';
case unreachable:
Expand Down
101 changes: 89 additions & 12 deletions src/binaryen-c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,16 @@ BinaryenLiteral toBinaryenLiteral(Literal x) {
case Type::f64:
ret.i64 = x.reinterpreti64();
break;
case Type::v128: {
case Type::v128:
memcpy(&ret.v128, x.getv128Ptr(), 16);
break;
}

case Type::anyref: // there's no anyref literals
case Type::exnref: // there's no exnref literals
case Type::funcref:
ret.func = x.getFunc().c_str();
break;
case Type::nullref:
break;
case Type::anyref:
case Type::exnref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
Expand All @@ -90,8 +93,12 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) {
return Literal(x.i64).castToF64();
case Type::v128:
return Literal(x.v128);
case Type::anyref: // there's no anyref literals
case Type::exnref: // there's no exnref literals
case Type::funcref:
return Literal::makeFuncref(x.func);
case Type::nullref:
return Literal::makeNullref();
case Type::anyref:
case Type::exnref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
Expand Down Expand Up @@ -209,8 +216,14 @@ void printArg(std::ostream& setup, std::ostream& out, BinaryenLiteral arg) {
out << "BinaryenLiteralVec128(" << array << ")";
break;
}
case Type::anyref: // there's no anyref literals
case Type::exnref: // there's no exnref literals
case Type::funcref:
out << "BinaryenLiteralFuncref(" << arg.func << ")";
break;
case Type::nullref:
out << "BinaryenLiteralNullref()";
break;
case Type::anyref:
case Type::exnref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
Expand Down Expand Up @@ -265,7 +278,9 @@ BinaryenType BinaryenTypeInt64(void) { return i64; }
BinaryenType BinaryenTypeFloat32(void) { return f32; }
BinaryenType BinaryenTypeFloat64(void) { return f64; }
BinaryenType BinaryenTypeVec128(void) { return v128; }
BinaryenType BinaryenTypeFuncref(void) { return funcref; }
BinaryenType BinaryenTypeAnyref(void) { return anyref; }
BinaryenType BinaryenTypeNullref(void) { return nullref; }
BinaryenType BinaryenTypeExnref(void) { return exnref; }
BinaryenType BinaryenTypeUnreachable(void) { return unreachable; }
BinaryenType BinaryenTypeAuto(void) { return uint32_t(-1); }
Expand Down Expand Up @@ -397,6 +412,15 @@ BinaryenExpressionId BinaryenMemoryCopyId(void) {
BinaryenExpressionId BinaryenMemoryFillId(void) {
return Expression::Id::MemoryFillId;
}
BinaryenExpressionId BinaryenRefNullId(void) {
return Expression::Id::RefNullId;
}
BinaryenExpressionId BinaryenRefIsNullId(void) {
return Expression::Id::RefIsNullId;
}
BinaryenExpressionId BinaryenRefFuncId(void) {
return Expression::Id::RefFuncId;
}
BinaryenExpressionId BinaryenTryId(void) { return Expression::Id::TryId; }
BinaryenExpressionId BinaryenThrowId(void) { return Expression::Id::ThrowId; }
BinaryenExpressionId BinaryenRethrowId(void) {
Expand Down Expand Up @@ -1330,17 +1354,22 @@ BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module,
BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module,
BinaryenExpressionRef condition,
BinaryenExpressionRef ifTrue,
BinaryenExpressionRef ifFalse) {
BinaryenExpressionRef ifFalse,
BinaryenType type) {
auto* ret = ((Module*)module)->allocator.alloc<Select>();

if (tracing) {
traceExpression(ret, "BinaryenSelect", condition, ifTrue, ifFalse);
traceExpression(ret, "BinaryenSelect", condition, ifTrue, ifFalse, type);
}

ret->condition = (Expression*)condition;
ret->ifTrue = (Expression*)ifTrue;
ret->ifFalse = (Expression*)ifFalse;
ret->finalize();
if (type != BinaryenTypeAuto()) {
ret->finalize(Type(type));
} else {
ret->finalize();
}
return static_cast<Expression*>(ret);
}
BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module,
Expand Down Expand Up @@ -1695,6 +1724,32 @@ BinaryenExpressionRef BinaryenPop(BinaryenModuleRef module, BinaryenType type) {
return static_cast<Expression*>(ret);
}

BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module) {
auto* ret = Builder(*(Module*)module).makeRefNull();
if (tracing) {
traceExpression(ret, "BinaryenRefNull");
}
return static_cast<Expression*>(ret);
}

BinaryenExpressionRef BinaryenRefIsNull(BinaryenModuleRef module,
BinaryenExpressionRef value) {
auto* ret = Builder(*(Module*)module).makeRefIsNull((Expression*)value);
if (tracing) {
traceExpression(ret, "BinaryenRefIsNull", value);
}
return static_cast<Expression*>(ret);
}

BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
const char* func) {
auto* ret = Builder(*(Module*)module).makeRefFunc(func);
if (tracing) {
traceExpression(ret, "BinaryenRefFunc", StringLit(func));
}
return static_cast<Expression*>(ret);
}

BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module,
BinaryenExpressionRef body,
BinaryenExpressionRef catchBody) {
Expand Down Expand Up @@ -2964,6 +3019,28 @@ BinaryenExpressionRef BinaryenPushGetValue(BinaryenExpressionRef expr) {
assert(expression->is<Push>());
return static_cast<Push*>(expression)->value;
}
// RefIsNull
BinaryenExpressionRef BinaryenRefIsNullGetValue(BinaryenExpressionRef expr) {
if (tracing) {
std::cout << " BinaryenRefIsNullGetValue(expressions[" << expressions[expr]
<< "]);\n";
}

auto* expression = (Expression*)expr;
assert(expression->is<RefIsNull>());
return static_cast<RefIsNull*>(expression)->value;
}
// RefFunc
const char* BinaryenRefFuncGetFunc(BinaryenExpressionRef expr) {
if (tracing) {
std::cout << " BinaryenRefFuncGetFunc(expressions[" << expressions[expr]
<< "]);\n";
}

auto* expression = (Expression*)expr;
assert(expression->is<RefFunc>());
return static_cast<RefFunc*>(expression)->func.c_str();
}
// Try
BinaryenExpressionRef BinaryenTryGetBody(BinaryenExpressionRef expr) {
if (tracing) {
Expand Down
19 changes: 18 additions & 1 deletion src/binaryen-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ BINARYEN_API BinaryenType BinaryenTypeInt64(void);
BINARYEN_API BinaryenType BinaryenTypeFloat32(void);
BINARYEN_API BinaryenType BinaryenTypeFloat64(void);
BINARYEN_API BinaryenType BinaryenTypeVec128(void);
BINARYEN_API BinaryenType BinaryenTypeFuncref(void);
BINARYEN_API BinaryenType BinaryenTypeAnyref(void);
BINARYEN_API BinaryenType BinaryenTypeNullref(void);
BINARYEN_API BinaryenType BinaryenTypeExnref(void);
BINARYEN_API BinaryenType BinaryenTypeUnreachable(void);
// Not a real type. Used as the last parameter to BinaryenBlock to let
Expand Down Expand Up @@ -158,6 +160,9 @@ BINARYEN_API BinaryenExpressionId BinaryenMemoryInitId(void);
BINARYEN_API BinaryenExpressionId BinaryenDataDropId(void);
BINARYEN_API BinaryenExpressionId BinaryenMemoryCopyId(void);
BINARYEN_API BinaryenExpressionId BinaryenMemoryFillId(void);
BINARYEN_API BinaryenExpressionId BinaryenRefNullId(void);
BINARYEN_API BinaryenExpressionId BinaryenRefIsNullId(void);
BINARYEN_API BinaryenExpressionId BinaryenRefFuncId(void);
BINARYEN_API BinaryenExpressionId BinaryenTryId(void);
BINARYEN_API BinaryenExpressionId BinaryenThrowId(void);
BINARYEN_API BinaryenExpressionId BinaryenRethrowId(void);
Expand Down Expand Up @@ -222,6 +227,7 @@ struct BinaryenLiteral {
float f32;
double f64;
uint8_t v128[16];
const char* func;
};
};

Expand Down Expand Up @@ -692,7 +698,8 @@ BINARYEN_API BinaryenExpressionRef
BinaryenSelect(BinaryenModuleRef module,
BinaryenExpressionRef condition,
BinaryenExpressionRef ifTrue,
BinaryenExpressionRef ifFalse);
BinaryenExpressionRef ifFalse,
BinaryenType type);
BINARYEN_API BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module,
BinaryenExpressionRef value);
// Return: value can be NULL
Expand Down Expand Up @@ -797,6 +804,11 @@ BinaryenMemoryFill(BinaryenModuleRef module,
BinaryenExpressionRef dest,
BinaryenExpressionRef value,
BinaryenExpressionRef size);
BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module);
BINARYEN_API BinaryenExpressionRef
BinaryenRefIsNull(BinaryenModuleRef module, BinaryenExpressionRef value);
BINARYEN_API BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
const char* func);
BINARYEN_API BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module,
BinaryenExpressionRef body,
BinaryenExpressionRef catchBody);
Expand Down Expand Up @@ -1035,6 +1047,11 @@ BinaryenMemoryFillGetValue(BinaryenExpressionRef expr);
BINARYEN_API BinaryenExpressionRef
BinaryenMemoryFillGetSize(BinaryenExpressionRef expr);

BINARYEN_API BinaryenExpressionRef
BinaryenRefIsNullGetValue(BinaryenExpressionRef expr);

BINARYEN_API const char* BinaryenRefFuncGetFunc(BinaryenExpressionRef expr);

BINARYEN_API BinaryenExpressionRef
BinaryenTryGetBody(BinaryenExpressionRef expr);
BINARYEN_API BinaryenExpressionRef
Expand Down
Loading

0 comments on commit bcc7614

Please sign in to comment.