From ecd7ad19f2e914707efc858f993a75f959ead2ca Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcong.cai@bmw.com> Date: Mon, 16 Oct 2023 16:18:01 +0800 Subject: [PATCH 1/2] fix: crash on assignment chain Fixes: #2674 --- src/compiler.ts | 6 +- tests/compiler/assignment-chain.debug.wat | 98 +++++++++++++++++++++ tests/compiler/assignment-chain.json | 4 + tests/compiler/assignment-chain.release.wat | 69 +++++++++++++++ tests/compiler/assignment-chain.ts | 8 ++ 5 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 tests/compiler/assignment-chain.debug.wat create mode 100644 tests/compiler/assignment-chain.json create mode 100644 tests/compiler/assignment-chain.release.wat create mode 100644 tests/compiler/assignment-chain.ts diff --git a/src/compiler.ts b/src/compiler.ts index 2567805aff..ef0b314174 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -5811,14 +5811,14 @@ export class Compiler extends DiagnosticEmitter { assert(getterInstance.signature.thisType == thisType); let returnType = getterInstance.signature.returnType; let returnTypeRef = returnType.toRef(); - let tempThis = flow.getTempLocal(returnType); + let tempThis = flow.getTempLocal(thisType); let ret = module.block(null, [ this.makeCallDirect(setterInstance, [ - module.local_tee(tempThis.index, thisExpr, returnType.isManaged), + module.local_tee(tempThis.index, thisExpr, /*isManaged=*/false, thisType.toRef()), // thisType is managed but here it must be alive valueExpr ], valueExpression), this.makeCallDirect(getterInstance, [ - module.local_get(tempThis.index, returnTypeRef) + module.local_get(tempThis.index, thisType.toRef()) ], valueExpression) ], returnTypeRef); return ret; diff --git a/tests/compiler/assignment-chain.debug.wat b/tests/compiler/assignment-chain.debug.wat new file mode 100644 index 0000000000..e4415d8a18 --- /dev/null +++ b/tests/compiler/assignment-chain.debug.wat @@ -0,0 +1,98 @@ +(module + (type $i32_i64_=>_none (func (param i32 i64))) + (type $i32_=>_none (func (param i32))) + (type $i32_=>_i64 (func (param i32) (result i64))) + (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) + (type $none_=>_none (func)) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (global $~lib/memory/__data_end i32 (i32.const 8)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 32776)) + (global $~lib/memory/__heap_base i32 (i32.const 32776)) + (memory $0 0) + (table $0 1 1 funcref) + (elem $0 (i32.const 1)) + (export "memory" (memory $0)) + (export "foo" (func $export:assignment-chain/foo)) + (func $assignment-chain/A#set:y (param $this i32) (param $y i64) + local.get $this + local.get $y + i64.store $0 offset=8 + ) + (func $assignment-chain/A#get:y (param $this i32) (result i64) + local.get $this + i64.load $0 offset=8 + ) + (func $assignment-chain/A#set:x (param $this i32) (param $x i64) + local.get $this + local.get $x + i64.store $0 + ) + (func $~stack_check + global.get $~lib/memory/__stack_pointer + global.get $~lib/memory/__data_end + i32.lt_s + if + i32.const 32800 + i32.const 32848 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + ) + (func $assignment-chain/foo (param $a i32) + (local $1 i32) + (local $2 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store $0 + local.get $a + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store $0 + local.get $2 + local.get $a + local.tee $1 + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store $0 offset=4 + local.get $2 + i64.const 1 + call $assignment-chain/A#set:y + local.get $1 + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store $0 offset=4 + local.get $2 + call $assignment-chain/A#get:y + call $assignment-chain/A#set:x + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + ) + (func $export:assignment-chain/foo (param $0 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store $0 + local.get $0 + call $assignment-chain/foo + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + ) +) diff --git a/tests/compiler/assignment-chain.json b/tests/compiler/assignment-chain.json new file mode 100644 index 0000000000..1bdd02b1be --- /dev/null +++ b/tests/compiler/assignment-chain.json @@ -0,0 +1,4 @@ +{ + "asc_flags": [ + ] +} diff --git a/tests/compiler/assignment-chain.release.wat b/tests/compiler/assignment-chain.release.wat new file mode 100644 index 0000000000..1203755091 --- /dev/null +++ b/tests/compiler/assignment-chain.release.wat @@ -0,0 +1,69 @@ +(module + (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) + (type $i32_=>_none (func (param i32))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 33792)) + (memory $0 0) + (export "memory" (memory $0)) + (export "foo" (func $export:assignment-chain/foo)) + (func $export:assignment-chain/foo (param $0 i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + block $folding-inner0 + global.get $~lib/memory/__stack_pointer + i32.const 1024 + i32.lt_s + br_if $folding-inner0 + global.get $~lib/memory/__stack_pointer + local.tee $1 + local.get $0 + i32.store $0 + local.get $1 + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + global.get $~lib/memory/__stack_pointer + i32.const 1024 + i32.lt_s + br_if $folding-inner0 + global.get $~lib/memory/__stack_pointer + local.tee $1 + i64.const 0 + i64.store $0 + local.get $1 + local.get $0 + i32.store $0 + local.get $1 + local.get $0 + i32.store $0 offset=4 + local.get $0 + i64.const 1 + i64.store $0 offset=8 + local.get $1 + local.get $0 + i32.store $0 offset=4 + local.get $0 + local.get $0 + i64.load $0 offset=8 + i64.store $0 + local.get $1 + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + return + end + i32.const 33824 + i32.const 33872 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + ) +) diff --git a/tests/compiler/assignment-chain.ts b/tests/compiler/assignment-chain.ts new file mode 100644 index 0000000000..f22186a7bc --- /dev/null +++ b/tests/compiler/assignment-chain.ts @@ -0,0 +1,8 @@ +class A { + x: i64 = 0; + y: i64 = 0; +} + +export function foo(a: A): void { + a.x = a.y = 1; +} From 38821c1f920800debeaecef1e29884286b4eceb4 Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcong.cai@bmw.com> Date: Mon, 16 Oct 2023 16:43:45 +0800 Subject: [PATCH 2/2] fix lint --- src/compiler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler.ts b/src/compiler.ts index ef0b314174..cda945784b 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -5814,7 +5814,7 @@ export class Compiler extends DiagnosticEmitter { let tempThis = flow.getTempLocal(thisType); let ret = module.block(null, [ this.makeCallDirect(setterInstance, [ - module.local_tee(tempThis.index, thisExpr, /*isManaged=*/false, thisType.toRef()), // thisType is managed but here it must be alive + module.local_tee(tempThis.index, thisExpr, /* isManaged=*/false, thisType.toRef()), // thisType is managed but here it must be alive valueExpr ], valueExpression), this.makeCallDirect(getterInstance, [