From 78adcb1b371a66263cdee74850b020acd3008c9c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 13 May 2026 16:43:41 -0700 Subject: [PATCH 01/12] work --- src/tools/wasm-ctor-eval.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 93e8d4ae51f..075b2f0341e 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -323,6 +323,11 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { } applyGlobalsToModule(); + + // If we got to the point of applying things to the module, then we evalled + // a ctor, which means we evalled the start function. Wipe it out, as it + // must not run again (just like a ctor that runs before all others). + wasm->start = Name(); } void init(Module& wasm_, EvallingModuleRunner& instance_) override { From 12ec38c925965835f4664feb913795fb44f325b3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 13 May 2026 16:43:55 -0700 Subject: [PATCH 02/12] test --- test/lit/ctor-eval/start.wast | 63 +++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 test/lit/ctor-eval/start.wast diff --git a/test/lit/ctor-eval/start.wast b/test/lit/ctor-eval/start.wast new file mode 100644 index 00000000000..16f52b7278a --- /dev/null +++ b/test/lit/ctor-eval/start.wast @@ -0,0 +1,63 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: foreach %s %t wasm-ctor-eval --ctors=test --kept-exports=test --quiet -all -S -o - | filecheck %s + +;; This code does the following: +;; +;; * start checks if global1 is set, then writes global2. +;; * test sets global1. +;; +;; We must eval away the start function, when we eval away the other. That is, +;; there should be no start function afterwards (though $start remains, +;; uncalled). Otherwise, if it remains as the start, it will trap when it reads +;; the modified global. +;; +;; While doing so we must apply the changes of the start function, to global2. + +(module + + ;; CHECK: (type $0 (func)) + + ;; CHECK: (global $global1 (mut i32) (i32.const 1337)) + (global $global1 (mut i32) (i32.const 0)) + + ;; CHECK: (global $global2 (mut i32) (i32.const 42)) + (global $global2 (mut i32) (i32.const 0)) + + ;; CHECK: (export "test" (func $test_2)) + + ;; CHECK: (start $start) + (start $start) + + ;; CHECK: (func $start (type $0) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (global.get $global1) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.set $global2 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $start + (if + (global.get $global1) + (then + (unreachable) + ) + ) + (global.set $global2 + (i32.const 42) + ) + ) + + (func $test (export "test") + (global.set $global1 + (i32.const 1337) + ) + ) +) + +;; CHECK: (func $test_2 (type $0) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) From 00f13fed7b003fdcd354745309bcb2d7bdd9a974 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 13 May 2026 16:46:24 -0700 Subject: [PATCH 03/12] fix --- test/lit/ctor-eval/start.wast | 43 +++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/test/lit/ctor-eval/start.wast b/test/lit/ctor-eval/start.wast index 16f52b7278a..299653bd7b6 100644 --- a/test/lit/ctor-eval/start.wast +++ b/test/lit/ctor-eval/start.wast @@ -7,15 +7,16 @@ ;; * test sets global1. ;; ;; We must eval away the start function, when we eval away the other. That is, -;; there should be no start function afterwards (though $start remains, -;; uncalled). Otherwise, if it remains as the start, it will trap when it reads -;; the modified global. +;; there should be no start function afterwards. Otherwise, if it remains as the +;; start, it will trap when it reads the modified global. ;; ;; While doing so we must apply the changes of the start function, to global2. +;; So both globals end up modified. (module + ;; CHECK: (type $0 (func (result i32))) - ;; CHECK: (type $0 (func)) + ;; CHECK: (type $1 (func)) ;; CHECK: (global $global1 (mut i32) (i32.const 1337)) (global $global1 (mut i32) (i32.const 0)) @@ -23,22 +24,8 @@ ;; CHECK: (global $global2 (mut i32) (i32.const 42)) (global $global2 (mut i32) (i32.const 0)) - ;; CHECK: (export "test" (func $test_2)) - - ;; CHECK: (start $start) (start $start) - ;; CHECK: (func $start (type $0) - ;; CHECK-NEXT: (if - ;; CHECK-NEXT: (global.get $global1) - ;; CHECK-NEXT: (then - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.set $global2 - ;; CHECK-NEXT: (i32.const 42) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) (func $start (if (global.get $global1) @@ -56,8 +43,26 @@ (i32.const 1337) ) ) + + ;; CHECK: (export "test" (func $test_3)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (func $keepalive (type $0) (result i32) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (global.get $global1) + ;; CHECK-NEXT: (global.get $global2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + ;; Keep the globals alive to show changes. + (i32.add + (global.get $global1) + (global.get $global2) + ) + ) ) -;; CHECK: (func $test_2 (type $0) +;; CHECK: (func $test_3 (type $1) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) From 6e64eed21e12bf72debc749a5cf366e91b3c969a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 13 May 2026 16:48:09 -0700 Subject: [PATCH 04/12] test --- test/lit/ctor-eval/start-bad.wast | 62 +++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 test/lit/ctor-eval/start-bad.wast diff --git a/test/lit/ctor-eval/start-bad.wast b/test/lit/ctor-eval/start-bad.wast new file mode 100644 index 00000000000..bf9e2d7c900 --- /dev/null +++ b/test/lit/ctor-eval/start-bad.wast @@ -0,0 +1,62 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: foreach %s %t wasm-ctor-eval --ctors=test --kept-exports=test --quiet -all -S -o - | filecheck %s + +;; The start function traps here, so we cannot eval anything. None of the +;; globals should change. + +(module + ;; CHECK: (type $0 (func)) + + ;; CHECK: (type $1 (func (result i32))) + + ;; CHECK: (global $global1 (mut i32) (i32.const 0)) + (global $global1 (mut i32) (i32.const 0)) + + ;; CHECK: (global $global2 (mut i32) (i32.const 0)) + (global $global2 (mut i32) (i32.const 0)) + + ;; CHECK: (export "test" (func $test)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + (start $start) + + ;; CHECK: (func $start (type $0) + ;; CHECK-NEXT: (global.set $global2 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $start + (global.set $global2 + (i32.const 42) + ) + (unreachable) + ) + + ;; CHECK: (func $test (type $0) + ;; CHECK-NEXT: (global.set $global1 + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test (export "test") + (global.set $global1 + (i32.const 1337) + ) + ) + + ;; CHECK: (func $keepalive (type $1) (result i32) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (global.get $global1) + ;; CHECK-NEXT: (global.get $global2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + ;; Keep the globals alive to show changes. + (i32.add + (global.get $global1) + (global.get $global2) + ) + ) +) From 6c4f1192b42ea3774077c1b08a7c51d805c6b9a2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 13 May 2026 16:49:00 -0700 Subject: [PATCH 05/12] work --- test/lit/ctor-eval/start.wast | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/lit/ctor-eval/start.wast b/test/lit/ctor-eval/start.wast index 299653bd7b6..6880667ed48 100644 --- a/test/lit/ctor-eval/start.wast +++ b/test/lit/ctor-eval/start.wast @@ -3,7 +3,7 @@ ;; This code does the following: ;; -;; * start checks if global1 is set, then writes global2. +;; * start writes global2, and traps if global1 is set. ;; * test sets global1. ;; ;; We must eval away the start function, when we eval away the other. That is, @@ -27,15 +27,15 @@ (start $start) (func $start + (global.set $global2 + (i32.const 42) + ) (if (global.get $global1) (then (unreachable) ) ) - (global.set $global2 - (i32.const 42) - ) ) (func $test (export "test") From 796c111647191bfd19bcc1f9b40ee78714e8dd2a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 13 May 2026 17:10:54 -0700 Subject: [PATCH 06/12] test --- test/lit/ctor-eval/start-bad-2.wast | 65 +++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 test/lit/ctor-eval/start-bad-2.wast diff --git a/test/lit/ctor-eval/start-bad-2.wast b/test/lit/ctor-eval/start-bad-2.wast new file mode 100644 index 00000000000..2b38a836a62 --- /dev/null +++ b/test/lit/ctor-eval/start-bad-2.wast @@ -0,0 +1,65 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: foreach %s %t wasm-ctor-eval --ctors=test --kept-exports=test --quiet -all -S -o - | filecheck %s + +;; We fail to eval away test (due to infinite recursion). As a result, we do +;; not update either global - not the one it modifies or even the one that the +;; start function modifies, and the start function remains as the start. +;; TODO: We could perhaps eval away the start in such cases, even when nothing +;; else gets optimized. + +(module + ;; CHECK: (type $0 (func)) + + ;; CHECK: (type $1 (func (result i32))) + + ;; CHECK: (global $global1 (mut i32) (i32.const 0)) + (global $global1 (mut i32) (i32.const 0)) + + ;; CHECK: (global $global2 (mut i32) (i32.const 0)) + (global $global2 (mut i32) (i32.const 0)) + + ;; CHECK: (export "test" (func $test)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (start $start) + (start $start) + + ;; CHECK: (func $start (type $0) + ;; CHECK-NEXT: (global.set $global2 + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $start + (global.set $global2 + (i32.const 42) + ) + ) + + ;; CHECK: (func $test (type $0) + ;; CHECK-NEXT: (call $test) + ;; CHECK-NEXT: (global.set $global1 + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test (export "test") + (call $test) + (global.set $global1 + (i32.const 1337) + ) + ) + + ;; CHECK: (func $keepalive (type $1) (result i32) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (global.get $global1) + ;; CHECK-NEXT: (global.get $global2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive (export "keepalive") (result i32) + ;; Keep the globals alive to show changes. + (i32.add + (global.get $global1) + (global.get $global2) + ) + ) +) From 059dbff50eca6bb53a66797b596c9ae4a0ff7164 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 14 May 2026 10:18:22 -0700 Subject: [PATCH 07/12] update existing tests --- test/lit/ctor-eval/gc-cycle-multi.wast | 17 -- test/lit/ctor-eval/gc-cycle.wast | 356 +++++-------------------- 2 files changed, 60 insertions(+), 313 deletions(-) diff --git a/test/lit/ctor-eval/gc-cycle-multi.wast b/test/lit/ctor-eval/gc-cycle-multi.wast index dc14403b32f..d6299516756 100644 --- a/test/lit/ctor-eval/gc-cycle-multi.wast +++ b/test/lit/ctor-eval/gc-cycle-multi.wast @@ -82,8 +82,6 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - ;; CHECK: (func $keepalive (type $2) (result i32) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (struct.get $A 1 @@ -115,21 +113,6 @@ ) ) ) -;; CHECK: (func $start (type $1) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_6) -;; CHECK-NEXT: (global.get $ctor-eval$global_6) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_7) -;; CHECK-NEXT: (global.get $ctor-eval$global_7) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_8) -;; CHECK-NEXT: (global.get $ctor-eval$global_8) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - ;; CHECK: (func $test1_6 (type $1) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) diff --git a/test/lit/ctor-eval/gc-cycle.wast b/test/lit/ctor-eval/gc-cycle.wast index 0af9fbf10b3..287009dee74 100644 --- a/test/lit/ctor-eval/gc-cycle.wast +++ b/test/lit/ctor-eval/gc-cycle.wast @@ -5,9 +5,9 @@ ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) (type $A (struct (field (mut (ref null $A))) (field i32))) - ;; CHECK: (type $1 (func)) + ;; CHECK: (type $1 (func (result i32))) - ;; CHECK: (type $2 (func (result i32))) + ;; CHECK: (type $2 (func)) ;; CHECK: (global $ctor-eval$global_3 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -40,9 +40,7 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - - ;; CHECK: (func $keepalive (type $2) (result i32) + ;; CHECK: (func $keepalive (type $1) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (struct.get $A 0 ;; CHECK-NEXT: (global.get $a) @@ -62,14 +60,7 @@ ) ) -;; CHECK: (func $start (type $1) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_3) -;; CHECK-NEXT: (global.get $ctor-eval$global_3) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $1) +;; CHECK: (func $test_3 (type $2) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) @@ -80,9 +71,9 @@ ;; CHECK: (type $A (struct (field i32) (field (mut (ref null $A))))) (type $A (struct (field i32) (field (mut (ref null $A))))) - ;; CHECK: (type $1 (func)) + ;; CHECK: (type $1 (func (result i32))) - ;; CHECK: (type $2 (func (result i32))) + ;; CHECK: (type $2 (func)) ;; CHECK: (global $ctor-eval$global_3 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (i32.const 42) @@ -112,9 +103,7 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - - ;; CHECK: (func $keepalive (type $2) (result i32) + ;; CHECK: (func $keepalive (type $1) (result i32) ;; CHECK-NEXT: (struct.get $A 0 ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -130,14 +119,7 @@ ) ) -;; CHECK: (func $start (type $1) -;; CHECK-NEXT: (struct.set $A 1 -;; CHECK-NEXT: (global.get $ctor-eval$global_3) -;; CHECK-NEXT: (global.get $ctor-eval$global_3) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $1) +;; CHECK: (func $test_3 (type $2) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) @@ -147,9 +129,9 @@ ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) (type $A (struct (field (mut (ref null $A))) (field i32))) - ;; CHECK: (type $1 (func)) + ;; CHECK: (type $1 (func (result i32))) - ;; CHECK: (type $2 (func (result i32))) + ;; CHECK: (type $2 (func)) ;; CHECK: (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -197,9 +179,7 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - - ;; CHECK: (func $keepalive (type $2) (result i32) + ;; CHECK: (func $keepalive (type $1) (result i32) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -221,14 +201,7 @@ ) ) -;; CHECK: (func $start (type $1) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_7) -;; CHECK-NEXT: (global.get $ctor-eval$global_8) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $1) +;; CHECK: (func $test_3 (type $2) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $A)) ;; CHECK-NEXT: (nop) @@ -246,9 +219,9 @@ (type $B (struct (field (ref null $A)) (field i32))) ) - ;; CHECK: (type $2 (func)) + ;; CHECK: (type $2 (func (result i32))) - ;; CHECK: (type $3 (func (result i32))) + ;; CHECK: (type $3 (func)) ;; CHECK: (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -295,9 +268,7 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - - ;; CHECK: (func $keepalive (type $3) (result i32) + ;; CHECK: (func $keepalive (type $2) (result i32) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -319,14 +290,7 @@ ) ) -;; CHECK: (func $start (type $2) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_7) -;; CHECK-NEXT: (global.get $ctor-eval$global_8) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $2) +;; CHECK: (func $test_3 (type $3) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (nop) @@ -344,9 +308,9 @@ ) - ;; CHECK: (type $2 (func)) + ;; CHECK: (type $2 (func (result i32))) - ;; CHECK: (type $3 (func (result i32))) + ;; CHECK: (type $3 (func)) ;; CHECK: (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -394,9 +358,7 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - - ;; CHECK: (func $keepalive (type $3) (result i32) + ;; CHECK: (func $keepalive (type $2) (result i32) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -418,14 +380,7 @@ ) ) -;; CHECK: (func $start (type $2) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_7) -;; CHECK-NEXT: (global.get $ctor-eval$global_8) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $2) +;; CHECK: (func $test_3 (type $3) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (nop) @@ -442,20 +397,15 @@ (type $B (struct (field (mut (ref $A))) (field i32))) ) - ;; CHECK: (type $2 (func)) + ;; CHECK: (type $2 (func (result i32))) - ;; CHECK: (type $3 (func (result i32))) + ;; CHECK: (type $3 (func)) ;; CHECK: (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: )) - ;; CHECK: (global $ctor-eval$global_8 (ref (exact $B)) (struct.new $B - ;; CHECK-NEXT: (global.get $ctor-eval$global_7) - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: )) - ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_7)) (global $a (mut (ref null $A)) (ref.null $A)) @@ -490,9 +440,7 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - - ;; CHECK: (func $keepalive (type $3) (result i32) + ;; CHECK: (func $keepalive (type $2) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -504,14 +452,7 @@ ) ) -;; CHECK: (func $start (type $2) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_7) -;; CHECK-NEXT: (global.get $ctor-eval$global_8) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $2) +;; CHECK: (func $test_3 (type $3) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (nop) @@ -532,20 +473,15 @@ (global $b (mut (ref null $B)) (ref.null $B)) - ;; CHECK: (type $2 (func)) + ;; CHECK: (type $2 (func (result i32))) - ;; CHECK: (type $3 (func (result i32))) + ;; CHECK: (type $3 (func)) ;; CHECK: (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: )) - ;; CHECK: (global $ctor-eval$global_8 (ref (exact $B)) (struct.new $B - ;; CHECK-NEXT: (global.get $ctor-eval$global_7) - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: )) - ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_7)) (global $a (mut (ref null $A)) (ref.null $A)) @@ -578,9 +514,7 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - - ;; CHECK: (func $keepalive (type $3) (result i32) + ;; CHECK: (func $keepalive (type $2) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -592,14 +526,7 @@ ) ) -;; CHECK: (func $start (type $2) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_7) -;; CHECK-NEXT: (global.get $ctor-eval$global_8) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $2) +;; CHECK: (func $test_3 (type $3) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (nop) @@ -610,25 +537,15 @@ ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) (type $A (struct (field (mut (ref null $A))) (field i32))) - ;; CHECK: (type $1 (func)) + ;; CHECK: (type $1 (func (result i32))) - ;; CHECK: (type $2 (func (result i32))) + ;; CHECK: (type $2 (func)) ;; CHECK: (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: )) - ;; CHECK: (global $ctor-eval$global_14 (ref (exact $A)) (struct.new $A - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: )) - - ;; CHECK: (global $ctor-eval$global_13 (ref (exact $A)) (struct.new $A - ;; CHECK-NEXT: (global.get $ctor-eval$global_14) - ;; CHECK-NEXT: (i32.const 99999) - ;; CHECK-NEXT: )) - ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_12)) (global $a (mut (ref null $A)) (ref.null $A)) @@ -674,9 +591,7 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - - ;; CHECK: (func $keepalive (type $2) (result i32) + ;; CHECK: (func $keepalive (type $1) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -688,14 +603,7 @@ ) ) -;; CHECK: (func $start (type $1) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_12) -;; CHECK-NEXT: (global.get $ctor-eval$global_13) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $1) +;; CHECK: (func $test_3 (type $2) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $A)) ;; CHECK-NEXT: (local $c (ref $A)) @@ -721,28 +629,15 @@ (global $b (mut (ref null $B)) (ref.null $B)) - ;; CHECK: (type $3 (func)) + ;; CHECK: (type $3 (func (result i32))) - ;; CHECK: (type $4 (func (result i32))) + ;; CHECK: (type $4 (func)) ;; CHECK: (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: )) - ;; CHECK: (global $ctor-eval$global_14 (ref (exact $B)) (array.new_fixed $B 10 - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: )) - ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_12)) (global $a (mut (ref null $A)) (ref.null $A)) @@ -780,18 +675,11 @@ ) ) - ;; CHECK: (global $ctor-eval$global_13 (ref (exact $C)) (array.new_fixed $C 2 - ;; CHECK-NEXT: (global.get $ctor-eval$global_14) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: )) - ;; CHECK: (export "test" (func $test_3)) ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - - ;; CHECK: (func $keepalive (type $4) (result i32) + ;; CHECK: (func $keepalive (type $3) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -803,14 +691,7 @@ ) ) -;; CHECK: (func $start (type $3) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_12) -;; CHECK-NEXT: (global.get $ctor-eval$global_13) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $3) +;; CHECK: (func $test_3 (type $4) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (local $c (ref $C)) @@ -829,28 +710,15 @@ (type $C (array (mut (ref any)))) ) - ;; CHECK: (type $3 (func)) + ;; CHECK: (type $3 (func (result i32))) - ;; CHECK: (type $4 (func (result i32))) + ;; CHECK: (type $4 (func)) ;; CHECK: (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: )) - ;; CHECK: (global $ctor-eval$global_14 (ref (exact $B)) (array.new_fixed $B 10 - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: )) - ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_12)) (global $a (mut (ref null $A)) (ref.null $A)) @@ -892,18 +760,11 @@ ) ) - ;; CHECK: (global $ctor-eval$global_13 (ref (exact $C)) (array.new_fixed $C 2 - ;; CHECK-NEXT: (global.get $ctor-eval$global_14) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: )) - ;; CHECK: (export "test" (func $test_3)) ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - - ;; CHECK: (func $keepalive (type $4) (result i32) + ;; CHECK: (func $keepalive (type $3) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -915,14 +776,7 @@ ) ) -;; CHECK: (func $start (type $3) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_12) -;; CHECK-NEXT: (global.get $ctor-eval$global_13) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $3) +;; CHECK: (func $test_3 (type $4) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (local $c (ref $C)) @@ -940,15 +794,9 @@ (type $B (array (ref null $A))) ) - ;; CHECK: (type $2 (func)) - - ;; CHECK: (type $3 (func (result anyref))) + ;; CHECK: (type $2 (func (result anyref))) - ;; CHECK: (global $ctor-eval$global_17 (ref (exact $A)) (struct.new $A - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: )) + ;; CHECK: (type $3 (func)) ;; CHECK: (global $ctor-eval$global_14 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -956,12 +804,6 @@ ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: )) - ;; CHECK: (global $ctor-eval$global_18 (ref (exact $A)) (struct.new $A - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: )) - ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_14)) (global $a (mut (ref null $A)) (ref.null $A)) (global $b (mut (ref null $B)) (ref.null $B)) @@ -994,23 +836,11 @@ ) ) - ;; CHECK: (global $ctor-eval$global_16 (ref (exact $B)) (array.new_fixed $B 3 - ;; CHECK-NEXT: (global.get $ctor-eval$global_17) - ;; CHECK-NEXT: (global.get $ctor-eval$global_14) - ;; CHECK-NEXT: (global.get $ctor-eval$global_18) - ;; CHECK-NEXT: )) - - ;; CHECK: (global $ctor-eval$global_15 (ref (exact $B)) (array.new_fixed $B 0)) - - ;; CHECK: (global $ctor-eval$global_19 (ref (exact $B)) (array.new_fixed $B 0)) - ;; CHECK: (export "test" (func $test_3)) ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - - ;; CHECK: (func $keepalive (type $3) (result anyref) + ;; CHECK: (func $keepalive (type $2) (result anyref) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -1022,22 +852,7 @@ ) ) -;; CHECK: (func $start (type $2) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global_14) -;; CHECK-NEXT: (global.get $ctor-eval$global_15) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (struct.set $A 1 -;; CHECK-NEXT: (global.get $ctor-eval$global_14) -;; CHECK-NEXT: (global.get $ctor-eval$global_16) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (struct.set $A 2 -;; CHECK-NEXT: (global.get $ctor-eval$global_14) -;; CHECK-NEXT: (global.get $ctor-eval$global_19) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $2) +;; CHECK: (func $test_3 (type $3) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) @@ -1052,9 +867,9 @@ (type $B (array (mut (ref null $A)))) ) - ;; CHECK: (type $2 (func)) + ;; CHECK: (type $2 (func (result anyref))) - ;; CHECK: (type $3 (func (result anyref))) + ;; CHECK: (type $3 (func)) ;; CHECK: (global $ctor-eval$global_17 (ref (exact $B)) (array.new_fixed $B 0)) @@ -1105,25 +920,11 @@ ) ) - ;; CHECK: (global $ctor-eval$global_15 (ref (exact $A)) (struct.new $A - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: )) - - ;; CHECK: (global $ctor-eval$global_19 (ref (exact $A)) (struct.new $A - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: )) - ;; CHECK: (export "test" (func $test_3)) ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (start $start) - - ;; CHECK: (func $keepalive (type $3) (result anyref) + ;; CHECK: (func $keepalive (type $2) (result anyref) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -1135,25 +936,7 @@ ) ) -;; CHECK: (func $start (type $2) -;; CHECK-NEXT: (array.set $B -;; CHECK-NEXT: (global.get $ctor-eval$global_14) -;; CHECK-NEXT: (i32.const 0) -;; CHECK-NEXT: (global.get $ctor-eval$global_15) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (array.set $B -;; CHECK-NEXT: (global.get $ctor-eval$global_14) -;; CHECK-NEXT: (i32.const 1) -;; CHECK-NEXT: (global.get $ctor-eval$global_16) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (array.set $B -;; CHECK-NEXT: (global.get $ctor-eval$global_14) -;; CHECK-NEXT: (i32.const 2) -;; CHECK-NEXT: (global.get $ctor-eval$global_19) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $2) +;; CHECK: (func $test_3 (type $3) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) @@ -1163,9 +946,9 @@ ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) (type $A (struct (field (mut (ref null $A))) (field i32))) - ;; CHECK: (type $1 (func)) + ;; CHECK: (type $1 (func (result i32))) - ;; CHECK: (type $2 (func (result i32))) + ;; CHECK: (type $2 (func)) ;; CHECK: (global $ctor-eval$global_4 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -1178,11 +961,6 @@ ;; CHECK: (global $b (mut (ref null $A)) (ref.null none)) (global $b (mut (ref null $A)) (ref.null $A)) - ;; CHECK: (export "test" (func $test_3)) - - ;; CHECK: (export "keepalive" (func $keepalive)) - - ;; CHECK: (start $start) (start $start) (func $test (export "test") @@ -1201,7 +979,11 @@ ) ) - ;; CHECK: (func $keepalive (type $2) (result i32) + ;; CHECK: (export "test" (func $test_4)) + + ;; CHECK: (export "keepalive" (func $keepalive)) + + ;; CHECK: (func $keepalive (type $1) (result i32) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -1222,15 +1004,6 @@ ) ) - ;; CHECK: (func $start (type $1) - ;; CHECK-NEXT: (struct.set $A 0 - ;; CHECK-NEXT: (global.get $ctor-eval$global_4) - ;; CHECK-NEXT: (global.get $ctor-eval$global_4) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.set $b - ;; CHECK-NEXT: (global.get $a) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) (func $start (global.set $b (global.get $a) @@ -1238,7 +1011,7 @@ ) ) -;; CHECK: (func $test_3 (type $1) +;; CHECK: (func $test_4 (type $2) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) @@ -1246,11 +1019,11 @@ ;; CHECK: (type $A (struct (field (mut (ref null $A))))) (type $A (struct (field (mut (ref null $A))))) - ;; CHECK: (type $1 (func)) + ;; CHECK: (type $1 (func (param anyref))) - ;; CHECK: (type $2 (func (param anyref))) + ;; CHECK: (type $2 (func)) - ;; CHECK: (import "a" "b" (func $import (type $2) (param anyref))) + ;; CHECK: (import "a" "b" (func $import (type $1) (param anyref))) (import "a" "b" (func $import (param anyref))) (func $test (export "test") @@ -1277,16 +1050,7 @@ ;; CHECK: (export "test" (func $test_3)) -;; CHECK: (start $start) - -;; CHECK: (func $start (type $1) -;; CHECK-NEXT: (struct.set $A 0 -;; CHECK-NEXT: (global.get $ctor-eval$global) -;; CHECK-NEXT: (global.get $ctor-eval$global) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) - -;; CHECK: (func $test_3 (type $1) +;; CHECK: (func $test_3 (type $2) ;; CHECK-NEXT: (call $import ;; CHECK-NEXT: (global.get $ctor-eval$global) ;; CHECK-NEXT: ) From f00a1c290b1bceb31dc74afa4a8f9e6a6fa1c77e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 14 May 2026 10:24:46 -0700 Subject: [PATCH 08/12] add keepalives to tests to avoid start removal making them remove too much to read --- test/lit/ctor-eval/gc-cycle.wast | 256 +++++++++++++++++++++++++++---- 1 file changed, 229 insertions(+), 27 deletions(-) diff --git a/test/lit/ctor-eval/gc-cycle.wast b/test/lit/ctor-eval/gc-cycle.wast index 287009dee74..7f9e63fc8d7 100644 --- a/test/lit/ctor-eval/gc-cycle.wast +++ b/test/lit/ctor-eval/gc-cycle.wast @@ -471,8 +471,6 @@ ) - (global $b (mut (ref null $B)) (ref.null $B)) - ;; CHECK: (type $2 (func (result i32))) ;; CHECK: (type $3 (func)) @@ -482,7 +480,16 @@ ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: )) + ;; CHECK: (global $ctor-eval$global_8 (ref (exact $B)) (struct.new $B + ;; CHECK-NEXT: (global.get $ctor-eval$global_7) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: )) + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_7)) + + ;; CHECK: (global $b (mut (ref null $B)) (global.get $ctor-eval$global_8)) + (global $b (mut (ref null $B)) (ref.null $B)) + (global $a (mut (ref null $A)) (ref.null $A)) (func $test (export "test") @@ -515,13 +522,23 @@ ;; CHECK: (export "keepalive" (func $keepalive)) ;; CHECK: (func $keepalive (type $2) (result i32) - ;; CHECK-NEXT: (struct.get $A 1 - ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.get $B 1 + ;; CHECK-NEXT: (global.get $b) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $keepalive (export "keepalive") (result i32) - (struct.get $A 1 - (global.get $a) + (i32.add + (struct.get $A 1 + (global.get $a) + ) + (struct.get $B 1 + (global.get $b) + ) ) ) ) @@ -546,11 +563,23 @@ ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: )) + ;; CHECK: (global $ctor-eval$global_14 (ref (exact $A)) (struct.new $A + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $ctor-eval$global_13 (ref (exact $A)) (struct.new $A + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (i32.const 99999) + ;; CHECK-NEXT: )) + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_12)) (global $a (mut (ref null $A)) (ref.null $A)) + ;; CHECK: (global $b (mut (ref null $A)) (global.get $ctor-eval$global_14)) (global $b (mut (ref null $A)) (ref.null $A)) + ;; CHECK: (global $c (mut (ref null $A)) (global.get $ctor-eval$global_13)) (global $c (mut (ref null $A)) (ref.null $A)) (func $test (export "test") @@ -592,13 +621,29 @@ ;; CHECK: (export "keepalive" (func $keepalive)) ;; CHECK: (func $keepalive (type $1) (result i32) - ;; CHECK-NEXT: (struct.get $A 1 - ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $c) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $keepalive (export "keepalive") (result i32) - (struct.get $A 1 - (global.get $a) + (select + (struct.get $A 1 + (global.get $a) + ) + (struct.get $A 1 + (global.get $b) + ) + (struct.get $A 1 + (global.get $c) + ) ) ) ) @@ -625,20 +670,44 @@ (type $C (array (mut (ref any)))) ) - (global $c (mut (ref null $C)) (ref.null $C)) - - (global $b (mut (ref null $B)) (ref.null $B)) + ;; CHECK: (type $3 (func (result anyref))) - ;; CHECK: (type $3 (func (result i32))) + ;; CHECK: (type $4 (func (result i32))) - ;; CHECK: (type $4 (func)) + ;; CHECK: (type $5 (func)) ;; CHECK: (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: )) + ;; CHECK: (global $ctor-eval$global_14 (ref (exact $B)) (array.new_fixed $B 10 + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: )) + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_12)) + + ;; CHECK: (global $ctor-eval$global_13 (ref (exact $C)) (array.new_fixed $C 2 + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $b (mut (ref null $B)) (global.get $ctor-eval$global_14)) + + ;; CHECK: (global $c (mut (ref null $C)) (global.get $ctor-eval$global_13)) + (global $c (mut (ref null $C)) (ref.null $C)) + + (global $b (mut (ref null $B)) (ref.null $B)) + (global $a (mut (ref null $A)) (ref.null $A)) (func $test (export "test") @@ -675,11 +744,15 @@ ) ) - ;; CHECK: (export "test" (func $test_3)) + ;; CHECK: (export "test" (func $test_5)) ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (func $keepalive (type $3) (result i32) + ;; CHECK: (export "keepalive-B" (func $keepalive-B)) + + ;; CHECK: (export "keepalive-C" (func $keepalive-C)) + + ;; CHECK: (func $keepalive (type $4) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -689,9 +762,35 @@ (global.get $a) ) ) + + ;; CHECK: (func $keepalive-B (type $3) (result anyref) + ;; CHECK-NEXT: (array.get $B + ;; CHECK-NEXT: (global.get $b) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive-B (export "keepalive-B") (result anyref) + (array.get $B + (global.get $b) + (i32.const 0) + ) + ) + + ;; CHECK: (func $keepalive-C (type $3) (result anyref) + ;; CHECK-NEXT: (array.get $C + ;; CHECK-NEXT: (global.get $c) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive-C (export "keepalive-C") (result anyref) + (array.get $C + (global.get $c) + (i32.const 0) + ) + ) ) -;; CHECK: (func $test_3 (type $4) +;; CHECK: (func $test_5 (type $5) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (local $c (ref $C)) @@ -710,20 +809,42 @@ (type $C (array (mut (ref any)))) ) - ;; CHECK: (type $3 (func (result i32))) + ;; CHECK: (type $3 (func (result anyref))) - ;; CHECK: (type $4 (func)) + ;; CHECK: (type $4 (func (result i32))) + + ;; CHECK: (type $5 (func)) ;; CHECK: (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: )) + ;; CHECK: (global $ctor-eval$global_14 (ref (exact $B)) (array.new_fixed $B 10 + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: )) + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_12)) (global $a (mut (ref null $A)) (ref.null $A)) + ;; CHECK: (global $ctor-eval$global_13 (ref (exact $C)) (array.new_fixed $C 2 + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $b (mut (ref null $B)) (global.get $ctor-eval$global_14)) (global $b (mut (ref null $B)) (ref.null $B)) + ;; CHECK: (global $c (mut (ref null $C)) (global.get $ctor-eval$global_13)) (global $c (mut (ref null $C)) (ref.null $C)) (func $test (export "test") @@ -760,11 +881,15 @@ ) ) - ;; CHECK: (export "test" (func $test_3)) + ;; CHECK: (export "test" (func $test_5)) ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (func $keepalive (type $3) (result i32) + ;; CHECK: (export "keepalive-B" (func $keepalive-B)) + + ;; CHECK: (export "keepalive-C" (func $keepalive-C)) + + ;; CHECK: (func $keepalive (type $4) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -774,9 +899,35 @@ (global.get $a) ) ) + + ;; CHECK: (func $keepalive-B (type $3) (result anyref) + ;; CHECK-NEXT: (array.get $B + ;; CHECK-NEXT: (global.get $b) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive-B (export "keepalive-B") (result anyref) + (array.get $B + (global.get $b) + (i32.const 0) + ) + ) + + ;; CHECK: (func $keepalive-C (type $3) (result anyref) + ;; CHECK-NEXT: (array.get $C + ;; CHECK-NEXT: (global.get $c) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive-C (export "keepalive-C") (result anyref) + (array.get $C + (global.get $c) + (i32.const 0) + ) + ) ) -;; CHECK: (func $test_3 (type $4) +;; CHECK: (func $test_5 (type $5) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (local $c (ref $C)) @@ -798,14 +949,33 @@ ;; CHECK: (type $3 (func)) + ;; CHECK: (global $ctor-eval$global_17 (ref (exact $A)) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: )) + ;; CHECK: (global $ctor-eval$global_14 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: )) + ;; CHECK: (global $ctor-eval$global_18 (ref (exact $A)) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: )) + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_14)) (global $a (mut (ref null $A)) (ref.null $A)) + ;; CHECK: (global $ctor-eval$global_16 (ref (exact $B)) (array.new_fixed $B 3 + ;; CHECK-NEXT: (global.get $ctor-eval$global_17) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_18) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $b (mut (ref null $B)) (global.get $ctor-eval$global_16)) (global $b (mut (ref null $B)) (ref.null $B)) (func $test (export "test") @@ -836,10 +1006,12 @@ ) ) - ;; CHECK: (export "test" (func $test_3)) + ;; CHECK: (export "test" (func $test_4)) ;; CHECK: (export "keepalive" (func $keepalive)) + ;; CHECK: (export "keepalive-B" (func $keepalive-B)) + ;; CHECK: (func $keepalive (type $2) (result anyref) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -850,9 +1022,22 @@ (global.get $a) ) ) + + ;; CHECK: (func $keepalive-B (type $2) (result anyref) + ;; CHECK-NEXT: (array.get $B + ;; CHECK-NEXT: (global.get $b) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive-B (export "keepalive-B") (result (ref null any)) + (array.get $B + (global.get $b) + (i32.const 0) + ) + ) ) -;; CHECK: (func $test_3 (type $3) +;; CHECK: (func $test_4 (type $3) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) @@ -881,6 +1066,8 @@ ;; CHECK: (global $ctor-eval$global_18 (ref (exact $B)) (array.new_fixed $B 0)) + ;; CHECK: (global $b (mut (ref null $B)) (global.get $ctor-eval$global_14)) + ;; CHECK: (global $ctor-eval$global_16 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (global.get $ctor-eval$global_17) ;; CHECK-NEXT: (global.get $ctor-eval$global_14) @@ -920,10 +1107,12 @@ ) ) - ;; CHECK: (export "test" (func $test_3)) + ;; CHECK: (export "test" (func $test_4)) ;; CHECK: (export "keepalive" (func $keepalive)) + ;; CHECK: (export "keepalive-B" (func $keepalive-B)) + ;; CHECK: (func $keepalive (type $2) (result anyref) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -934,9 +1123,22 @@ (global.get $a) ) ) + + ;; CHECK: (func $keepalive-B (type $2) (result anyref) + ;; CHECK-NEXT: (array.get $B + ;; CHECK-NEXT: (global.get $b) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $keepalive-B (export "keepalive-B") (result anyref) + (array.get $B + (global.get $b) + (i32.const 0) + ) + ) ) -;; CHECK: (func $test_3 (type $3) +;; CHECK: (func $test_4 (type $3) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) From e67476ab75dda9af3bb5cda9adbb1348136f2aea Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 15 May 2026 10:44:41 -0700 Subject: [PATCH 09/12] fix --- src/tools/wasm-ctor-eval.cpp | 29 ++-- test/lit/ctor-eval/gc-cycle.wast | 209 +++++++++++++++++++++------- test/lit/ctor-eval/start-rerun.wast | 44 ++++++ 3 files changed, 218 insertions(+), 64 deletions(-) create mode 100644 test/lit/ctor-eval/start-rerun.wast diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 075b2f0341e..57df170cac2 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -315,6 +315,11 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { // Called when we want to apply the current state of execution to the Module. // Until this is called the Module is never changed. void applyToModule() { + // If we got to the point of applying things to the module, then we evalled + // a ctor, which means we evalled the start function. Wipe it out, as it + // must not run again (just like a ctor that runs before all others). + wasm->start = Name(); + clearApplyState(); // If nothing was ever written to memories then there is nothing to update. @@ -323,11 +328,6 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { } applyGlobalsToModule(); - - // If we got to the point of applying things to the module, then we evalled - // a ctor, which means we evalled the start function. Wipe it out, as it - // must not run again (just like a ctor that runs before all others). - wasm->start = Name(); } void init(Module& wasm_, EvallingModuleRunner& instance_) override { @@ -1034,17 +1034,14 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { void createStartBlock() { Builder builder(*wasm); startBlock = builder.makeBlock(); - if (wasm->start.is()) { - // Put our block before any user start code. - auto* existingStart = wasm->getFunction(wasm->start); - existingStart->body = - builder.makeSequence(*startBlock, existingStart->body); - } else { - // Make a new start function. - wasm->start = Names::getValidFunctionName(*wasm, "start"); - wasm->addFunction(builder.makeFunction( - wasm->start, Signature{Type::none, Type::none}, {}, *startBlock)); - } + // There is no existing start, because each time we apply changes, we + // evalled away the old one. + assert(!wasm->start); + + // Make a new start function. + wasm->start = Names::getValidFunctionName(*wasm, "start"); + wasm->addFunction(builder.makeFunction( + wasm->start, Signature{Type::none, Type::none}, {}, *startBlock)); } void clearStartBlock() { diff --git a/test/lit/ctor-eval/gc-cycle.wast b/test/lit/ctor-eval/gc-cycle.wast index 7f9e63fc8d7..440cc46ab94 100644 --- a/test/lit/ctor-eval/gc-cycle.wast +++ b/test/lit/ctor-eval/gc-cycle.wast @@ -5,9 +5,9 @@ ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) (type $A (struct (field (mut (ref null $A))) (field i32))) - ;; CHECK: (type $1 (func (result i32))) + ;; CHECK: (type $1 (func)) - ;; CHECK: (type $2 (func)) + ;; CHECK: (type $2 (func (result i32))) ;; CHECK: (global $ctor-eval$global_3 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -40,7 +40,9 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (func $keepalive (type $1) (result i32) + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $2) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (struct.get $A 0 ;; CHECK-NEXT: (global.get $a) @@ -60,7 +62,14 @@ ) ) -;; CHECK: (func $test_3 (type $2) +;; CHECK: (func $start (type $1) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_3) +;; CHECK-NEXT: (global.get $ctor-eval$global_3) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $1) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) @@ -71,9 +80,9 @@ ;; CHECK: (type $A (struct (field i32) (field (mut (ref null $A))))) (type $A (struct (field i32) (field (mut (ref null $A))))) - ;; CHECK: (type $1 (func (result i32))) + ;; CHECK: (type $1 (func)) - ;; CHECK: (type $2 (func)) + ;; CHECK: (type $2 (func (result i32))) ;; CHECK: (global $ctor-eval$global_3 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (i32.const 42) @@ -103,7 +112,9 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (func $keepalive (type $1) (result i32) + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $2) (result i32) ;; CHECK-NEXT: (struct.get $A 0 ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -119,7 +130,14 @@ ) ) -;; CHECK: (func $test_3 (type $2) +;; CHECK: (func $start (type $1) +;; CHECK-NEXT: (struct.set $A 1 +;; CHECK-NEXT: (global.get $ctor-eval$global_3) +;; CHECK-NEXT: (global.get $ctor-eval$global_3) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $1) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) @@ -129,9 +147,9 @@ ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) (type $A (struct (field (mut (ref null $A))) (field i32))) - ;; CHECK: (type $1 (func (result i32))) + ;; CHECK: (type $1 (func)) - ;; CHECK: (type $2 (func)) + ;; CHECK: (type $2 (func (result i32))) ;; CHECK: (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -179,7 +197,9 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (func $keepalive (type $1) (result i32) + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $2) (result i32) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -201,7 +221,14 @@ ) ) -;; CHECK: (func $test_3 (type $2) +;; CHECK: (func $start (type $1) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $1) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $A)) ;; CHECK-NEXT: (nop) @@ -219,9 +246,9 @@ (type $B (struct (field (ref null $A)) (field i32))) ) - ;; CHECK: (type $2 (func (result i32))) + ;; CHECK: (type $2 (func)) - ;; CHECK: (type $3 (func)) + ;; CHECK: (type $3 (func (result i32))) ;; CHECK: (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -268,7 +295,9 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (func $keepalive (type $2) (result i32) + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $3) (result i32) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -290,7 +319,14 @@ ) ) -;; CHECK: (func $test_3 (type $3) +;; CHECK: (func $start (type $2) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $2) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (nop) @@ -308,9 +344,9 @@ ) - ;; CHECK: (type $2 (func (result i32))) + ;; CHECK: (type $2 (func)) - ;; CHECK: (type $3 (func)) + ;; CHECK: (type $3 (func (result i32))) ;; CHECK: (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -358,7 +394,9 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (func $keepalive (type $2) (result i32) + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $3) (result i32) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -380,7 +418,14 @@ ) ) -;; CHECK: (func $test_3 (type $3) +;; CHECK: (func $start (type $2) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $2) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (nop) @@ -397,15 +442,20 @@ (type $B (struct (field (mut (ref $A))) (field i32))) ) - ;; CHECK: (type $2 (func (result i32))) + ;; CHECK: (type $2 (func)) - ;; CHECK: (type $3 (func)) + ;; CHECK: (type $3 (func (result i32))) ;; CHECK: (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: )) + ;; CHECK: (global $ctor-eval$global_8 (ref (exact $B)) (struct.new $B + ;; CHECK-NEXT: (global.get $ctor-eval$global_7) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: )) + ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_7)) (global $a (mut (ref null $A)) (ref.null $A)) @@ -440,7 +490,9 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (func $keepalive (type $2) (result i32) + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $3) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -452,7 +504,14 @@ ) ) -;; CHECK: (func $test_3 (type $3) +;; CHECK: (func $start (type $2) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $2) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (nop) @@ -471,9 +530,9 @@ ) - ;; CHECK: (type $2 (func (result i32))) + ;; CHECK: (type $2 (func)) - ;; CHECK: (type $3 (func)) + ;; CHECK: (type $3 (func (result i32))) ;; CHECK: (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -521,7 +580,9 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (func $keepalive (type $2) (result i32) + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $3) (result i32) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -543,7 +604,14 @@ ) ) -;; CHECK: (func $test_3 (type $3) +;; CHECK: (func $start (type $2) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $2) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (nop) @@ -554,9 +622,9 @@ ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) (type $A (struct (field (mut (ref null $A))) (field i32))) - ;; CHECK: (type $1 (func (result i32))) + ;; CHECK: (type $1 (func)) - ;; CHECK: (type $2 (func)) + ;; CHECK: (type $2 (func (result i32))) ;; CHECK: (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -620,7 +688,9 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (func $keepalive (type $1) (result i32) + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $2) (result i32) ;; CHECK-NEXT: (select ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -648,7 +718,14 @@ ) ) -;; CHECK: (func $test_3 (type $2) +;; CHECK: (func $start (type $1) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_12) +;; CHECK-NEXT: (global.get $ctor-eval$global_13) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $1) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $A)) ;; CHECK-NEXT: (local $c (ref $A)) @@ -672,9 +749,9 @@ ;; CHECK: (type $3 (func (result anyref))) - ;; CHECK: (type $4 (func (result i32))) + ;; CHECK: (type $4 (func)) - ;; CHECK: (type $5 (func)) + ;; CHECK: (type $5 (func (result i32))) ;; CHECK: (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -752,7 +829,9 @@ ;; CHECK: (export "keepalive-C" (func $keepalive-C)) - ;; CHECK: (func $keepalive (type $4) (result i32) + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $5) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -790,7 +869,14 @@ ) ) -;; CHECK: (func $test_5 (type $5) +;; CHECK: (func $start (type $4) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_12) +;; CHECK-NEXT: (global.get $ctor-eval$global_13) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_5 (type $4) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (local $c (ref $C)) @@ -811,9 +897,9 @@ ;; CHECK: (type $3 (func (result anyref))) - ;; CHECK: (type $4 (func (result i32))) + ;; CHECK: (type $4 (func)) - ;; CHECK: (type $5 (func)) + ;; CHECK: (type $5 (func (result i32))) ;; CHECK: (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -889,7 +975,9 @@ ;; CHECK: (export "keepalive-C" (func $keepalive-C)) - ;; CHECK: (func $keepalive (type $4) (result i32) + ;; CHECK: (start $start) + + ;; CHECK: (func $keepalive (type $5) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -927,7 +1015,14 @@ ) ) -;; CHECK: (func $test_5 (type $5) +;; CHECK: (func $start (type $4) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_12) +;; CHECK-NEXT: (global.get $ctor-eval$global_13) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_5 (type $4) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (local $c (ref $C)) @@ -1148,9 +1243,9 @@ ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) (type $A (struct (field (mut (ref null $A))) (field i32))) - ;; CHECK: (type $1 (func (result i32))) + ;; CHECK: (type $1 (func)) - ;; CHECK: (type $2 (func)) + ;; CHECK: (type $2 (func (result i32))) ;; CHECK: (global $ctor-eval$global_4 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -1185,7 +1280,9 @@ ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (func $keepalive (type $1) (result i32) + ;; CHECK: (start $start_3) + + ;; CHECK: (func $keepalive (type $2) (result i32) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -1213,7 +1310,14 @@ ) ) -;; CHECK: (func $test_4 (type $2) +;; CHECK: (func $start_3 (type $1) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_4) +;; CHECK-NEXT: (global.get $ctor-eval$global_4) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_4 (type $1) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) @@ -1221,11 +1325,11 @@ ;; CHECK: (type $A (struct (field (mut (ref null $A))))) (type $A (struct (field (mut (ref null $A))))) - ;; CHECK: (type $1 (func (param anyref))) + ;; CHECK: (type $1 (func)) - ;; CHECK: (type $2 (func)) + ;; CHECK: (type $2 (func (param anyref))) - ;; CHECK: (import "a" "b" (func $import (type $1) (param anyref))) + ;; CHECK: (import "a" "b" (func $import (type $2) (param anyref))) (import "a" "b" (func $import (param anyref))) (func $test (export "test") @@ -1252,7 +1356,16 @@ ;; CHECK: (export "test" (func $test_3)) -;; CHECK: (func $test_3 (type $2) +;; CHECK: (start $start) + +;; CHECK: (func $start (type $1) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global) +;; CHECK-NEXT: (global.get $ctor-eval$global) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $test_3 (type $1) ;; CHECK-NEXT: (call $import ;; CHECK-NEXT: (global.get $ctor-eval$global) ;; CHECK-NEXT: ) diff --git a/test/lit/ctor-eval/start-rerun.wast b/test/lit/ctor-eval/start-rerun.wast new file mode 100644 index 00000000000..30be014784d --- /dev/null +++ b/test/lit/ctor-eval/start-rerun.wast @@ -0,0 +1,44 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: foreach %s %t wasm-ctor-eval --ctors=t,s --kept-exports=t,s --quiet -all -S -o - | filecheck %s + +;; A corner case where we export the start function and consider it a ctor. +;; That it executes twice should not cause an internal error. + +(module + (rec + (type $A (sub (shared (struct (field (mut (ref null $B))))))) + (type $B (sub (shared (struct (field (mut (ref null (shared any)))))))) + ) + + (global $global (ref $A) (struct.new $A + (struct.new_default $B) + )) + + (export "s" (func $s)) + + (export "t" (func $t)) + + (start $s) + + (func $s + (nop) + ) + + (func $t + (nop) + ) +) + +;; CHECK: (type $0 (func)) + +;; CHECK: (export "s" (func $s_4)) + +;; CHECK: (export "t" (func $t_3)) + +;; CHECK: (func $t_3 (type $0) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) + +;; CHECK: (func $s_4 (type $0) +;; CHECK-NEXT: (nop) +;; CHECK-NEXT: ) From 18a9854736b45089d014c42370ff303b18acebad Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 15 May 2026 10:51:25 -0700 Subject: [PATCH 10/12] fix --- src/tools/wasm-ctor-eval.cpp | 35 +++++++++++------ test/lit/ctor-eval/gc-cycle-multi.wast | 17 +++++++++ test/lit/ctor-eval/gc-cycle.wast | 53 ++++++++++++++++++++++++++ test/lit/ctor-eval/start-rerun.wast | 26 +++++++++++-- 4 files changed, 116 insertions(+), 15 deletions(-) diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 57df170cac2..c8fe1d5e385 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -312,13 +312,21 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { linkedInstances.swap(linkedInstances_); } + bool firstApplication = true; + // Called when we want to apply the current state of execution to the Module. // Until this is called the Module is never changed. void applyToModule() { - // If we got to the point of applying things to the module, then we evalled - // a ctor, which means we evalled the start function. Wipe it out, as it - // must not run again (just like a ctor that runs before all others). - wasm->start = Name(); + if (firstApplication) { + // The first time we apply things to the module, we can remove the start + // function: we evalled it successfully, if we got to here (and we must + // not execute it again later, which would mean it runs twice). We do not + // do this after the first application because we start to build up a new + // start function with the things we need, unrelated to the original one + // (see addStartFixup). + wasm->start = Name(); + firstApplication = false; + } clearApplyState(); @@ -1034,14 +1042,17 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { void createStartBlock() { Builder builder(*wasm); startBlock = builder.makeBlock(); - // There is no existing start, because each time we apply changes, we - // evalled away the old one. - assert(!wasm->start); - - // Make a new start function. - wasm->start = Names::getValidFunctionName(*wasm, "start"); - wasm->addFunction(builder.makeFunction( - wasm->start, Signature{Type::none, Type::none}, {}, *startBlock)); + if (wasm->start.is()) { + // Put our block before any user start code. + auto* existingStart = wasm->getFunction(wasm->start); + existingStart->body = + builder.makeSequence(*startBlock, existingStart->body); + } else { + // Make a new start function. + wasm->start = Names::getValidFunctionName(*wasm, "start"); + wasm->addFunction(builder.makeFunction( + wasm->start, Signature{Type::none, Type::none}, {}, *startBlock)); + } } void clearStartBlock() { diff --git a/test/lit/ctor-eval/gc-cycle-multi.wast b/test/lit/ctor-eval/gc-cycle-multi.wast index d6299516756..dc14403b32f 100644 --- a/test/lit/ctor-eval/gc-cycle-multi.wast +++ b/test/lit/ctor-eval/gc-cycle-multi.wast @@ -82,6 +82,8 @@ ;; CHECK: (export "keepalive" (func $keepalive)) + ;; CHECK: (start $start) + ;; CHECK: (func $keepalive (type $2) (result i32) ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (struct.get $A 1 @@ -113,6 +115,21 @@ ) ) ) +;; CHECK: (func $start (type $1) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_6) +;; CHECK-NEXT: (global.get $ctor-eval$global_6) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: (global.get $ctor-eval$global_7) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: (global.get $ctor-eval$global_8) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + ;; CHECK: (func $test1_6 (type $1) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) diff --git a/test/lit/ctor-eval/gc-cycle.wast b/test/lit/ctor-eval/gc-cycle.wast index 440cc46ab94..7a53e87dd5f 100644 --- a/test/lit/ctor-eval/gc-cycle.wast +++ b/test/lit/ctor-eval/gc-cycle.wast @@ -1101,12 +1101,18 @@ ) ) + ;; CHECK: (global $ctor-eval$global_15 (ref (exact $B)) (array.new_fixed $B 0)) + + ;; CHECK: (global $ctor-eval$global_19 (ref (exact $B)) (array.new_fixed $B 0)) + ;; CHECK: (export "test" (func $test_4)) ;; CHECK: (export "keepalive" (func $keepalive)) ;; CHECK: (export "keepalive-B" (func $keepalive-B)) + ;; CHECK: (start $start) + ;; CHECK: (func $keepalive (type $2) (result anyref) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -1132,6 +1138,21 @@ ) ) +;; CHECK: (func $start (type $3) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_14) +;; CHECK-NEXT: (global.get $ctor-eval$global_15) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (struct.set $A 1 +;; CHECK-NEXT: (global.get $ctor-eval$global_14) +;; CHECK-NEXT: (global.get $ctor-eval$global_16) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (struct.set $A 2 +;; CHECK-NEXT: (global.get $ctor-eval$global_14) +;; CHECK-NEXT: (global.get $ctor-eval$global_19) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + ;; CHECK: (func $test_4 (type $3) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (nop) @@ -1202,12 +1223,26 @@ ) ) + ;; CHECK: (global $ctor-eval$global_15 (ref (exact $A)) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: )) + + ;; CHECK: (global $ctor-eval$global_19 (ref (exact $A)) (struct.new $A + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: )) + ;; CHECK: (export "test" (func $test_4)) ;; CHECK: (export "keepalive" (func $keepalive)) ;; CHECK: (export "keepalive-B" (func $keepalive-B)) + ;; CHECK: (start $start) + ;; CHECK: (func $keepalive (type $2) (result anyref) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) @@ -1233,6 +1268,24 @@ ) ) +;; CHECK: (func $start (type $3) +;; CHECK-NEXT: (array.set $B +;; CHECK-NEXT: (global.get $ctor-eval$global_14) +;; CHECK-NEXT: (i32.const 0) +;; CHECK-NEXT: (global.get $ctor-eval$global_15) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (array.set $B +;; CHECK-NEXT: (global.get $ctor-eval$global_14) +;; CHECK-NEXT: (i32.const 1) +;; CHECK-NEXT: (global.get $ctor-eval$global_16) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (array.set $B +;; CHECK-NEXT: (global.get $ctor-eval$global_14) +;; CHECK-NEXT: (i32.const 2) +;; CHECK-NEXT: (global.get $ctor-eval$global_19) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + ;; CHECK: (func $test_4 (type $3) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (nop) diff --git a/test/lit/ctor-eval/start-rerun.wast b/test/lit/ctor-eval/start-rerun.wast index 30be014784d..540ae38dc82 100644 --- a/test/lit/ctor-eval/start-rerun.wast +++ b/test/lit/ctor-eval/start-rerun.wast @@ -6,7 +6,10 @@ (module (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $A (sub (shared (struct (field (mut (ref null $B))))))) (type $A (sub (shared (struct (field (mut (ref null $B))))))) + ;; CHECK: (type $B (sub (shared (struct (field (mut (ref null (shared any)))))))) (type $B (sub (shared (struct (field (mut (ref null (shared any)))))))) ) @@ -29,16 +32,33 @@ ) ) -;; CHECK: (type $0 (func)) +;; CHECK: (type $2 (func)) + +;; CHECK: (global $ctor-eval$global_3 (ref (exact $A)) (struct.new $A +;; CHECK-NEXT: (ref.null (shared none)) +;; CHECK-NEXT: )) + +;; CHECK: (global $ctor-eval$global_4 (ref (exact $B)) (struct.new $B +;; CHECK-NEXT: (ref.null (shared none)) +;; CHECK-NEXT: )) ;; CHECK: (export "s" (func $s_4)) ;; CHECK: (export "t" (func $t_3)) -;; CHECK: (func $t_3 (type $0) +;; CHECK: (start $start) + +;; CHECK: (func $start (type $2) +;; CHECK-NEXT: (struct.set $A 0 +;; CHECK-NEXT: (global.get $ctor-eval$global_3) +;; CHECK-NEXT: (global.get $ctor-eval$global_4) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) + +;; CHECK: (func $t_3 (type $2) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) -;; CHECK: (func $s_4 (type $0) +;; CHECK: (func $s_4 (type $2) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) From 437e645ede12f7fc8b115b342d748d069b4957a6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 15 May 2026 10:53:02 -0700 Subject: [PATCH 11/12] revert --- test/lit/ctor-eval/gc-cycle.wast | 239 +++++++------------------------ 1 file changed, 53 insertions(+), 186 deletions(-) diff --git a/test/lit/ctor-eval/gc-cycle.wast b/test/lit/ctor-eval/gc-cycle.wast index 7a53e87dd5f..736feec5bc8 100644 --- a/test/lit/ctor-eval/gc-cycle.wast +++ b/test/lit/ctor-eval/gc-cycle.wast @@ -530,6 +530,8 @@ ) + (global $b (mut (ref null $B)) (ref.null $B)) + ;; CHECK: (type $2 (func)) ;; CHECK: (type $3 (func (result i32))) @@ -545,10 +547,6 @@ ;; CHECK-NEXT: )) ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_7)) - - ;; CHECK: (global $b (mut (ref null $B)) (global.get $ctor-eval$global_8)) - (global $b (mut (ref null $B)) (ref.null $B)) - (global $a (mut (ref null $A)) (ref.null $A)) (func $test (export "test") @@ -583,23 +581,13 @@ ;; CHECK: (start $start) ;; CHECK: (func $keepalive (type $3) (result i32) - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (struct.get $A 1 - ;; CHECK-NEXT: (global.get $a) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.get $B 1 - ;; CHECK-NEXT: (global.get $b) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $keepalive (export "keepalive") (result i32) - (i32.add - (struct.get $A 1 - (global.get $a) - ) - (struct.get $B 1 - (global.get $b) - ) + (struct.get $A 1 + (global.get $a) ) ) ) @@ -644,10 +632,8 @@ ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_12)) (global $a (mut (ref null $A)) (ref.null $A)) - ;; CHECK: (global $b (mut (ref null $A)) (global.get $ctor-eval$global_14)) (global $b (mut (ref null $A)) (ref.null $A)) - ;; CHECK: (global $c (mut (ref null $A)) (global.get $ctor-eval$global_13)) (global $c (mut (ref null $A)) (ref.null $A)) (func $test (export "test") @@ -691,29 +677,13 @@ ;; CHECK: (start $start) ;; CHECK: (func $keepalive (type $2) (result i32) - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (struct.get $A 1 - ;; CHECK-NEXT: (global.get $a) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.get $A 1 - ;; CHECK-NEXT: (global.get $b) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.get $A 1 - ;; CHECK-NEXT: (global.get $c) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $keepalive (export "keepalive") (result i32) - (select - (struct.get $A 1 - (global.get $a) - ) - (struct.get $A 1 - (global.get $b) - ) - (struct.get $A 1 - (global.get $c) - ) + (struct.get $A 1 + (global.get $a) ) ) ) @@ -747,11 +717,13 @@ (type $C (array (mut (ref any)))) ) - ;; CHECK: (type $3 (func (result anyref))) + (global $c (mut (ref null $C)) (ref.null $C)) - ;; CHECK: (type $4 (func)) + (global $b (mut (ref null $B)) (ref.null $B)) + + ;; CHECK: (type $3 (func)) - ;; CHECK: (type $5 (func (result i32))) + ;; CHECK: (type $4 (func (result i32))) ;; CHECK: (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -772,19 +744,6 @@ ;; CHECK-NEXT: )) ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_12)) - - ;; CHECK: (global $ctor-eval$global_13 (ref (exact $C)) (array.new_fixed $C 2 - ;; CHECK-NEXT: (global.get $ctor-eval$global_14) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: )) - - ;; CHECK: (global $b (mut (ref null $B)) (global.get $ctor-eval$global_14)) - - ;; CHECK: (global $c (mut (ref null $C)) (global.get $ctor-eval$global_13)) - (global $c (mut (ref null $C)) (ref.null $C)) - - (global $b (mut (ref null $B)) (ref.null $B)) - (global $a (mut (ref null $A)) (ref.null $A)) (func $test (export "test") @@ -821,17 +780,18 @@ ) ) - ;; CHECK: (export "test" (func $test_5)) - - ;; CHECK: (export "keepalive" (func $keepalive)) + ;; CHECK: (global $ctor-eval$global_13 (ref (exact $C)) (array.new_fixed $C 2 + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: )) - ;; CHECK: (export "keepalive-B" (func $keepalive-B)) + ;; CHECK: (export "test" (func $test_3)) - ;; CHECK: (export "keepalive-C" (func $keepalive-C)) + ;; CHECK: (export "keepalive" (func $keepalive)) ;; CHECK: (start $start) - ;; CHECK: (func $keepalive (type $5) (result i32) + ;; CHECK: (func $keepalive (type $4) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -841,42 +801,16 @@ (global.get $a) ) ) - - ;; CHECK: (func $keepalive-B (type $3) (result anyref) - ;; CHECK-NEXT: (array.get $B - ;; CHECK-NEXT: (global.get $b) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $keepalive-B (export "keepalive-B") (result anyref) - (array.get $B - (global.get $b) - (i32.const 0) - ) - ) - - ;; CHECK: (func $keepalive-C (type $3) (result anyref) - ;; CHECK-NEXT: (array.get $C - ;; CHECK-NEXT: (global.get $c) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $keepalive-C (export "keepalive-C") (result anyref) - (array.get $C - (global.get $c) - (i32.const 0) - ) - ) ) -;; CHECK: (func $start (type $4) +;; CHECK: (func $start (type $3) ;; CHECK-NEXT: (struct.set $A 0 ;; CHECK-NEXT: (global.get $ctor-eval$global_12) ;; CHECK-NEXT: (global.get $ctor-eval$global_13) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) -;; CHECK: (func $test_5 (type $4) +;; CHECK: (func $test_3 (type $3) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (local $c (ref $C)) @@ -895,11 +829,9 @@ (type $C (array (mut (ref any)))) ) - ;; CHECK: (type $3 (func (result anyref))) - - ;; CHECK: (type $4 (func)) + ;; CHECK: (type $3 (func)) - ;; CHECK: (type $5 (func (result i32))) + ;; CHECK: (type $4 (func (result i32))) ;; CHECK: (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -922,15 +854,8 @@ ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_12)) (global $a (mut (ref null $A)) (ref.null $A)) - ;; CHECK: (global $ctor-eval$global_13 (ref (exact $C)) (array.new_fixed $C 2 - ;; CHECK-NEXT: (global.get $ctor-eval$global_14) - ;; CHECK-NEXT: (global.get $ctor-eval$global_12) - ;; CHECK-NEXT: )) - - ;; CHECK: (global $b (mut (ref null $B)) (global.get $ctor-eval$global_14)) (global $b (mut (ref null $B)) (ref.null $B)) - ;; CHECK: (global $c (mut (ref null $C)) (global.get $ctor-eval$global_13)) (global $c (mut (ref null $C)) (ref.null $C)) (func $test (export "test") @@ -967,17 +892,18 @@ ) ) - ;; CHECK: (export "test" (func $test_5)) - - ;; CHECK: (export "keepalive" (func $keepalive)) + ;; CHECK: (global $ctor-eval$global_13 (ref (exact $C)) (array.new_fixed $C 2 + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_12) + ;; CHECK-NEXT: )) - ;; CHECK: (export "keepalive-B" (func $keepalive-B)) + ;; CHECK: (export "test" (func $test_3)) - ;; CHECK: (export "keepalive-C" (func $keepalive-C)) + ;; CHECK: (export "keepalive" (func $keepalive)) ;; CHECK: (start $start) - ;; CHECK: (func $keepalive (type $5) (result i32) + ;; CHECK: (func $keepalive (type $4) (result i32) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -987,42 +913,16 @@ (global.get $a) ) ) - - ;; CHECK: (func $keepalive-B (type $3) (result anyref) - ;; CHECK-NEXT: (array.get $B - ;; CHECK-NEXT: (global.get $b) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $keepalive-B (export "keepalive-B") (result anyref) - (array.get $B - (global.get $b) - (i32.const 0) - ) - ) - - ;; CHECK: (func $keepalive-C (type $3) (result anyref) - ;; CHECK-NEXT: (array.get $C - ;; CHECK-NEXT: (global.get $c) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $keepalive-C (export "keepalive-C") (result anyref) - (array.get $C - (global.get $c) - (i32.const 0) - ) - ) ) -;; CHECK: (func $start (type $4) +;; CHECK: (func $start (type $3) ;; CHECK-NEXT: (struct.set $A 0 ;; CHECK-NEXT: (global.get $ctor-eval$global_12) ;; CHECK-NEXT: (global.get $ctor-eval$global_13) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) -;; CHECK: (func $test_5 (type $4) +;; CHECK: (func $test_3 (type $3) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (local $c (ref $C)) @@ -1040,9 +940,9 @@ (type $B (array (ref null $A))) ) - ;; CHECK: (type $2 (func (result anyref))) + ;; CHECK: (type $2 (func)) - ;; CHECK: (type $3 (func)) + ;; CHECK: (type $3 (func (result anyref))) ;; CHECK: (global $ctor-eval$global_17 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (ref.null none) @@ -1064,13 +964,6 @@ ;; CHECK: (global $a (mut (ref null $A)) (global.get $ctor-eval$global_14)) (global $a (mut (ref null $A)) (ref.null $A)) - ;; CHECK: (global $ctor-eval$global_16 (ref (exact $B)) (array.new_fixed $B 3 - ;; CHECK-NEXT: (global.get $ctor-eval$global_17) - ;; CHECK-NEXT: (global.get $ctor-eval$global_14) - ;; CHECK-NEXT: (global.get $ctor-eval$global_18) - ;; CHECK-NEXT: )) - - ;; CHECK: (global $b (mut (ref null $B)) (global.get $ctor-eval$global_16)) (global $b (mut (ref null $B)) (ref.null $B)) (func $test (export "test") @@ -1101,19 +994,23 @@ ) ) + ;; CHECK: (global $ctor-eval$global_16 (ref (exact $B)) (array.new_fixed $B 3 + ;; CHECK-NEXT: (global.get $ctor-eval$global_17) + ;; CHECK-NEXT: (global.get $ctor-eval$global_14) + ;; CHECK-NEXT: (global.get $ctor-eval$global_18) + ;; CHECK-NEXT: )) + ;; CHECK: (global $ctor-eval$global_15 (ref (exact $B)) (array.new_fixed $B 0)) ;; CHECK: (global $ctor-eval$global_19 (ref (exact $B)) (array.new_fixed $B 0)) - ;; CHECK: (export "test" (func $test_4)) + ;; CHECK: (export "test" (func $test_3)) ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (export "keepalive-B" (func $keepalive-B)) - ;; CHECK: (start $start) - ;; CHECK: (func $keepalive (type $2) (result anyref) + ;; CHECK: (func $keepalive (type $3) (result anyref) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -1123,22 +1020,9 @@ (global.get $a) ) ) - - ;; CHECK: (func $keepalive-B (type $2) (result anyref) - ;; CHECK-NEXT: (array.get $B - ;; CHECK-NEXT: (global.get $b) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $keepalive-B (export "keepalive-B") (result (ref null any)) - (array.get $B - (global.get $b) - (i32.const 0) - ) - ) ) -;; CHECK: (func $start (type $3) +;; CHECK: (func $start (type $2) ;; CHECK-NEXT: (struct.set $A 0 ;; CHECK-NEXT: (global.get $ctor-eval$global_14) ;; CHECK-NEXT: (global.get $ctor-eval$global_15) @@ -1153,7 +1037,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) -;; CHECK: (func $test_4 (type $3) +;; CHECK: (func $test_3 (type $2) ;; CHECK-NEXT: (local $a (ref $A)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) @@ -1168,9 +1052,9 @@ (type $B (array (mut (ref null $A)))) ) - ;; CHECK: (type $2 (func (result anyref))) + ;; CHECK: (type $2 (func)) - ;; CHECK: (type $3 (func)) + ;; CHECK: (type $3 (func (result anyref))) ;; CHECK: (global $ctor-eval$global_17 (ref (exact $B)) (array.new_fixed $B 0)) @@ -1182,8 +1066,6 @@ ;; CHECK: (global $ctor-eval$global_18 (ref (exact $B)) (array.new_fixed $B 0)) - ;; CHECK: (global $b (mut (ref null $B)) (global.get $ctor-eval$global_14)) - ;; CHECK: (global $ctor-eval$global_16 (ref (exact $A)) (struct.new $A ;; CHECK-NEXT: (global.get $ctor-eval$global_17) ;; CHECK-NEXT: (global.get $ctor-eval$global_14) @@ -1235,15 +1117,13 @@ ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: )) - ;; CHECK: (export "test" (func $test_4)) + ;; CHECK: (export "test" (func $test_3)) ;; CHECK: (export "keepalive" (func $keepalive)) - ;; CHECK: (export "keepalive-B" (func $keepalive-B)) - ;; CHECK: (start $start) - ;; CHECK: (func $keepalive (type $2) (result anyref) + ;; CHECK: (func $keepalive (type $3) (result anyref) ;; CHECK-NEXT: (struct.get $A 1 ;; CHECK-NEXT: (global.get $a) ;; CHECK-NEXT: ) @@ -1253,22 +1133,9 @@ (global.get $a) ) ) - - ;; CHECK: (func $keepalive-B (type $2) (result anyref) - ;; CHECK-NEXT: (array.get $B - ;; CHECK-NEXT: (global.get $b) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $keepalive-B (export "keepalive-B") (result anyref) - (array.get $B - (global.get $b) - (i32.const 0) - ) - ) ) -;; CHECK: (func $start (type $3) +;; CHECK: (func $start (type $2) ;; CHECK-NEXT: (array.set $B ;; CHECK-NEXT: (global.get $ctor-eval$global_14) ;; CHECK-NEXT: (i32.const 0) @@ -1286,7 +1153,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) -;; CHECK: (func $test_4 (type $3) +;; CHECK: (func $test_3 (type $2) ;; CHECK-NEXT: (local $b (ref $B)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) From 7e2142a625095e51e0141fee77184f40ca268057 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 15 May 2026 10:57:36 -0700 Subject: [PATCH 12/12] comment --- test/lit/ctor-eval/gc-cycle.wast | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/lit/ctor-eval/gc-cycle.wast b/test/lit/ctor-eval/gc-cycle.wast index 736feec5bc8..faf26c4adec 100644 --- a/test/lit/ctor-eval/gc-cycle.wast +++ b/test/lit/ctor-eval/gc-cycle.wast @@ -1158,7 +1158,9 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (module - ;; The start function already exists here. We must prepend to it. + ;; The start function already exists here. We must *not* prepend to it: it gets + ;; evalled away too (we execute it before the first ctor, and we should not + ;; eval those contents twice). ;; CHECK: (type $A (struct (field (mut (ref null $A))) (field i32))) (type $A (struct (field (mut (ref null $A))) (field i32)))