Skip to content

Commit

Permalink
Add support for reference types proposal
Browse files Browse the repository at this point in the history
  • Loading branch information
aheejin committed Dec 8, 2019
1 parent 5bcbae5 commit d673f61
Show file tree
Hide file tree
Showing 89 changed files with 7,426 additions and 1,545 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ Current Trunk

- `local.tee`'s C/Binaryen.js API now takes an additional type parameter for its
local type, like `local.get`. This is required to handle subtypes.
- Reference type support is added. Supported instructions are `ref.null`,
`ref.is_null`, `ref.func`, and typed `select`. Table instructions are not
supported yet.
- Added load_splat SIMD instructions
- Binaryen.js instruction API changes:
- `notify` -> `atomic.notify`
Expand Down
6 changes: 4 additions & 2 deletions check.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,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
# HACK Remove this condition after nullref is implemented in V8
if 'reference_types.wast' 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
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']])


# 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 @@ -467,6 +469,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
21 changes: 15 additions & 6 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 Expand Up @@ -109,9 +114,13 @@ Type sigToType(char sig) {
return f64;
case 'V':
return v128;
case 'a':
case 'F':
return funcref;
case 'A':
return anyref;
case 'e':
case 'N':
return nullref;
case 'E':
return exnref;
case 'v':
return none;
Expand Down
97 changes: 76 additions & 21 deletions src/binaryen-c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@ using namespace wasm;

// Literal utilities

static_assert(sizeof(BinaryenLiteral) == sizeof(Literal),
"Binaryen C API literal must match wasm.h");

BinaryenLiteral toBinaryenLiteral(Literal x) {
BinaryenLiteral ret;
ret.type = x.type;
Expand All @@ -65,15 +62,15 @@ 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::none:
case Type::unreachable:
case Type::nullref:
break;
case Type::funcref:
ret.func = x.func.c_str();
break;
default:
WASM_UNREACHABLE("unexpected type");
}
return ret;
Expand All @@ -91,10 +88,7 @@ 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::none:
case Type::unreachable:
default:
WASM_UNREACHABLE("unexpected type");
}
WASM_UNREACHABLE("invalid type");
Expand Down Expand Up @@ -212,10 +206,7 @@ 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::none:
case Type::unreachable:
default:
WASM_UNREACHABLE("unexpected type");
}
}
Expand Down Expand Up @@ -268,7 +259,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 @@ -400,6 +393,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 @@ -1392,17 +1394,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 @@ -1757,6 +1764,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 anyref) {
auto* ret = Builder(*(Module*)module).makeRefIsNull((Expression*)anyref);
if (tracing) {
traceExpression(ret, "BinaryenRefIsNull", anyref);
}
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 @@ -3026,6 +3059,28 @@ BinaryenExpressionRef BinaryenPushGetValue(BinaryenExpressionRef expr) {
assert(expression->is<Push>());
return static_cast<Push*>(expression)->value;
}
// RefIsNull
BinaryenExpressionRef BinaryenRefIsNullGetAnyref(BinaryenExpressionRef expr) {
if (tracing) {
std::cout << " BinaryenRefIsNullGetAnyref(expressions["
<< expressions[expr] << "]);\n";
}

auto* expression = (Expression*)expr;
assert(expression->is<RefIsNull>());
return static_cast<RefIsNull*>(expression)->anyref;
}
// 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 @@ -99,7 +99,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 @@ -159,6 +161,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 @@ -240,6 +245,7 @@ struct BinaryenLiteral {
double f64;
uint8_t v128[16];
};
const char* func;
};

BINARYEN_API struct BinaryenLiteral BinaryenLiteralInt32(int32_t x);
Expand Down Expand Up @@ -705,7 +711,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 @@ -810,6 +817,11 @@ BinaryenMemoryFill(BinaryenModuleRef module,
BinaryenExpressionRef dest,
BinaryenExpressionRef value,
BinaryenExpressionRef size);
BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module);
BINARYEN_API BinaryenExpressionRef
BinaryenRefIsNull(BinaryenModuleRef module, BinaryenExpressionRef anyref);
BINARYEN_API BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
const char* func);
BINARYEN_API BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module,
BinaryenExpressionRef body,
BinaryenExpressionRef catchBody);
Expand Down Expand Up @@ -1048,6 +1060,11 @@ BinaryenMemoryFillGetValue(BinaryenExpressionRef expr);
BINARYEN_API BinaryenExpressionRef
BinaryenMemoryFillGetSize(BinaryenExpressionRef expr);

BINARYEN_API BinaryenExpressionRef
BinaryenRefIsNullGetAnyref(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 d673f61

Please sign in to comment.