From e929730a10b96f9e4070e45025e6450e45c4cd68 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 27 Jan 2026 14:03:47 -0800 Subject: [PATCH 1/2] start --- src/ir/possible-contents.cpp | 5 ++ test/lit/passes/gufa-configureAll.wast | 90 ++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 test/lit/passes/gufa-configureAll.wast diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 9170a16524d..c018cf628d7 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -2454,6 +2454,11 @@ Flower::Flower(Module& wasm, const PassOptions& options) } } + // configureAll functions are called from outside the module, as if exported. + for (auto func : Intrinsics(wasm).getConfigureAllFunctions()) { + calledFromOutside.insert(func); + } + // Apply changes to all functions called from outside. for (auto funcName : calledFromOutside) { auto* func = wasm.getFunction(funcName); diff --git a/test/lit/passes/gufa-configureAll.wast b/test/lit/passes/gufa-configureAll.wast new file mode 100644 index 00000000000..185498fa03f --- /dev/null +++ b/test/lit/passes/gufa-configureAll.wast @@ -0,0 +1,90 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; RUN: foreach %s %t wasm-opt --signature-pruning --closed-world -all -S -o - | filecheck %s + +;; Test that configureAll is respected: referred functions are assumed to be +;; called from outside the module, depsite closed world. + +(module + ;; CHECK: (type $externs (array (mut externref))) + (type $externs (array (mut externref))) + + ;; CHECK: (type $funcs (array (mut funcref))) + (type $funcs (array (mut funcref))) + + ;; CHECK: (type $bytes (array (mut i8))) + (type $bytes (array (mut i8))) + + ;; CHECK: (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref))) + (type $configureAll (func (param (ref null $externs)) (param (ref null $funcs)) (param (ref null $bytes)) (param externref))) + + (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll))) + + ;; CHECK: (data $bytes "12345678") + (data $bytes "12345678") + + ;; CHECK: (elem $externs externref (item (ref.null noextern))) + (elem $externs externref + (ref.null extern) + ) + + ;; CHECK: (elem $funcs func $configured) + (elem $funcs funcref + (ref.func $configured) + (ref.func $unconfigured) ;; in the elem, but not sent to configureAll + ) + + ;; CHECK: (start $start) + (start $start) + + ;; CHECK: (func $start (type $7) + ;; CHECK-NEXT: (call $configureAll + ;; CHECK-NEXT: (array.new_elem $externs $externs + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (array.new_elem $funcs $funcs + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (array.new_data $bytes $bytes + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 8) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null noextern) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $start + (call $configureAll + (array.new_elem $externs $externs + (i32.const 0) (i32.const 1)) + (array.new_elem $funcs $funcs + (i32.const 0) (i32.const 1)) ;; only send index 0, not 1 + (array.new_data $bytes $bytes + (i32.const 0) (i32.const 8)) + (ref.null extern) + ) + ) + + ;; CHECK: (func $foo (type $6) (result i32) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + (func $configured (param $x i32) (result i32) + ;; The call from outside the module, through configureAll, is the only call + ;; we have - without it, this would be unreachable code, and optimized away. + (i32.eqz + (local.get $x) + ) + ) + + ;; CHECK: (func $unconfigured (type $any-2) + ;; CHECK-NEXT: (local $0 anyref) + ;; CHECK-NEXT: ) + (func $unconfigured (param $x i32) (result i32) + ;; As above, but *not* in configureAll (though it is in a table, so it is + ;; not entirely removed) - so we do optimize. + (i32.eqz + (local.get $x) + ) + ) +) From 7acaa8558b50edfaebce5223941bf599bf2e67c3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 27 Jan 2026 14:05:09 -0800 Subject: [PATCH 2/2] test --- test/lit/passes/gufa-configureAll.wast | 31 ++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/test/lit/passes/gufa-configureAll.wast b/test/lit/passes/gufa-configureAll.wast index 185498fa03f..274ad8fa1d4 100644 --- a/test/lit/passes/gufa-configureAll.wast +++ b/test/lit/passes/gufa-configureAll.wast @@ -1,6 +1,6 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. -;; RUN: foreach %s %t wasm-opt --signature-pruning --closed-world -all -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt --gufa --closed-world -all -S -o - | filecheck %s ;; Test that configureAll is respected: referred functions are assumed to be ;; called from outside the module, depsite closed world. @@ -15,9 +15,14 @@ ;; CHECK: (type $bytes (array (mut i8))) (type $bytes (array (mut i8))) + ;; CHECK: (type $3 (func (param i32) (result i32))) + ;; CHECK: (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref))) (type $configureAll (func (param (ref null $externs)) (param (ref null $funcs)) (param (ref null $bytes)) (param externref))) + ;; CHECK: (type $5 (func)) + + ;; CHECK: (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll) (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref))) (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll))) ;; CHECK: (data $bytes "12345678") @@ -31,13 +36,17 @@ ;; CHECK: (elem $funcs func $configured) (elem $funcs funcref (ref.func $configured) - (ref.func $unconfigured) ;; in the elem, but not sent to configureAll + ) + + ;; CHECK: (elem $other func $unconfigured) + (elem $other funcref + (ref.func $unconfigured) ) ;; CHECK: (start $start) (start $start) - ;; CHECK: (func $start (type $7) + ;; CHECK: (func $start (type $5) ;; CHECK-NEXT: (call $configureAll ;; CHECK-NEXT: (array.new_elem $externs $externs ;; CHECK-NEXT: (i32.const 0) @@ -45,7 +54,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (array.new_elem $funcs $funcs ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (array.new_data $bytes $bytes ;; CHECK-NEXT: (i32.const 0) @@ -59,15 +68,17 @@ (array.new_elem $externs $externs (i32.const 0) (i32.const 1)) (array.new_elem $funcs $funcs - (i32.const 0) (i32.const 1)) ;; only send index 0, not 1 + (i32.const 0) (i32.const 1)) (array.new_data $bytes $bytes (i32.const 0) (i32.const 8)) (ref.null extern) ) ) - ;; CHECK: (func $foo (type $6) (result i32) - ;; CHECK-NEXT: (i32.const 42) + ;; CHECK: (func $configured (type $3) (param $x i32) (result i32) + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $configured (param $x i32) (result i32) ;; The call from outside the module, through configureAll, is the only call @@ -77,8 +88,10 @@ ) ) - ;; CHECK: (func $unconfigured (type $any-2) - ;; CHECK-NEXT: (local $0 anyref) + ;; CHECK: (func $unconfigured (type $3) (param $x i32) (result i32) + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $unconfigured (param $x i32) (result i32) ;; As above, but *not* in configureAll (though it is in a table, so it is