Skip to content

Commit

Permalink
Add support for reference types proposal
Browse files Browse the repository at this point in the history
This adds support for the reference type proposal. This adds 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 does not include table instructions yet. This also does not include
wasm2js support.

This does not pass `fuzz_opt.py` yet because there are remaining bugs
related to `nullref` handling, because `nullref` is not allowed to be
written to text or binary format. We are discussing whether we should
allow it to be written in WebAssembly/reference-types#60 now.

This is not ready for review yet because it does not pass fuzzer now;
I'm uploading this just to show how the current a bit ad-hoc `nullref`
handling looks like. So don't spend too much time on reviewing each
detail for now. I apprciate some high-level comments on how we should
handle `nullref` or other stuff.
  • Loading branch information
aheejin committed Nov 19, 2019
1 parent ee3022f commit 3227168
Show file tree
Hide file tree
Showing 83 changed files with 4,590 additions and 2,177 deletions.
7 changes: 7 additions & 0 deletions scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
("v128.pop", "makePop(v128)"),
("anyref.pop", "makePop(anyref)"),
("exnref.pop", "makePop(exnref)"),
("funcref.pop", "makePop(funcref)"),
("nullref.pop", "makePop(nullref)"),
("i32.load", "makeLoad(s, i32, /*isAtomic=*/false)"),
("i64.load", "makeLoad(s, i64, /*isAtomic=*/false)"),
("f32.load", "makeLoad(s, f32, /*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
18 changes: 12 additions & 6 deletions src/asmjs/asm_v_wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ AsmType wasmToAsmType(Type type) {
case v128:
assert(false && "v128 not implemented yet");
case anyref:
assert(false && "anyref is not supported by asm2wasm");
case funcref:
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 @@ -78,11 +79,14 @@ char getSig(Type type) {
case v128:
return 'V';
case anyref:
return 'a';
return 'A';
case funcref:
return 'F';
case exnref:
return 'e';
return 'E';
case none:
return 'v';
case nullref: // nullref cannot be included in signatures
case unreachable:
WASM_UNREACHABLE();
}
Expand All @@ -109,10 +113,12 @@ Type sigToType(char sig) {
return f64;
case 'V':
return v128;
case 'a':
case 'A':
return anyref;
case 'e':
case 'E':
return exnref;
case 'F':
return funcref;
case 'v':
return none;
default:
Expand Down
90 changes: 71 additions & 19 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 @@ -69,11 +66,7 @@ BinaryenLiteral toBinaryenLiteral(Literal x) {
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:
default:
WASM_UNREACHABLE();
}
return ret;
Expand All @@ -91,10 +84,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();
}
WASM_UNREACHABLE();
Expand Down Expand Up @@ -212,10 +202,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();
}
}
Expand Down Expand Up @@ -269,6 +256,8 @@ BinaryenType BinaryenTypeFloat32(void) { return f32; }
BinaryenType BinaryenTypeFloat64(void) { return f64; }
BinaryenType BinaryenTypeVec128(void) { return v128; }
BinaryenType BinaryenTypeAnyref(void) { return anyref; }
BinaryenType BinaryenTypeFuncref(void) { return funcref; }
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 @@ -364,6 +353,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 @@ -1355,17 +1353,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 @@ -1720,6 +1723,33 @@ 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));
}
ret->finalize();
return static_cast<Expression*>(ret);
}

BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module,
BinaryenExpressionRef body,
BinaryenExpressionRef catchBody) {
Expand Down Expand Up @@ -2989,6 +3019,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
18 changes: 17 additions & 1 deletion src/binaryen-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ BINARYEN_API BinaryenType BinaryenTypeFloat32(void);
BINARYEN_API BinaryenType BinaryenTypeFloat64(void);
BINARYEN_API BinaryenType BinaryenTypeVec128(void);
BINARYEN_API BinaryenType BinaryenTypeAnyref(void);
BINARYEN_API BinaryenType BinaryenTypeFuncref(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 @@ -145,6 +147,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 @@ -689,7 +694,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 @@ -794,6 +800,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 @@ -1032,6 +1043,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
64 changes: 47 additions & 17 deletions src/gen-s-parser.inc
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,9 @@ switch (op[0]) {
default: goto parse_error;
}
}
case 'u':
if (strcmp(op, "funcref.pop") == 0) { return makePop(funcref); }
goto parse_error;
default: goto parse_error;
}
}
Expand Down Expand Up @@ -2474,30 +2477,57 @@ switch (op[0]) {
default: goto parse_error;
}
}
case 'n':
if (strcmp(op, "nop") == 0) { return makeNop(); }
goto parse_error;
case 'n': {
switch (op[1]) {
case 'o':
if (strcmp(op, "nop") == 0) { return makeNop(); }
goto parse_error;
case 'u':
if (strcmp(op, "nullref.pop") == 0) { return makePop(nullref); }
goto parse_error;
default: goto parse_error;
}
}
case 'p':
if (strcmp(op, "push") == 0) { return makePush(s); }
goto parse_error;
case 'r': {
switch (op[3]) {
case 'h':
if (strcmp(op, "rethrow") == 0) { return makeRethrow(s); }
goto parse_error;
case 'u': {
switch (op[6]) {
case '\0':
if (strcmp(op, "return") == 0) { return makeReturn(s); }
switch (op[2]) {
case 'f': {
switch (op[4]) {
case 'f':
if (strcmp(op, "ref.func") == 0) { return makeRefFunc(s); }
goto parse_error;
case '_': {
switch (op[11]) {
case 'i':
if (strcmp(op, "ref.is_null") == 0) { return makeRefIsNull(s); }
goto parse_error;
case 'n':
if (strcmp(op, "ref.null") == 0) { return makeRefNull(s); }
goto parse_error;
default: goto parse_error;
}
}
case 't': {
switch (op[3]) {
case 'h':
if (strcmp(op, "rethrow") == 0) { return makeRethrow(s); }
goto parse_error;
case 'u': {
switch (op[6]) {
case '\0':
if (strcmp(op, "return_call") == 0) { return makeCall(s, /*isReturn=*/true); }
goto parse_error;
case '_':
if (strcmp(op, "return_call_indirect") == 0) { return makeCallIndirect(s, /*isReturn=*/true); }
if (strcmp(op, "return") == 0) { return makeReturn(s); }
goto parse_error;
case '_': {
switch (op[11]) {
case '\0':
if (strcmp(op, "return_call") == 0) { return makeCall(s, /*isReturn=*/true); }
goto parse_error;
case '_':
if (strcmp(op, "return_call_indirect") == 0) { return makeCallIndirect(s, /*isReturn=*/true); }
goto parse_error;
default: goto parse_error;
}
}
default: goto parse_error;
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/ir/ExpressionAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ template<typename T> void visitImmediates(Expression* curr, T& visitor) {
visitor.visitInt(curr->op);
visitor.visitNonScopeName(curr->nameOperand);
}
void visitRefNull(RefNull* curr) {}
void visitRefIsNull(RefIsNull* curr) {}
void visitRefFunc(RefFunc* curr) { visitor.visitNonScopeName(curr->func); }
void visitTry(Try* curr) {}
void visitThrow(Throw* curr) { visitor.visitNonScopeName(curr->event); }
void visitRethrow(Rethrow* curr) {}
Expand Down
Loading

0 comments on commit 3227168

Please sign in to comment.