Skip to content

Fix crash on reference typed constant #2238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,7 @@ function builtin_isConstant(ctx: BuiltinContext): ExpressionRef {
var expr = compiler.compileExpression(ctx.operands[0], Type.auto);
compiler.currentType = Type.bool;
if (!mustPreserveSideEffects(expr, module.ref)) {
return module.i32(getExpressionId(expr) == ExpressionId.Const ? 1 : 0);
return module.i32(module.isConstExpression(expr) ? 1 : 0);
}
return module.block(null, [
module.maybeDrop(expr),
Expand Down
16 changes: 7 additions & 9 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1158,16 +1158,14 @@ export class Compiler extends DiagnosticEmitter {
this.currentFlow = previousFlow;
}

// If not a constant, attempt to precompute
if (getExpressionId(initExpr) != ExpressionId.Const) {
// If not a constant expression, attempt to precompute
if (!module.isConstExpression(initExpr)) {
if (isDeclaredConstant) {
if (getExpressionId(initExpr) != ExpressionId.Const) {
let precomp = module.runExpression(initExpr, ExpressionRunnerFlags.PreserveSideeffects);
if (precomp) {
initExpr = precomp;
} else {
initializeInStart = true;
}
let precomp = module.runExpression(initExpr, ExpressionRunnerFlags.PreserveSideeffects);
if (precomp) {
initExpr = precomp;
} else {
initializeInStart = true;
}
} else {
initializeInStart = true;
Expand Down
25 changes: 24 additions & 1 deletion src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2582,12 +2582,35 @@ export class Module {
var runner = binaryen._ExpressionRunnerCreate(this.ref, flags, maxDepth, maxLoopIterations);
var precomp = binaryen._ExpressionRunnerRunAndDispose(runner, expr);
if (precomp) {
assert(getExpressionId(precomp) == ExpressionId.Const);
if (!this.isConstExpression(precomp)) return 0;
assert(getExpressionType(precomp) == getExpressionType(expr));
}
return precomp;
}

isConstExpression(expr: ExpressionRef, features: FeatureFlags = 0): bool {
switch (getExpressionId(expr)) {
case ExpressionId.Const:
case ExpressionId.RefNull:
case ExpressionId.RefFunc:
case ExpressionId.I31New: return true;
case ExpressionId.Binary: {
if (this.getFeatures() & FeatureFlags.ExtendedConst) {
switch (getBinaryOp(expr)) {
case BinaryOp.AddI32:
case BinaryOp.SubI32:
case BinaryOp.MulI32:
case BinaryOp.AddI64:
case BinaryOp.SubI64:
case BinaryOp.MulI64: return this.isConstExpression(getBinaryLeft(expr)) && this.isConstExpression(getBinaryRight(expr));
}
}
break;
}
}
return false;
}

// source map generation

addDebugInfoFile(name: string): Index {
Expand Down
2 changes: 2 additions & 0 deletions tests/compiler/features/gc.debug.wat
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
(type $none_=>_none (func))
(type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32)))
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
(global $features/gc/a anyref (ref.null any))
(global $~lib/memory/__data_end i32 (i32.const 60))
(global $~lib/memory/__stack_pointer (mut i32) (i32.const 16444))
(global $~lib/memory/__heap_base i32 (i32.const 16444))
Expand All @@ -10,6 +11,7 @@
(data (i32.const 12) ",\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\1c\00\00\00f\00e\00a\00t\00u\00r\00e\00s\00/\00g\00c\00.\00t\00s\00")
(table $0 1 funcref)
(elem $0 (i32.const 1))
(export "a" (global $features/gc/a))
(export "memory" (memory $0))
(export "_start" (func $~start))
(func $features/gc/test_i31
Expand Down
2 changes: 2 additions & 0 deletions tests/compiler/features/gc.release.wat
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
(module
(type $none_=>_none (func))
(global $features/gc/a anyref (ref.null any))
(memory $0 1)
(data (i32.const 1036) ",")
(data (i32.const 1048) "\01\00\00\00\1c\00\00\00f\00e\00a\00t\00u\00r\00e\00s\00/\00g\00c\00.\00t\00s")
(export "a" (global $features/gc/a))
(export "memory" (memory $0))
(export "_start" (func $~start))
(func $~start
Expand Down
6 changes: 6 additions & 0 deletions tests/compiler/features/gc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ function test_i31(): void {
}

test_i31();

// constant globals

export const a: anyref = null;
// export const b: i31ref = null; // TODO: not yet nullable in Binaryen
// export const c: dataref = null; // TODO: not yet nullable in Binaryen
14 changes: 5 additions & 9 deletions tests/compiler/features/reference-types.debug.wat
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
(global $features/reference-types/externGlobalInit (mut externref) (ref.null extern))
(global $features/reference-types/anyGlobal (mut anyref) (ref.null any))
(global $features/reference-types/anyGlobalInit (mut anyref) (ref.null any))
(global $features/reference-types/otherFuncGlobal (mut funcref) (ref.null func))
(global $features/reference-types/otherFuncGlobal (mut funcref) (ref.func $features/reference-types/someFunc))
(global $features/reference-types/a externref (ref.null extern))
(global $features/reference-types/b funcref (ref.null func))
(global $~lib/memory/__data_end i32 (i32.const 92))
(global $~lib/memory/__stack_pointer (mut i32) (i32.const 16476))
(global $~lib/memory/__heap_base i32 (i32.const 16476))
Expand All @@ -26,6 +28,8 @@
(export "somethingReal" (func $features/reference-types/somethingReal))
(export "somethingNull" (func $features/reference-types/somethingNull))
(export "internal" (func $features/reference-types/internal))
(export "a" (global $features/reference-types/a))
(export "b" (global $features/reference-types/b))
(export "memory" (memory $0))
(start $~start)
(func $features/reference-types/testLocal<funcref>
Expand Down Expand Up @@ -268,8 +272,6 @@
call $~lib/builtins/abort
unreachable
end
ref.null func
global.set $features/reference-types/funcGlobalInit
global.get $features/reference-types/funcGlobalInit
ref.is_null
i32.eqz
Expand Down Expand Up @@ -311,8 +313,6 @@
call $~lib/builtins/abort
unreachable
end
ref.null extern
global.set $features/reference-types/externGlobalInit
global.get $features/reference-types/externGlobalInit
ref.is_null
i32.eqz
Expand Down Expand Up @@ -354,8 +354,6 @@
call $~lib/builtins/abort
unreachable
end
ref.null any
global.set $features/reference-types/anyGlobalInit
global.get $features/reference-types/anyGlobalInit
ref.is_null
i32.eqz
Expand Down Expand Up @@ -384,8 +382,6 @@
call $~lib/builtins/abort
unreachable
end
ref.func $features/reference-types/someFunc
global.set $features/reference-types/otherFuncGlobal
global.get $features/reference-types/otherFuncGlobal
ref.is_null
if
Expand Down
4 changes: 4 additions & 0 deletions tests/compiler/features/reference-types.release.wat
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
(import "reference-types" "external" (func $features/reference-types/external (param externref) (result externref)))
(global $features/reference-types/funcGlobal (mut funcref) (ref.null func))
(global $features/reference-types/anyGlobal (mut anyref) (ref.null any))
(global $features/reference-types/a externref (ref.null extern))
(global $features/reference-types/b funcref (ref.null func))
(memory $0 1)
(data (i32.const 1036) "L")
(data (i32.const 1048) "\01\00\00\006\00\00\00f\00e\00a\00t\00u\00r\00e\00s\00/\00r\00e\00f\00e\00r\00e\00n\00c\00e\00-\00t\00y\00p\00e\00s\00.\00t\00s")
Expand All @@ -17,6 +19,8 @@
(export "somethingReal" (func $features/reference-types/somethingReal))
(export "somethingNull" (func $features/reference-types/somethingNull))
(export "internal" (func $features/reference-types/internal))
(export "a" (global $features/reference-types/a))
(export "b" (global $features/reference-types/b))
(export "memory" (memory $0))
(start $~start)
(func $features/reference-types/someFunc
Expand Down
5 changes: 5 additions & 0 deletions tests/compiler/features/reference-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,8 @@ assert(otherFuncGlobal);
// can assign any reference type to anyref

anyGlobal = funcGlobal;

// constant globals

export const a: externref = null;
export const b: funcref = null;