From 3cdfcb98c3ddbdcd0c1662b0306963843dc22d72 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 25 Mar 2022 20:09:45 +0100 Subject: [PATCH 1/2] Fix crash on reference typed constant --- src/builtins.ts | 2 +- src/compiler.ts | 16 ++++++------ src/module.ts | 25 ++++++++++++++++++- tests/compiler/features/gc.debug.wat | 2 ++ tests/compiler/features/gc.release.wat | 2 ++ tests/compiler/features/gc.ts | 6 +++++ .../features/reference-types.debug.wat | 14 ++++------- .../features/reference-types.release.wat | 4 +++ tests/compiler/features/reference-types.ts | 5 ++++ 9 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/builtins.ts b/src/builtins.ts index 47ee2fe435..a3171074ef 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -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), diff --git a/src/compiler.ts b/src/compiler.ts index 73959fefc0..b8682d41dc 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -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; diff --git a/src/module.ts b/src/module.ts index 16aa7c058b..e3d9d91f9b 100644 --- a/src/module.ts +++ b/src/module.ts @@ -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 expr; 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 { diff --git a/tests/compiler/features/gc.debug.wat b/tests/compiler/features/gc.debug.wat index cedb0b1868..d4d8e4d91c 100644 --- a/tests/compiler/features/gc.debug.wat +++ b/tests/compiler/features/gc.debug.wat @@ -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)) @@ -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 diff --git a/tests/compiler/features/gc.release.wat b/tests/compiler/features/gc.release.wat index c8b639951c..1bc02d535f 100644 --- a/tests/compiler/features/gc.release.wat +++ b/tests/compiler/features/gc.release.wat @@ -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 diff --git a/tests/compiler/features/gc.ts b/tests/compiler/features/gc.ts index 6b9c564b78..4346bd1ba0 100644 --- a/tests/compiler/features/gc.ts +++ b/tests/compiler/features/gc.ts @@ -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 diff --git a/tests/compiler/features/reference-types.debug.wat b/tests/compiler/features/reference-types.debug.wat index 0f89b35fd6..858489b81f 100644 --- a/tests/compiler/features/reference-types.debug.wat +++ b/tests/compiler/features/reference-types.debug.wat @@ -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)) @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/tests/compiler/features/reference-types.release.wat b/tests/compiler/features/reference-types.release.wat index e6d211b914..23ef52e390 100644 --- a/tests/compiler/features/reference-types.release.wat +++ b/tests/compiler/features/reference-types.release.wat @@ -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") @@ -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 diff --git a/tests/compiler/features/reference-types.ts b/tests/compiler/features/reference-types.ts index 2d03fd2303..07336989c5 100644 --- a/tests/compiler/features/reference-types.ts +++ b/tests/compiler/features/reference-types.ts @@ -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; From 1c4cef0e064512b1a1a8702259e4e22a6c855780 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 25 Mar 2022 20:15:54 +0100 Subject: [PATCH 2/2] ER should return 0 if non-constant --- src/module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module.ts b/src/module.ts index e3d9d91f9b..60259ff153 100644 --- a/src/module.ts +++ b/src/module.ts @@ -2582,7 +2582,7 @@ export class Module { var runner = binaryen._ExpressionRunnerCreate(this.ref, flags, maxDepth, maxLoopIterations); var precomp = binaryen._ExpressionRunnerRunAndDispose(runner, expr); if (precomp) { - if (!this.isConstExpression(precomp)) return expr; + if (!this.isConstExpression(precomp)) return 0; assert(getExpressionType(precomp) == getExpressionType(expr)); } return precomp;