Skip to content

Commit

Permalink
feat: Update reference types support to latest Binaryen (#1465)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcodeIO authored Sep 19, 2020
1 parent c76eb81 commit 9f38cc4
Show file tree
Hide file tree
Showing 34 changed files with 1,095 additions and 551 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ jobs:
- uses: dcodeIO/setup-node-nvm@master
with:
node-mirror: https://nodejs.org/download/v8-canary/
node-version: "15.0.0-v8-canary202007077c53168ead"
node-version: "node"
- name: Install dependencies
run: npm ci --no-audit
- name: Clean distribution files
run: npm run clean
- name: Test experimental features
env:
ASC_FEATURES: mutable-globals,threads,reference-types,bigint-integration
ASC_FEATURES: mutable-globals,threads,reference-types,bigint-integration,gc
run: |
npm run test:compiler rt/flags features/js-bigint-integration features/reference-types features/threads
test-runtimes:
Expand Down
4 changes: 3 additions & 1 deletion cli/asc.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,15 @@
" simd SIMD types and operations.",
" threads Threading and atomic operations.",
" reference-types Reference types and operations.",
" gc Garbage collection (anyref, WIP).",
""
],
"TODO_doesNothingYet": [
" nontrapping-f2i Non-trapping float to integer ops.",
" exception-handling Exception handling.",
" tail-calls Tail call operations.",
" multi-value Multi value types."
" multi-value Multi value types.",
" memory64 Memory64 operations."
],
"type": "S",
"mutuallyExclusive": "disable"
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"url": "https://github.com/AssemblyScript/assemblyscript/issues"
},
"dependencies": {
"binaryen": "96.0.0-nightly.20200911",
"binaryen": "97.0.0-nightly.20200919",
"long": "^4.0.0",
"source-map-support": "^0.5.19",
"ts-node": "^6.2.0"
Expand Down
59 changes: 26 additions & 33 deletions src/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ import {
import {
BinaryOp,
UnaryOp,
HostOp,
AtomicRMWOp,
SIMDExtractOp,
SIMDReplaceOp,
Expand Down Expand Up @@ -968,39 +967,16 @@ function builtin_nameof(ctx: BuiltinContext): ExpressionRef {
return module.unreachable();
}
var value: string;
if (resultType.isReference) {
if (resultType.isInternalReference) {
let classReference = resultType.getClass();
if (classReference) {
value = classReference.name;
} else {
let signatureReference = resultType.getSignature();
if (signatureReference) {
value = "Function";
} else {
assert(resultType.isExternalReference);
value = "Externref";
}
assert(resultType.getSignature());
value = "Function";
}
} else {
switch (resultType.kind) {
case TypeKind.BOOL: { value = "bool"; break; }
case TypeKind.I8: { value = "i8"; break; }
case TypeKind.U8: { value = "u8"; break; }
case TypeKind.I16: { value = "i16"; break; }
case TypeKind.U16: { value = "u16"; break; }
case TypeKind.I32: { value = "i32"; break; }
case TypeKind.U32: { value = "u32"; break; }
case TypeKind.F32: { value = "f32"; break; }
case TypeKind.I64: { value = "i64"; break; }
case TypeKind.U64: { value = "u64"; break; }
case TypeKind.F64: { value = "f64"; break; }
case TypeKind.ISIZE: { value = "isize"; break; }
case TypeKind.USIZE: { value = "usize"; break; }
case TypeKind.V128: { value = "v128"; break; }
case TypeKind.EXTERNREF: { value = "externref"; break; }
default: assert(false);
case TypeKind.VOID: { value = "void"; break; }
}
value = resultType.toString();
}
return compiler.ensureStaticString(value);
}
Expand Down Expand Up @@ -2472,7 +2448,7 @@ function builtin_memory_size(ctx: BuiltinContext): ExpressionRef {
checkTypeAbsent(ctx) |
checkArgsRequired(ctx, 0)
) return module.unreachable();
return module.host(HostOp.MemorySize);
return module.memory_size();
}
builtins.set(BuiltinNames.memory_size, builtin_memory_size);

Expand All @@ -2485,10 +2461,7 @@ function builtin_memory_grow(ctx: BuiltinContext): ExpressionRef {
checkTypeAbsent(ctx) |
checkArgsRequired(ctx, 1)
) return module.unreachable();
var operands = ctx.operands;
return module.host(HostOp.MemoryGrow, null, [
compiler.compileExpression(operands[0], Type.i32, Constraints.CONV_IMPLICIT)
]);
return module.memory_grow(compiler.compileExpression(ctx.operands[0], Type.i32, Constraints.CONV_IMPLICIT));
}
builtins.set(BuiltinNames.memory_grow, builtin_memory_grow);

Expand Down Expand Up @@ -2775,6 +2748,11 @@ function builtin_assert(ctx: BuiltinContext): ExpressionRef {
// TODO: also check for NaN in float assertions, as in `Boolean(NaN) -> false`?
case TypeKind.F32: return module.if(module.binary(BinaryOp.EqF32, arg0, module.f32(0)), abort);
case TypeKind.F64: return module.if(module.binary(BinaryOp.EqF64, arg0, module.f64(0)), abort);
case TypeKind.FUNCREF:
case TypeKind.EXTERNREF:
case TypeKind.EXNREF:
case TypeKind.ANYREF: return module.if(module.ref_is_null(arg0), abort);

}
} else {
compiler.currentType = type.nonNullableType;
Expand Down Expand Up @@ -2852,6 +2830,21 @@ function builtin_assert(ctx: BuiltinContext): ExpressionRef {
flow.freeTempLocal(temp);
return ret;
}
case TypeKind.FUNCREF:
case TypeKind.EXTERNREF:
case TypeKind.EXNREF:
case TypeKind.ANYREF: {
let temp = flow.getTempLocal(type);
let ret = module.if(
module.ref_is_null(
module.local_tee(temp.index, arg0)
),
abort,
module.local_get(temp.index, NativeType.F64)
);
flow.freeTempLocal(temp);
return ret;
}
}
}
compiler.error(
Expand Down
8 changes: 8 additions & 0 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ export namespace CommonNames {
export const f32 = "f32";
export const f64 = "f64";
export const v128 = "v128";
export const funcref = "funcref";
export const externref = "externref";
export const exnref = "exnref";
export const anyref = "anyref";
export const i8x16 = "i8x16";
export const u8x16 = "u8x16";
export const i16x8 = "i16x8";
Expand Down Expand Up @@ -170,6 +173,8 @@ export namespace CommonNames {
export const ASC_FEATURE_TAIL_CALLS = "ASC_FEATURE_TAIL_CALLS";
export const ASC_FEATURE_REFERENCE_TYPES = "ASC_FEATURE_REFERENCE_TYPES";
export const ASC_FEATURE_MULTI_VALUE = "ASC_FEATURE_MULTI_VALUE";
export const ASC_FEATURE_GC = "ASC_FEATURE_GC";
export const ASC_FEATURE_MEMORY64 = "ASC_FEATURE_MEMORY64";
// classes
export const I8 = "I8";
export const I16 = "I16";
Expand All @@ -185,7 +190,10 @@ export namespace CommonNames {
export const F32 = "F32";
export const F64 = "F64";
export const V128 = "V128";
export const Funcref = "Funcref";
export const Externref = "Externref";
export const Exnref = "Exnref";
export const Anyref = "Anyref";
export const String = "String";
export const Array = "Array";
export const StaticArray = "StaticArray";
Expand Down
83 changes: 48 additions & 35 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,8 @@ export class Compiler extends DiagnosticEmitter {
if (options.hasFeature(Feature.TAIL_CALLS)) featureFlags |= FeatureFlags.TailCall;
if (options.hasFeature(Feature.REFERENCE_TYPES)) featureFlags |= FeatureFlags.ReferenceTypes;
if (options.hasFeature(Feature.MULTI_VALUE)) featureFlags |= FeatureFlags.MultiValue;
if (options.hasFeature(Feature.GC)) featureFlags |= FeatureFlags.GC;
if (options.hasFeature(Feature.MEMORY64)) featureFlags |= FeatureFlags.Memory64;
module.setFeatures(featureFlags);

// set up the main start function
Expand Down Expand Up @@ -3624,12 +3626,21 @@ export class Compiler extends DiagnosticEmitter {
fromType = fromType.nonNullableType;
}
if (fromType.isAssignableTo(toType)) { // downcast or same
assert(fromType.kind == toType.kind);
assert(toType.isExternalReference || fromType.kind == toType.kind);
this.currentType = toType;
return expr;
}
if (explicit && toType.nonNullableType.isAssignableTo(fromType)) { // upcast
// <Cat | null>(<Animal>maybeCat)
if (toType.isExternalReference) {
this.error(
DiagnosticCode.Not_implemented_0,
reportNode.range,
"ref.cast"
);
this.currentType = toType;
return module.unreachable();
}
assert(fromType.kind == toType.kind);
if (!this.options.noAssert) {
expr = this.makeRuntimeUpcastCheck(expr, fromType, toType, reportNode);
Expand Down Expand Up @@ -4390,12 +4401,15 @@ export class Compiler extends DiagnosticEmitter {
);
break;
}
case TypeKind.EXTERNREF: {
// TODO: ref.eq
case TypeKind.FUNCREF:
case TypeKind.EXTERNREF:
case TypeKind.EXNREF:
case TypeKind.ANYREF: {
this.error(
DiagnosticCode.Not_implemented_0,
DiagnosticCode.Operation_0_cannot_be_applied_to_type_1,
expression.range,
"ref.eq instruction"
"ref.eq",
commonType.toString()
);
expr = module.unreachable();
break;
Expand Down Expand Up @@ -4491,12 +4505,15 @@ export class Compiler extends DiagnosticEmitter {
);
break;
}
case TypeKind.EXTERNREF: {
// TODO: !ref.eq
case TypeKind.FUNCREF:
case TypeKind.EXTERNREF:
case TypeKind.EXNREF:
case TypeKind.ANYREF: {
this.error(
DiagnosticCode.Not_implemented_0,
DiagnosticCode.Operation_0_cannot_be_applied_to_type_1,
expression.range,
"ref.eq instruction"
"ref.eq",
commonType.toString()
);
expr = module.unreachable();
break;
Expand Down Expand Up @@ -8311,13 +8328,7 @@ export class Compiler extends DiagnosticEmitter {
this.currentType = signatureReference.type.asNullable();
return options.isWasm64 ? module.i64(0) : module.i32(0);
}
// TODO: return null ref for externref or funcref
this.error(
DiagnosticCode.Not_implemented_0,
expression.range,
"ref.null"
);
return module.unreachable();
return this.makeZero(contextualType, expression);
}
this.currentType = options.usizeType;
this.warning(
Expand Down Expand Up @@ -8508,7 +8519,7 @@ export class Compiler extends DiagnosticEmitter {
);
if (!functionInstance || !this.compileFunction(functionInstance)) return module.unreachable();
if (contextualType.isExternalReference) {
this.currentType = Type.externref;
this.currentType = Type.funcref;
return module.ref_func(functionInstance.internalName);
}
let offset = this.ensureRuntimeFunction(functionInstance);
Expand Down Expand Up @@ -10619,7 +10630,17 @@ export class Compiler extends DiagnosticEmitter {
checkTypeSupported(type: Type, reportNode: Node): bool {
switch (type.kind) {
case TypeKind.V128: return this.checkFeatureEnabled(Feature.SIMD, reportNode);
case TypeKind.EXTERNREF: return this.checkFeatureEnabled(Feature.REFERENCE_TYPES, reportNode);
case TypeKind.FUNCREF:
case TypeKind.EXTERNREF:
return this.checkFeatureEnabled(Feature.REFERENCE_TYPES, reportNode);
case TypeKind.EXNREF: {
return this.checkFeatureEnabled(Feature.REFERENCE_TYPES, reportNode)
&& this.checkFeatureEnabled(Feature.EXCEPTION_HANDLING, reportNode);
}
case TypeKind.ANYREF: {
return this.checkFeatureEnabled(Feature.REFERENCE_TYPES, reportNode)
&& this.checkFeatureEnabled(Feature.GC, reportNode);
}
}
let classReference = type.getClass();
if (classReference) {
Expand Down Expand Up @@ -10712,14 +10733,11 @@ export class Compiler extends DiagnosticEmitter {
case TypeKind.F32: return module.f32(0);
case TypeKind.F64: return module.f64(0);
case TypeKind.V128: return module.v128(v128_zero);
case TypeKind.FUNCREF:
case TypeKind.EXTERNREF:
// TODO: return null ref for both externref as well as funcref
this.error(
DiagnosticCode.Not_implemented_0,
reportNode.range,
"ref.null"
);
return module.unreachable();
case TypeKind.EXNREF:
case TypeKind.ANYREF:
return module.ref_null(type.toNativeType());
}
}

Expand Down Expand Up @@ -10824,16 +10842,11 @@ export class Compiler extends DiagnosticEmitter {
module.i64(0xFFFFFFFE, 0xFFDFFFFF) // (0x7FF0000000000000 - 1) << 1
);
}
case TypeKind.EXTERNREF: {
// TODO: non-null object might still be considered falseish
// i.e. a ref to Boolean(false), Number(0), String("") etc.
// TODO: return module.unary(UnaryOp.EqzI32, module.ref_is_null(expr));
this.error(
DiagnosticCode.Not_implemented_0,
reportNode.range,
"ref.is_null"
);
return module.unreachable();
case TypeKind.FUNCREF:
case TypeKind.EXTERNREF:
case TypeKind.EXNREF:
case TypeKind.ANYREF:{
return module.ref_is_null(expr);
}
default: {
assert(false);
Expand Down
14 changes: 14 additions & 0 deletions src/flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,10 @@ export class Flow {
case <u32>NativeType.F32: { temps = parentFunction.tempF32s; break; }
case <u32>NativeType.F64: { temps = parentFunction.tempF64s; break; }
case <u32>NativeType.V128: { temps = parentFunction.tempV128s; break; }
case <u32>NativeType.Funcref: { temps = parentFunction.tempFuncrefs; break; }
case <u32>NativeType.Externref: { temps = parentFunction.tempExternrefs; break; }
case <u32>NativeType.Exnref: { temps = parentFunction.tempExnrefs; break; }
case <u32>NativeType.Anyref: { temps = parentFunction.tempAnyrefs; break; }
default: throw new Error("concrete type expected");
}
var local: Local;
Expand Down Expand Up @@ -395,6 +397,12 @@ export class Flow {
else parentFunction.tempV128s = temps = [];
break;
}
case <u32>NativeType.Funcref: {
let tempFuncrefs = parentFunction.tempFuncrefs;
if (tempFuncrefs) temps = tempFuncrefs;
else parentFunction.tempFuncrefs = temps = [];
break;
}
case <u32>NativeType.Externref: {
let tempExternrefs = parentFunction.tempExternrefs;
if (tempExternrefs) temps = tempExternrefs;
Expand All @@ -407,6 +415,12 @@ export class Flow {
else parentFunction.tempExnrefs = temps = [];
break;
}
case <u32>NativeType.Anyref: {
let tempAnyrefs = parentFunction.tempAnyrefs;
if (tempAnyrefs) temps = tempAnyrefs;
else parentFunction.tempAnyrefs = temps = [];
break;
}
default: throw new Error("concrete type expected");
}
assert(local.index >= 0);
Expand Down
Loading

0 comments on commit 9f38cc4

Please sign in to comment.