From 8e8f130c7540b062f96a5a86c7432f95eeda55c2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 17 Nov 2025 13:31:07 -0800 Subject: [PATCH 1/8] start.almost --- src/ir/module-utils.cpp | 20 --- src/passes/AbstractTypeRefining.cpp | 3 +- src/passes/TypeFinalizing.cpp | 2 + .../signature-pruning-configureAll.wast | 169 ++++++++++++++++++ .../signature-refining-configureAll.wast | 34 ++-- 5 files changed, 189 insertions(+), 39 deletions(-) create mode 100644 test/lit/passes/signature-pruning-configureAll.wast diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp index 0dd3342f0d8..32a8a079dce 100644 --- a/src/ir/module-utils.cpp +++ b/src/ir/module-utils.cpp @@ -693,26 +693,6 @@ std::vector getPublicHeapTypes(Module& wasm) { WASM_UNREACHABLE("unexpected export kind"); } - // ConfigureAll in a start function makes its functions callable. They are - // only signature-called, so the heap type does not need to be public - nor - // types referred to - but for now we mark them as public to avoid breakage in - // several passes. - // TODO Specific fixes in those passes could replace this, and allow better - // optimization. - if (wasm.start) { - auto* start = wasm.getFunction(wasm.start); - if (!start->imported()) { - Intrinsics intrinsics(wasm); - for (auto* call : FindAll(start->body).list) { - if (intrinsics.isConfigureAll(call)) { - for (auto func : intrinsics.getConfigureAllFunctions(call)) { - notePublic(wasm.getFunction(func)->type.getHeapType()); - } - } - } - } - } - // Ignorable public types are public. for (auto type : getIgnorablePublicTypes()) { notePublic(type); diff --git a/src/passes/AbstractTypeRefining.cpp b/src/passes/AbstractTypeRefining.cpp index 73551f3c729..d29cfb893c7 100644 --- a/src/passes/AbstractTypeRefining.cpp +++ b/src/passes/AbstractTypeRefining.cpp @@ -243,7 +243,8 @@ struct AbstractTypeRefining : public Pass { for (auto type : subTypes.types) { if (!type.isStruct()) { - // TODO: support arrays and funcs + // TODO: Support arrays and functions (for functions we will need to + // handle configureAll). continue; } diff --git a/src/passes/TypeFinalizing.cpp b/src/passes/TypeFinalizing.cpp index ebf04318af3..083c2a4ab44 100644 --- a/src/passes/TypeFinalizing.cpp +++ b/src/passes/TypeFinalizing.cpp @@ -50,6 +50,8 @@ struct TypeFinalizing : public Pass { subTypes = SubTypes(*module); } + // Note we don't need to worry about signature-called functions here + // (configureAll) because such calls don't care about finality. auto privateTypes = ModuleUtils::getPrivateHeapTypes(*module); for (auto type : privateTypes) { // If we are finalizing types then we can only do that to leaf types. If diff --git a/test/lit/passes/signature-pruning-configureAll.wast b/test/lit/passes/signature-pruning-configureAll.wast new file mode 100644 index 00000000000..111bf625860 --- /dev/null +++ b/test/lit/passes/signature-pruning-configureAll.wast @@ -0,0 +1,169 @@ +;; 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 --signature-pruning -all -S -o - | filecheck %s --check-prefix OPEN_WORLD + +;; Test that configureAll is respected: referred functions are not pruned. +;; This is so even in closed world. + +(module + ;; CHECK: (type $externs (array (mut externref))) + ;; OPEN_WORLD: (type $externs (array (mut externref))) + (type $externs (array (mut externref))) + + ;; CHECK: (type $funcs (array (mut funcref))) + ;; OPEN_WORLD: (type $funcs (array (mut funcref))) + (type $funcs (array (mut funcref))) + + ;; CHECK: (type $bytes (array (mut i8))) + ;; OPEN_WORLD: (type $bytes (array (mut i8))) + (type $bytes (array (mut i8))) + + ;; CHECK: (rec + ;; CHECK-NEXT: (type $ret-any-2 (func (result (ref (exact $struct))))) + + ;; CHECK: (type $struct (struct)) + + ;; CHECK: (type $ret-any-1 (func (result (ref (exact $struct))))) + + ;; CHECK: (type $6 (func (result i32))) + + ;; CHECK: (type $7 (func)) + + ;; CHECK: (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref))) + ;; OPEN_WORLD: (rec + ;; OPEN_WORLD-NEXT: (type $ret-any-2 (func (result (ref (exact $struct))))) + + ;; OPEN_WORLD: (type $struct (struct)) + + ;; OPEN_WORLD: (type $ret-any-1 (func (result (ref (exact $struct))))) + + ;; OPEN_WORLD: (type $6 (func (result i32))) + + ;; OPEN_WORLD: (type $7 (func)) + + ;; OPEN_WORLD: (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))) + + (type $struct (struct)) + + (rec + (type $any-1 (func (param anyref))) + + ;; use brands to allow $any-1/2 to be optimized separately. + (type $brand1 (struct)) + ) + + (rec + (type $any-2 (func (param anyref))) + + (type $brand2 (struct)) + (type $brand3 (struct)) + ) + + ;; CHECK: (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll) (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref))) + ;; OPEN_WORLD: (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") + + ;; CHECK: (elem $externs externref (item (ref.null noextern))) + ;; OPEN_WORLD: (data $bytes "12345678") + + ;; OPEN_WORLD: (elem $externs externref (item (ref.null noextern))) + (elem $externs externref + (ref.null extern) + ) + + ;; CHECK: (elem $funcs func $foo $bar) + ;; OPEN_WORLD: (elem $funcs func $foo $bar) + (elem $funcs funcref + (ref.func $foo) + (ref.func $bar) + ) + + (data $bytes "12345678") + + ;; CHECK: (start $start) + ;; OPEN_WORLD: (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: ) + ;; OPEN_WORLD: (func $start (type $7) + ;; OPEN_WORLD-NEXT: (call $configureAll + ;; OPEN_WORLD-NEXT: (array.new_elem $externs $externs + ;; OPEN_WORLD-NEXT: (i32.const 0) + ;; OPEN_WORLD-NEXT: (i32.const 1) + ;; OPEN_WORLD-NEXT: ) + ;; OPEN_WORLD-NEXT: (array.new_elem $funcs $funcs + ;; OPEN_WORLD-NEXT: (i32.const 0) + ;; OPEN_WORLD-NEXT: (i32.const 2) + ;; OPEN_WORLD-NEXT: ) + ;; OPEN_WORLD-NEXT: (array.new_data $bytes $bytes + ;; OPEN_WORLD-NEXT: (i32.const 0) + ;; OPEN_WORLD-NEXT: (i32.const 8) + ;; OPEN_WORLD-NEXT: ) + ;; OPEN_WORLD-NEXT: (ref.null noextern) + ;; OPEN_WORLD-NEXT: ) + ;; OPEN_WORLD-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 2)) + (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: ) + ;; OPEN_WORLD: (func $foo (type $6) (result i32) + ;; OPEN_WORLD-NEXT: (i32.const 42) + ;; OPEN_WORLD-NEXT: ) + (func $foo (result i32) + ;; Nothing to do here anyhow, but do not error. + (i32.const 42) + ) + + ;; CHECK: (func $bar (type $ret-any-1) (result (ref (exact $struct))) + ;; CHECK-NEXT: (struct.new_default $struct) + ;; CHECK-NEXT: ) + ;; OPEN_WORLD: (func $bar (type $ret-any-1) (result (ref (exact $struct))) + ;; OPEN_WORLD-NEXT: (struct.new_default $struct) + ;; OPEN_WORLD-NEXT: ) + (func $bar (type $any-1) (param $x anyref) + ;; The param is unused, but will not be pruned due to configureAll. + (struct.new $struct) + ) + + ;; CHECK: (func $unconfigured (type $ret-any-2) (result (ref (exact $struct))) + ;; CHECK-NEXT: (struct.new_default $struct) + ;; CHECK-NEXT: ) + ;; OPEN_WORLD: (func $unconfigured (type $ret-any-2) (result (ref (exact $struct))) + ;; OPEN_WORLD-NEXT: (struct.new_default $struct) + ;; OPEN_WORLD-NEXT: ) + (func $unconfigured (type $any-2) (param $x anyref) + ;; This is not referred to by configureAll, and can be pruned. + (struct.new $struct) + ) +) diff --git a/test/lit/passes/signature-refining-configureAll.wast b/test/lit/passes/signature-refining-configureAll.wast index 48ca0dfffd9..9cb7f0c56ae 100644 --- a/test/lit/passes/signature-refining-configureAll.wast +++ b/test/lit/passes/signature-refining-configureAll.wast @@ -24,7 +24,11 @@ ;; CHECK: (type $struct (struct)) - ;; CHECK: (type $5 (func)) + ;; CHECK: (type $ret-any-1 (func (result (ref (exact $struct))))) + + ;; CHECK: (type $6 (func (result i32))) + + ;; CHECK: (type $7 (func)) ;; CHECK: (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref))) ;; OPEN_WORLD: (rec @@ -32,7 +36,11 @@ ;; OPEN_WORLD: (type $struct (struct)) - ;; OPEN_WORLD: (type $5 (func)) + ;; OPEN_WORLD: (type $ret-any-1 (func (result (ref (exact $struct))))) + + ;; OPEN_WORLD: (type $6 (func (result i32))) + + ;; OPEN_WORLD: (type $7 (func)) ;; OPEN_WORLD: (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))) @@ -40,19 +48,9 @@ (type $struct (struct)) (rec - ;; CHECK: (type $7 (func (result i32))) - - ;; CHECK: (rec - ;; CHECK-NEXT: (type $ret-any-1 (func (result anyref))) - ;; OPEN_WORLD: (type $7 (func (result i32))) - - ;; OPEN_WORLD: (rec - ;; OPEN_WORLD-NEXT: (type $ret-any-1 (func (result anyref))) (type $ret-any-1 (func (result anyref))) ;; use brands to allow $ret-any-1/2 to be optimized separately. - ;; CHECK: (type $brand1 (struct)) - ;; OPEN_WORLD: (type $brand1 (struct)) (type $brand1 (struct)) ) @@ -90,7 +88,7 @@ ;; OPEN_WORLD: (start $start) (start $start) - ;; CHECK: (func $start (type $5) + ;; CHECK: (func $start (type $7) ;; CHECK-NEXT: (call $configureAll ;; CHECK-NEXT: (array.new_elem $externs $externs ;; CHECK-NEXT: (i32.const 0) @@ -107,7 +105,7 @@ ;; CHECK-NEXT: (ref.null noextern) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPEN_WORLD: (func $start (type $5) + ;; OPEN_WORLD: (func $start (type $7) ;; OPEN_WORLD-NEXT: (call $configureAll ;; OPEN_WORLD-NEXT: (array.new_elem $externs $externs ;; OPEN_WORLD-NEXT: (i32.const 0) @@ -136,10 +134,10 @@ ) ) - ;; CHECK: (func $foo (type $7) (result i32) + ;; CHECK: (func $foo (type $6) (result i32) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) - ;; OPEN_WORLD: (func $foo (type $7) (result i32) + ;; OPEN_WORLD: (func $foo (type $6) (result i32) ;; OPEN_WORLD-NEXT: (i32.const 42) ;; OPEN_WORLD-NEXT: ) (func $foo (result i32) @@ -147,10 +145,10 @@ (i32.const 42) ) - ;; CHECK: (func $bar (type $ret-any-1) (result anyref) + ;; CHECK: (func $bar (type $ret-any-1) (result (ref (exact $struct))) ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) - ;; OPEN_WORLD: (func $bar (type $ret-any-1) (result anyref) + ;; OPEN_WORLD: (func $bar (type $ret-any-1) (result (ref (exact $struct))) ;; OPEN_WORLD-NEXT: (struct.new_default $struct) ;; OPEN_WORLD-NEXT: ) (func $bar (type $ret-any-1) (result anyref) From 70a85916b149cf4966deae49f44565895ef040db Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 17 Nov 2025 13:32:16 -0800 Subject: [PATCH 2/8] start.almost --- test/lit/passes/signature-pruning-configureAll.wast | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/lit/passes/signature-pruning-configureAll.wast b/test/lit/passes/signature-pruning-configureAll.wast index 111bf625860..cc63e6267a4 100644 --- a/test/lit/passes/signature-pruning-configureAll.wast +++ b/test/lit/passes/signature-pruning-configureAll.wast @@ -1,10 +1,8 @@ ;; 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 --signature-pruning -all -S -o - | filecheck %s --check-prefix OPEN_WORLD ;; Test that configureAll is respected: referred functions are not pruned. -;; This is so even in closed world. (module ;; CHECK: (type $externs (array (mut externref))) @@ -153,7 +151,6 @@ ;; OPEN_WORLD-NEXT: ) (func $bar (type $any-1) (param $x anyref) ;; The param is unused, but will not be pruned due to configureAll. - (struct.new $struct) ) ;; CHECK: (func $unconfigured (type $ret-any-2) (result (ref (exact $struct))) @@ -164,6 +161,5 @@ ;; OPEN_WORLD-NEXT: ) (func $unconfigured (type $any-2) (param $x anyref) ;; This is not referred to by configureAll, and can be pruned. - (struct.new $struct) ) ) From 79c77a5ee161ce160cab9288eafb988a66094f4d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 17 Nov 2025 13:32:41 -0800 Subject: [PATCH 3/8] start.almost --- .../signature-pruning-configureAll.wast | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/test/lit/passes/signature-pruning-configureAll.wast b/test/lit/passes/signature-pruning-configureAll.wast index cc63e6267a4..24b18d4b8ad 100644 --- a/test/lit/passes/signature-pruning-configureAll.wast +++ b/test/lit/passes/signature-pruning-configureAll.wast @@ -6,15 +6,12 @@ (module ;; CHECK: (type $externs (array (mut externref))) - ;; OPEN_WORLD: (type $externs (array (mut externref))) (type $externs (array (mut externref))) ;; CHECK: (type $funcs (array (mut funcref))) - ;; OPEN_WORLD: (type $funcs (array (mut funcref))) (type $funcs (array (mut funcref))) ;; CHECK: (type $bytes (array (mut i8))) - ;; OPEN_WORLD: (type $bytes (array (mut i8))) (type $bytes (array (mut i8))) ;; CHECK: (rec @@ -29,18 +26,7 @@ ;; CHECK: (type $7 (func)) ;; CHECK: (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref))) - ;; OPEN_WORLD: (rec - ;; OPEN_WORLD-NEXT: (type $ret-any-2 (func (result (ref (exact $struct))))) - ;; OPEN_WORLD: (type $struct (struct)) - - ;; OPEN_WORLD: (type $ret-any-1 (func (result (ref (exact $struct))))) - - ;; OPEN_WORLD: (type $6 (func (result i32))) - - ;; OPEN_WORLD: (type $7 (func)) - - ;; OPEN_WORLD: (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))) (type $struct (struct)) @@ -60,21 +46,17 @@ ) ;; CHECK: (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll) (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref))) - ;; OPEN_WORLD: (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") ;; CHECK: (elem $externs externref (item (ref.null noextern))) - ;; OPEN_WORLD: (data $bytes "12345678") - ;; OPEN_WORLD: (elem $externs externref (item (ref.null noextern))) (elem $externs externref (ref.null extern) ) ;; CHECK: (elem $funcs func $foo $bar) - ;; OPEN_WORLD: (elem $funcs func $foo $bar) (elem $funcs funcref (ref.func $foo) (ref.func $bar) @@ -83,7 +65,6 @@ (data $bytes "12345678") ;; CHECK: (start $start) - ;; OPEN_WORLD: (start $start) (start $start) ;; CHECK: (func $start (type $7) @@ -103,23 +84,6 @@ ;; CHECK-NEXT: (ref.null noextern) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; OPEN_WORLD: (func $start (type $7) - ;; OPEN_WORLD-NEXT: (call $configureAll - ;; OPEN_WORLD-NEXT: (array.new_elem $externs $externs - ;; OPEN_WORLD-NEXT: (i32.const 0) - ;; OPEN_WORLD-NEXT: (i32.const 1) - ;; OPEN_WORLD-NEXT: ) - ;; OPEN_WORLD-NEXT: (array.new_elem $funcs $funcs - ;; OPEN_WORLD-NEXT: (i32.const 0) - ;; OPEN_WORLD-NEXT: (i32.const 2) - ;; OPEN_WORLD-NEXT: ) - ;; OPEN_WORLD-NEXT: (array.new_data $bytes $bytes - ;; OPEN_WORLD-NEXT: (i32.const 0) - ;; OPEN_WORLD-NEXT: (i32.const 8) - ;; OPEN_WORLD-NEXT: ) - ;; OPEN_WORLD-NEXT: (ref.null noextern) - ;; OPEN_WORLD-NEXT: ) - ;; OPEN_WORLD-NEXT: ) (func $start (call $configureAll (array.new_elem $externs $externs @@ -135,9 +99,6 @@ ;; CHECK: (func $foo (type $6) (result i32) ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) - ;; OPEN_WORLD: (func $foo (type $6) (result i32) - ;; OPEN_WORLD-NEXT: (i32.const 42) - ;; OPEN_WORLD-NEXT: ) (func $foo (result i32) ;; Nothing to do here anyhow, but do not error. (i32.const 42) @@ -146,9 +107,6 @@ ;; CHECK: (func $bar (type $ret-any-1) (result (ref (exact $struct))) ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) - ;; OPEN_WORLD: (func $bar (type $ret-any-1) (result (ref (exact $struct))) - ;; OPEN_WORLD-NEXT: (struct.new_default $struct) - ;; OPEN_WORLD-NEXT: ) (func $bar (type $any-1) (param $x anyref) ;; The param is unused, but will not be pruned due to configureAll. ) @@ -156,9 +114,6 @@ ;; CHECK: (func $unconfigured (type $ret-any-2) (result (ref (exact $struct))) ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) - ;; OPEN_WORLD: (func $unconfigured (type $ret-any-2) (result (ref (exact $struct))) - ;; OPEN_WORLD-NEXT: (struct.new_default $struct) - ;; OPEN_WORLD-NEXT: ) (func $unconfigured (type $any-2) (param $x anyref) ;; This is not referred to by configureAll, and can be pruned. ) From fe83ee0907e276ef88ca5bfbdbb95969c637cd29 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 17 Nov 2025 13:41:33 -0800 Subject: [PATCH 4/8] go --- src/ir/intrinsics.cpp | 20 ++++++++++++ src/ir/intrinsics.h | 2 ++ src/ir/module-utils.cpp | 1 - src/passes/SignaturePruning.cpp | 6 ++++ src/passes/SignatureRefining.cpp | 6 ++++ .../signature-pruning-configureAll.wast | 32 +++++++++---------- 6 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/ir/intrinsics.cpp b/src/ir/intrinsics.cpp index b485aa70a64..2ee68ec3e66 100644 --- a/src/ir/intrinsics.cpp +++ b/src/ir/intrinsics.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "ir/find_all.h" #include "ir/intrinsics.h" #include "wasm-builder.h" @@ -100,4 +101,23 @@ std::vector Intrinsics::getConfigureAllFunctions(Call* call) { return ret; } +std::vector Intrinsics::getConfigureAllFunctions() { + // ConfigureAll in a start function makes its functions callable. + if (wasm.start) { + auto* start = wasm.getFunction(wasm.start); + if (!start->imported()) { + FindAll calls(start->body); + if (calls.list.size() > 1) { + Fatal() << "Multiple configureAlls"; + } + for (auto* call : calls.list) { + if (intrinsics.isConfigureAll(call)) { + return getConfigureAllFunctions(call); + } + } + } + } + return {}; +} + } // namespace wasm diff --git a/src/ir/intrinsics.h b/src/ir/intrinsics.h index c06eb832677..43e080b806b 100644 --- a/src/ir/intrinsics.h +++ b/src/ir/intrinsics.h @@ -109,6 +109,8 @@ class Intrinsics { // // where the segment $seg is of size N. std::vector getConfigureAllFunctions(Call* call); + // As above, but looks through the module to find the configureAll. + std::vector getConfigureAllFunctions(); }; } // namespace wasm diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp index 32a8a079dce..5abbbecc01d 100644 --- a/src/ir/module-utils.cpp +++ b/src/ir/module-utils.cpp @@ -15,7 +15,6 @@ */ #include "module-utils.h" -#include "ir/find_all.h" #include "ir/intrinsics.h" #include "ir/manipulation.h" #include "ir/metadata.h" diff --git a/src/passes/SignaturePruning.cpp b/src/passes/SignaturePruning.cpp index 2330720b622..c6e4a21f514 100644 --- a/src/passes/SignaturePruning.cpp +++ b/src/passes/SignaturePruning.cpp @@ -176,6 +176,12 @@ struct SignaturePruning : public Pass { allInfo[tag->type].optimizable = false; } + // configureAll functions are signature-called, and must also not be + // modified. + for (auto func : Intrinsics(*module).getConfigureAllFunctions()) { + allInfo[module->getFunction(func)->type.getHeapType].optimizable = false; + } + // A type must have the same number of parameters and results as its // supertypes and subtypes, so we only attempt to modify types without // supertypes or subtypes. diff --git a/src/passes/SignatureRefining.cpp b/src/passes/SignatureRefining.cpp index b3884fa7046..e1c79ea49a8 100644 --- a/src/passes/SignatureRefining.cpp +++ b/src/passes/SignatureRefining.cpp @@ -154,6 +154,12 @@ struct SignatureRefining : public Pass { } } + // configureAll functions are signature-called, and must also not be + // modified. + for (auto func : Intrinsics(*module).getConfigureAllFunctions()) { + allInfo[module->getFunction(func)->type.getHeapType].canModify = false; + } + // Also skip modifying types used in tags, even private tags, since we don't // analyze exception handling or stack switching instructions. TODO: Analyze // and optimize exception handling and stack switching instructions. diff --git a/test/lit/passes/signature-pruning-configureAll.wast b/test/lit/passes/signature-pruning-configureAll.wast index 24b18d4b8ad..b4e2c51a587 100644 --- a/test/lit/passes/signature-pruning-configureAll.wast +++ b/test/lit/passes/signature-pruning-configureAll.wast @@ -14,24 +14,17 @@ ;; CHECK: (type $bytes (array (mut i8))) (type $bytes (array (mut i8))) - ;; CHECK: (rec - ;; CHECK-NEXT: (type $ret-any-2 (func (result (ref (exact $struct))))) - - ;; CHECK: (type $struct (struct)) - - ;; CHECK: (type $ret-any-1 (func (result (ref (exact $struct))))) - - ;; CHECK: (type $6 (func (result i32))) - - ;; CHECK: (type $7 (func)) ;; 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))) (type $struct (struct)) (rec + ;; CHECK: (rec + ;; CHECK-NEXT: (type $any-2 (func)) + + ;; CHECK: (type $any-1 (func)) (type $any-1 (func (param anyref))) ;; use brands to allow $any-1/2 to be optimized separately. @@ -45,13 +38,17 @@ (type $brand3 (struct)) ) + ;; CHECK: (type $6 (func (result i32))) + + ;; CHECK: (type $7 (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") ;; CHECK: (elem $externs externref (item (ref.null noextern))) - (elem $externs externref (ref.null extern) ) @@ -104,15 +101,16 @@ (i32.const 42) ) - ;; CHECK: (func $bar (type $ret-any-1) (result (ref (exact $struct))) - ;; CHECK-NEXT: (struct.new_default $struct) + ;; CHECK: (func $bar (type $any-1) + ;; CHECK-NEXT: (local $0 anyref) ;; CHECK-NEXT: ) (func $bar (type $any-1) (param $x anyref) - ;; The param is unused, but will not be pruned due to configureAll. + ;; The param is unused, but will not be pruned (turned into a local) due to + ;; configureAll. ) - ;; CHECK: (func $unconfigured (type $ret-any-2) (result (ref (exact $struct))) - ;; CHECK-NEXT: (struct.new_default $struct) + ;; CHECK: (func $unconfigured (type $any-2) + ;; CHECK-NEXT: (local $0 anyref) ;; CHECK-NEXT: ) (func $unconfigured (type $any-2) (param $x anyref) ;; This is not referred to by configureAll, and can be pruned. From 52cdb68a929536ef7446b9bbb9f4bd2d91e04c0f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 17 Nov 2025 13:42:21 -0800 Subject: [PATCH 5/8] go --- src/ir/intrinsics.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ir/intrinsics.cpp b/src/ir/intrinsics.cpp index 2ee68ec3e66..80656f9e861 100644 --- a/src/ir/intrinsics.cpp +++ b/src/ir/intrinsics.cpp @@ -103,15 +103,15 @@ std::vector Intrinsics::getConfigureAllFunctions(Call* call) { std::vector Intrinsics::getConfigureAllFunctions() { // ConfigureAll in a start function makes its functions callable. - if (wasm.start) { - auto* start = wasm.getFunction(wasm.start); + if (module.start) { + auto* start = module.getFunction(module.start); if (!start->imported()) { FindAll calls(start->body); if (calls.list.size() > 1) { Fatal() << "Multiple configureAlls"; } for (auto* call : calls.list) { - if (intrinsics.isConfigureAll(call)) { + if (isConfigureAll(call)) { return getConfigureAllFunctions(call); } } From 377b6c7ebd2e622967b3831c95675cebda08f539 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 17 Nov 2025 13:48:53 -0800 Subject: [PATCH 6/8] work --- src/passes/SignaturePruning.cpp | 2 +- src/passes/SignatureRefining.cpp | 2 +- test/lit/passes/signature-pruning-configureAll.wast | 5 ++--- test/lit/passes/signature-refining-configureAll.wast | 8 ++++---- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/passes/SignaturePruning.cpp b/src/passes/SignaturePruning.cpp index c6e4a21f514..5b8eeafaa99 100644 --- a/src/passes/SignaturePruning.cpp +++ b/src/passes/SignaturePruning.cpp @@ -179,7 +179,7 @@ struct SignaturePruning : public Pass { // configureAll functions are signature-called, and must also not be // modified. for (auto func : Intrinsics(*module).getConfigureAllFunctions()) { - allInfo[module->getFunction(func)->type.getHeapType].optimizable = false; + allInfo[module->getFunction(func)->type.getHeapType()].optimizable = false; } // A type must have the same number of parameters and results as its diff --git a/src/passes/SignatureRefining.cpp b/src/passes/SignatureRefining.cpp index e1c79ea49a8..86c8cac8827 100644 --- a/src/passes/SignatureRefining.cpp +++ b/src/passes/SignatureRefining.cpp @@ -157,7 +157,7 @@ struct SignatureRefining : public Pass { // configureAll functions are signature-called, and must also not be // modified. for (auto func : Intrinsics(*module).getConfigureAllFunctions()) { - allInfo[module->getFunction(func)->type.getHeapType].canModify = false; + allInfo[module->getFunction(func)->type.getHeapType()].canModify = false; } // Also skip modifying types used in tags, even private tags, since we don't diff --git a/test/lit/passes/signature-pruning-configureAll.wast b/test/lit/passes/signature-pruning-configureAll.wast index b4e2c51a587..ceaadf25938 100644 --- a/test/lit/passes/signature-pruning-configureAll.wast +++ b/test/lit/passes/signature-pruning-configureAll.wast @@ -24,7 +24,7 @@ ;; CHECK: (rec ;; CHECK-NEXT: (type $any-2 (func)) - ;; CHECK: (type $any-1 (func)) + ;; CHECK: (type $any-1 (func (param anyref))) (type $any-1 (func (param anyref))) ;; use brands to allow $any-1/2 to be optimized separately. @@ -101,8 +101,7 @@ (i32.const 42) ) - ;; CHECK: (func $bar (type $any-1) - ;; CHECK-NEXT: (local $0 anyref) + ;; CHECK: (func $bar (type $any-1) (param $x anyref) ;; CHECK-NEXT: ) (func $bar (type $any-1) (param $x anyref) ;; The param is unused, but will not be pruned (turned into a local) due to diff --git a/test/lit/passes/signature-refining-configureAll.wast b/test/lit/passes/signature-refining-configureAll.wast index 9cb7f0c56ae..4a1b7f2612c 100644 --- a/test/lit/passes/signature-refining-configureAll.wast +++ b/test/lit/passes/signature-refining-configureAll.wast @@ -24,7 +24,7 @@ ;; CHECK: (type $struct (struct)) - ;; CHECK: (type $ret-any-1 (func (result (ref (exact $struct))))) + ;; CHECK: (type $ret-any-1 (func (result anyref))) ;; CHECK: (type $6 (func (result i32))) @@ -36,7 +36,7 @@ ;; OPEN_WORLD: (type $struct (struct)) - ;; OPEN_WORLD: (type $ret-any-1 (func (result (ref (exact $struct))))) + ;; OPEN_WORLD: (type $ret-any-1 (func (result anyref))) ;; OPEN_WORLD: (type $6 (func (result i32))) @@ -145,10 +145,10 @@ (i32.const 42) ) - ;; CHECK: (func $bar (type $ret-any-1) (result (ref (exact $struct))) + ;; CHECK: (func $bar (type $ret-any-1) (result anyref) ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) - ;; OPEN_WORLD: (func $bar (type $ret-any-1) (result (ref (exact $struct))) + ;; OPEN_WORLD: (func $bar (type $ret-any-1) (result anyref) ;; OPEN_WORLD-NEXT: (struct.new_default $struct) ;; OPEN_WORLD-NEXT: ) (func $bar (type $ret-any-1) (result anyref) From b32b648b711efd1c23dd0dbebf5b6e4e8ed063e7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 17 Nov 2025 13:50:00 -0800 Subject: [PATCH 7/8] format --- src/ir/intrinsics.cpp | 2 +- src/passes/SignaturePruning.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ir/intrinsics.cpp b/src/ir/intrinsics.cpp index 80656f9e861..9cff2493b7d 100644 --- a/src/ir/intrinsics.cpp +++ b/src/ir/intrinsics.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "ir/find_all.h" #include "ir/intrinsics.h" +#include "ir/find_all.h" #include "wasm-builder.h" namespace wasm { diff --git a/src/passes/SignaturePruning.cpp b/src/passes/SignaturePruning.cpp index 5b8eeafaa99..a867dffa255 100644 --- a/src/passes/SignaturePruning.cpp +++ b/src/passes/SignaturePruning.cpp @@ -179,7 +179,8 @@ struct SignaturePruning : public Pass { // configureAll functions are signature-called, and must also not be // modified. for (auto func : Intrinsics(*module).getConfigureAllFunctions()) { - allInfo[module->getFunction(func)->type.getHeapType()].optimizable = false; + allInfo[module->getFunction(func)->type.getHeapType()].optimizable = + false; } // A type must have the same number of parameters and results as its From 8c1d7ebbe75920b36189c7537ebc2fb871dccb4f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 17 Nov 2025 13:58:16 -0800 Subject: [PATCH 8/8] fix --- src/ir/intrinsics.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ir/intrinsics.cpp b/src/ir/intrinsics.cpp index 9cff2493b7d..b2a5e1ff11a 100644 --- a/src/ir/intrinsics.cpp +++ b/src/ir/intrinsics.cpp @@ -107,14 +107,20 @@ std::vector Intrinsics::getConfigureAllFunctions() { auto* start = module.getFunction(module.start); if (!start->imported()) { FindAll calls(start->body); - if (calls.list.size() > 1) { - Fatal() << "Multiple configureAlls"; - } + // Look for the (single) configureAll. + Call* configureAll = nullptr; for (auto* call : calls.list) { if (isConfigureAll(call)) { - return getConfigureAllFunctions(call); + if (configureAll) { + Fatal() << "Multiple configureAlls"; + } else { + configureAll = call; + } } } + if (configureAll) { + return getConfigureAllFunctions(configureAll); + } } } return {};