From e24f935f489a32439ab811cedf58bce2f73246ea Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 12 Nov 2025 14:54:25 -0800 Subject: [PATCH 1/3] [Custom Descriptors] Exact imports require CD Validate that exact function imports require custom descriptors. An alternative approach (that we may switch to in the future if necessary) would be to always allow exact imports, but then strip them out in the binary writer when custom descriptors are not enabled. For now take the more explicit what-you-see-is-what-you-get approach. --- src/wasm/wasm-validator.cpp | 7 ++++++- test/lit/validation/exact-import.wast | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 test/lit/validation/exact-import.wast diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 94d3b137699..0a1df50dbb9 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -4159,7 +4159,12 @@ void FunctionValidator::visitFunction(Function* curr) { curr->name, "all used types should be allowed"); - if (!curr->imported()) { + if (curr->imported()) { + shouldBeTrue( + curr->type.isInexact() || getModule()->features.hasCustomDescriptors(), + curr->name, + "exact imports require custom descriptors [--enable-custom-descriptors]"); + } else { shouldBeTrue( curr->type.isExact(), curr->name, "defined function should be exact"); } diff --git a/test/lit/validation/exact-import.wast b/test/lit/validation/exact-import.wast new file mode 100644 index 00000000000..318d397cfcb --- /dev/null +++ b/test/lit/validation/exact-import.wast @@ -0,0 +1,9 @@ +;; Test that exact imports require custom descriptors. + +;; RUN: not wasm-opt %s -all --disable-custom-descriptors 2>&1 | filecheck %s + +;; CHECK: exact imports require custom descriptors [--enable-custom-descriptors] + +(module + (import "" "" (func $f (exact))) +) From 2ac622d67bc879ff583c231fbc6d42e1b33e7f3d Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 12 Nov 2025 14:38:03 -0800 Subject: [PATCH 2/3] [Custom Descriptors] Use exact imports in wasm-split When custom descriptors are enabled, import primary functions into secondary modules using exact imports. This allows references to those functions in the secondary module to remain exact, just like they are before splitting. Remove the exact casts we previously inserted to fix this problem. Do not use exact imports when custom descriptors are not enabled. In principle this could cause validation errors because we allow e.g. exact locals even when custom descriptors are not enabled. This could be worked around in the future either by running a pass to remove exactness before splitting or by always using and allowing exact imports, but then emitting them as inexact imports when custom descriptors are disabled. --- src/ir/module-splitting.cpp | 37 +++------- src/ir/module-splitting.h | 6 +- test/lit/wasm-split/exact.wast | 6 +- .../wasm-split/multi-split-escape-names.wast | 36 ++++------ test/lit/wasm-split/multi-split.wast | 72 +++++++------------ test/lit/wasm-split/no-placeholders.wast | 2 +- test/lit/wasm-split/ref.func.wast | 6 +- test/lit/wasm-split/trampoline.wast | 2 +- 8 files changed, 55 insertions(+), 112 deletions(-) diff --git a/src/ir/module-splitting.cpp b/src/ir/module-splitting.cpp index ac88a2e6383..7438f8e695f 100644 --- a/src/ir/module-splitting.cpp +++ b/src/ir/module-splitting.cpp @@ -67,7 +67,13 @@ // 2. It assumes that either all table segment offsets are constants or there // is exactly one segment that may have a non-constant offset. It also // assumes that all segments are active segments. - +// +// 3. It assumes that if exact function references are required for validity +// (because they are stored in a local with an exact function type, for +// example), then custom descriptors are allowed so primary functions can +// be imported exactly. This could be worked around by removing exactness +// from the IR before splitting. +// #include "ir/module-splitting.h" #include "asmjs/shared-constants.h" #include "ir/export-utils.h" @@ -341,7 +347,6 @@ struct ModuleSplitter { void setupTablePatching(); void shareImportableItems(); void removeUnusedSecondaryElements(); - void updateIR(); ModuleSplitter(Module& primary, const Config& config) : config(config), primary(primary), tableManager(primary), @@ -358,7 +363,6 @@ struct ModuleSplitter { setupTablePatching(); shareImportableItems(); removeUnusedSecondaryElements(); - updateIR(); } }; @@ -520,7 +524,7 @@ void ModuleSplitter::exportImportFunction(Name funcName, func->hasExplicitName = primaryFunc->hasExplicitName; func->module = config.importNamespace; func->base = exportName; - func->type = func->type.with(Inexact); + func->type = func->type.withInexactIfNoCustomDescs(secondary->features); secondary->addFunction(std::move(func)); } } @@ -981,31 +985,6 @@ void ModuleSplitter::removeUnusedSecondaryElements() { } } -void ModuleSplitter::updateIR() { - // Imported functions may need type updates. - struct Fixer : public PostWalker { - void visitRefFunc(RefFunc* curr) { - auto& wasm = *getModule(); - auto* func = wasm.getFunction(curr->func); - if (func->type != curr->type) { - // This became an import, and lost exactness. - assert(!func->type.isExact()); - assert(curr->type.isExact()); - if (wasm.features.hasCustomDescriptors()) { - // Add a cast, as the parent may depend on the exactness to validate. - // TODO: The cast may be needed even without CD enabled - replaceCurrent(Builder(wasm).makeRefCast(curr, curr->type)); - } - curr->type = curr->type.with(Inexact); - } - } - } fixer; - fixer.walkModule(&primary); - for (auto& secondaryPtr : secondaries) { - fixer.walkModule(secondaryPtr.get()); - } -} - } // anonymous namespace Results splitFunctions(Module& primary, const Config& config) { diff --git a/src/ir/module-splitting.h b/src/ir/module-splitting.h index 8bf9a60ff7f..b7abda19aeb 100644 --- a/src/ir/module-splitting.h +++ b/src/ir/module-splitting.h @@ -26,7 +26,7 @@ // functions. The secondary module imports all of its dependencies from the // primary module. // -// This code currently makes a couple assumptions about the modules that will be +// This code currently makes a few assumptions about the modules that will be // split and will fail assertions if those assumptions are not true. // // 1) It assumes that mutable-globals are allowed. @@ -34,6 +34,10 @@ // 2) It assumes that either all segment offsets are constants or there is // exactly one segment that may have a non-constant offset. // +// 3) It assumes that exact function references are only required for validity +// if custom descriptors (and its exact function import feature) are +// allowed. +// // These requirements will be relaxed as necessary in the future, but for now // this code should be considered experimental and used with care. diff --git a/test/lit/wasm-split/exact.wast b/test/lit/wasm-split/exact.wast index 895b26e8eab..2275acec7d0 100644 --- a/test/lit/wasm-split/exact.wast +++ b/test/lit/wasm-split/exact.wast @@ -73,7 +73,7 @@ ;; SECONDARY: (import "primary" "table" (table $timport$0 1 funcref)) - ;; SECONDARY: (import "primary" "foo" (func $foo (type $0))) + ;; SECONDARY: (import "primary" "foo" (func $foo (exact (type $0)))) ;; SECONDARY: (elem $0 (i32.const 0) $bar) @@ -82,9 +82,7 @@ ;; SECONDARY: (func $bar (type $0) ;; SECONDARY-NEXT: (local $exact (ref (exact $0))) ;; SECONDARY-NEXT: (local.set $exact - ;; SECONDARY-NEXT: (ref.cast (ref (exact $0)) - ;; SECONDARY-NEXT: (ref.func $foo) - ;; SECONDARY-NEXT: ) + ;; SECONDARY-NEXT: (ref.func $foo) ;; SECONDARY-NEXT: ) ;; SECONDARY-NEXT: (local.set $exact ;; SECONDARY-NEXT: (ref.func $bar) diff --git a/test/lit/wasm-split/multi-split-escape-names.wast b/test/lit/wasm-split/multi-split-escape-names.wast index 4476f32e9a9..f3d5acbe2e9 100644 --- a/test/lit/wasm-split/multi-split-escape-names.wast +++ b/test/lit/wasm-split/multi-split-escape-names.wast @@ -24,9 +24,9 @@ ;; MOD1: (import "primary" "table" (table $timport$0 3 funcref)) - ;; MOD1: (import "primary" "trampoline_std::operator<<\\28std::__2::basic_ostream>&\\2c\\20wasm::Module&\\29" (func $trampoline_std::operator<<\28std::__2::basic_ostream>&\2c\20wasm::Module&\29 (result f32))) + ;; MOD1: (import "primary" "trampoline_std::operator<<\\28std::__2::basic_ostream>&\\2c\\20wasm::Module&\\29" (func $trampoline_std::operator<<\28std::__2::basic_ostream>&\2c\20wasm::Module&\29 (exact (result f32)))) - ;; MOD1: (import "primary" "trampoline_wasm::Literal::Literal\\28std::__2::array\\20const&\\29" (func $trampoline_wasm::Literal::Literal\28std::__2::array\20const&\29 (result i64))) + ;; MOD1: (import "primary" "trampoline_wasm::Literal::Literal\\28std::__2::array\\20const&\\29" (func $trampoline_wasm::Literal::Literal\28std::__2::array\20const&\29 (exact (result i64)))) ;; MOD1: (elem $0 (i32.const 2) $wasm::Type::getFeatures\28\29\20const) @@ -38,16 +38,12 @@ ;; MOD1-NEXT: ) ;; MOD1-NEXT: (drop ;; MOD1-NEXT: (call_ref $1 - ;; MOD1-NEXT: (ref.cast (ref (exact $1)) - ;; MOD1-NEXT: (ref.func $trampoline_wasm::Literal::Literal\28std::__2::array\20const&\29) - ;; MOD1-NEXT: ) + ;; MOD1-NEXT: (ref.func $trampoline_wasm::Literal::Literal\28std::__2::array\20const&\29) ;; MOD1-NEXT: ) ;; MOD1-NEXT: ) ;; MOD1-NEXT: (drop ;; MOD1-NEXT: (call_ref $0 - ;; MOD1-NEXT: (ref.cast (ref (exact $0)) - ;; MOD1-NEXT: (ref.func $trampoline_std::operator<<\28std::__2::basic_ostream>&\2c\20wasm::Module&\29) - ;; MOD1-NEXT: ) + ;; MOD1-NEXT: (ref.func $trampoline_std::operator<<\28std::__2::basic_ostream>&\2c\20wasm::Module&\29) ;; MOD1-NEXT: ) ;; MOD1-NEXT: ) ;; MOD1-NEXT: (i32.const 0) @@ -79,18 +75,16 @@ ;; MOD2: (import "primary" "table" (table $timport$0 3 funcref)) - ;; MOD2: (import "primary" "trampoline_std::operator<<\\28std::__2::basic_ostream>&\\2c\\20wasm::Module&\\29" (func $trampoline_std::operator<<\28std::__2::basic_ostream>&\2c\20wasm::Module&\29 (result f32))) + ;; MOD2: (import "primary" "trampoline_std::operator<<\\28std::__2::basic_ostream>&\\2c\\20wasm::Module&\\29" (func $trampoline_std::operator<<\28std::__2::basic_ostream>&\2c\20wasm::Module&\29 (exact (result f32)))) - ;; MOD2: (import "primary" "trampoline_wasm::Type::getFeatures\\28\\29\\20const" (func $trampoline_wasm::Type::getFeatures\28\29\20const (result i32))) + ;; MOD2: (import "primary" "trampoline_wasm::Type::getFeatures\\28\\29\\20const" (func $trampoline_wasm::Type::getFeatures\28\29\20const (exact (result i32)))) ;; MOD2: (elem $0 (i32.const 0) $wasm::Literal::Literal\28std::__2::array\20const&\29) ;; MOD2: (func $wasm::Literal::Literal\28std::__2::array\20const&\29 (result i64) ;; MOD2-NEXT: (drop ;; MOD2-NEXT: (call_ref $1 - ;; MOD2-NEXT: (ref.cast (ref (exact $1)) - ;; MOD2-NEXT: (ref.func $trampoline_wasm::Type::getFeatures\28\29\20const) - ;; MOD2-NEXT: ) + ;; MOD2-NEXT: (ref.func $trampoline_wasm::Type::getFeatures\28\29\20const) ;; MOD2-NEXT: ) ;; MOD2-NEXT: ) ;; MOD2-NEXT: (drop @@ -100,9 +94,7 @@ ;; MOD2-NEXT: ) ;; MOD2-NEXT: (drop ;; MOD2-NEXT: (call_ref $0 - ;; MOD2-NEXT: (ref.cast (ref (exact $0)) - ;; MOD2-NEXT: (ref.func $trampoline_std::operator<<\28std::__2::basic_ostream>&\2c\20wasm::Module&\29) - ;; MOD2-NEXT: ) + ;; MOD2-NEXT: (ref.func $trampoline_std::operator<<\28std::__2::basic_ostream>&\2c\20wasm::Module&\29) ;; MOD2-NEXT: ) ;; MOD2-NEXT: ) ;; MOD2-NEXT: (i64.const 0) @@ -134,25 +126,21 @@ ;; MOD3: (import "primary" "table" (table $timport$0 3 funcref)) - ;; MOD3: (import "primary" "trampoline_wasm::Literal::Literal\\28std::__2::array\\20const&\\29" (func $trampoline_wasm::Literal::Literal\28std::__2::array\20const&\29 (result i64))) + ;; MOD3: (import "primary" "trampoline_wasm::Literal::Literal\\28std::__2::array\\20const&\\29" (func $trampoline_wasm::Literal::Literal\28std::__2::array\20const&\29 (exact (result i64)))) - ;; MOD3: (import "primary" "trampoline_wasm::Type::getFeatures\\28\\29\\20const" (func $trampoline_wasm::Type::getFeatures\28\29\20const (result i32))) + ;; MOD3: (import "primary" "trampoline_wasm::Type::getFeatures\\28\\29\\20const" (func $trampoline_wasm::Type::getFeatures\28\29\20const (exact (result i32)))) ;; MOD3: (elem $0 (i32.const 1) $std::operator<<\28std::__2::basic_ostream>&\2c\20wasm::Module&\29) ;; MOD3: (func $std::operator<<\28std::__2::basic_ostream>&\2c\20wasm::Module&\29 (result f32) ;; MOD3-NEXT: (drop ;; MOD3-NEXT: (call_ref $1 - ;; MOD3-NEXT: (ref.cast (ref (exact $1)) - ;; MOD3-NEXT: (ref.func $trampoline_wasm::Type::getFeatures\28\29\20const) - ;; MOD3-NEXT: ) + ;; MOD3-NEXT: (ref.func $trampoline_wasm::Type::getFeatures\28\29\20const) ;; MOD3-NEXT: ) ;; MOD3-NEXT: ) ;; MOD3-NEXT: (drop ;; MOD3-NEXT: (call_ref $0 - ;; MOD3-NEXT: (ref.cast (ref (exact $0)) - ;; MOD3-NEXT: (ref.func $trampoline_wasm::Literal::Literal\28std::__2::array\20const&\29) - ;; MOD3-NEXT: ) + ;; MOD3-NEXT: (ref.func $trampoline_wasm::Literal::Literal\28std::__2::array\20const&\29) ;; MOD3-NEXT: ) ;; MOD3-NEXT: ) ;; MOD3-NEXT: (drop diff --git a/test/lit/wasm-split/multi-split.wast b/test/lit/wasm-split/multi-split.wast index a9c63f26490..70fbe70dd71 100644 --- a/test/lit/wasm-split/multi-split.wast +++ b/test/lit/wasm-split/multi-split.wast @@ -47,9 +47,9 @@ ;; MOD1: (import "primary" "table" (table $timport$0 3 funcref)) - ;; MOD1: (import "primary" "trampoline_B" (func $trampoline_B (result i64))) + ;; MOD1: (import "primary" "trampoline_B" (func $trampoline_B (exact (result i64)))) - ;; MOD1: (import "primary" "trampoline_C" (func $trampoline_C (result f32))) + ;; MOD1: (import "primary" "trampoline_C" (func $trampoline_C (exact (result f32)))) ;; MOD1: (elem $0 (i32.const 2) $A) @@ -61,16 +61,12 @@ ;; MOD1-NEXT: ) ;; MOD1-NEXT: (drop ;; MOD1-NEXT: (call_ref $0 - ;; MOD1-NEXT: (ref.cast (ref (exact $0)) - ;; MOD1-NEXT: (ref.func $trampoline_B) - ;; MOD1-NEXT: ) + ;; MOD1-NEXT: (ref.func $trampoline_B) ;; MOD1-NEXT: ) ;; MOD1-NEXT: ) ;; MOD1-NEXT: (drop ;; MOD1-NEXT: (call_ref $1 - ;; MOD1-NEXT: (ref.cast (ref (exact $1)) - ;; MOD1-NEXT: (ref.func $trampoline_C) - ;; MOD1-NEXT: ) + ;; MOD1-NEXT: (ref.func $trampoline_C) ;; MOD1-NEXT: ) ;; MOD1-NEXT: ) ;; MOD1-NEXT: (i32.const 0) @@ -83,9 +79,9 @@ ;; MOD1-OPTIONS: (import "custom_env" "%table" (table $timport$0 3 funcref)) - ;; MOD1-OPTIONS: (import "custom_env" "%trampoline_B" (func $trampoline_B (result i64))) + ;; MOD1-OPTIONS: (import "custom_env" "%trampoline_B" (func $trampoline_B (exact (result i64)))) - ;; MOD1-OPTIONS: (import "custom_env" "%trampoline_C" (func $trampoline_C (result f32))) + ;; MOD1-OPTIONS: (import "custom_env" "%trampoline_C" (func $trampoline_C (exact (result f32)))) ;; MOD1-OPTIONS: (elem $0 (i32.const 2) $A) @@ -97,16 +93,12 @@ ;; MOD1-OPTIONS-NEXT: ) ;; MOD1-OPTIONS-NEXT: (drop ;; MOD1-OPTIONS-NEXT: (call_ref $0 - ;; MOD1-OPTIONS-NEXT: (ref.cast (ref (exact $0)) - ;; MOD1-OPTIONS-NEXT: (ref.func $trampoline_B) - ;; MOD1-OPTIONS-NEXT: ) + ;; MOD1-OPTIONS-NEXT: (ref.func $trampoline_B) ;; MOD1-OPTIONS-NEXT: ) ;; MOD1-OPTIONS-NEXT: ) ;; MOD1-OPTIONS-NEXT: (drop ;; MOD1-OPTIONS-NEXT: (call_ref $1 - ;; MOD1-OPTIONS-NEXT: (ref.cast (ref (exact $1)) - ;; MOD1-OPTIONS-NEXT: (ref.func $trampoline_C) - ;; MOD1-OPTIONS-NEXT: ) + ;; MOD1-OPTIONS-NEXT: (ref.func $trampoline_C) ;; MOD1-OPTIONS-NEXT: ) ;; MOD1-OPTIONS-NEXT: ) ;; MOD1-OPTIONS-NEXT: (i32.const 0) @@ -138,18 +130,16 @@ ;; MOD2: (import "primary" "table" (table $timport$0 3 funcref)) - ;; MOD2: (import "primary" "trampoline_A" (func $trampoline_A (result i32))) + ;; MOD2: (import "primary" "trampoline_A" (func $trampoline_A (exact (result i32)))) - ;; MOD2: (import "primary" "trampoline_C" (func $trampoline_C (result f32))) + ;; MOD2: (import "primary" "trampoline_C" (func $trampoline_C (exact (result f32)))) ;; MOD2: (elem $0 (i32.const 0) $B) ;; MOD2: (func $B (result i64) ;; MOD2-NEXT: (drop ;; MOD2-NEXT: (call_ref $0 - ;; MOD2-NEXT: (ref.cast (ref (exact $0)) - ;; MOD2-NEXT: (ref.func $trampoline_A) - ;; MOD2-NEXT: ) + ;; MOD2-NEXT: (ref.func $trampoline_A) ;; MOD2-NEXT: ) ;; MOD2-NEXT: ) ;; MOD2-NEXT: (drop @@ -159,9 +149,7 @@ ;; MOD2-NEXT: ) ;; MOD2-NEXT: (drop ;; MOD2-NEXT: (call_ref $1 - ;; MOD2-NEXT: (ref.cast (ref (exact $1)) - ;; MOD2-NEXT: (ref.func $trampoline_C) - ;; MOD2-NEXT: ) + ;; MOD2-NEXT: (ref.func $trampoline_C) ;; MOD2-NEXT: ) ;; MOD2-NEXT: ) ;; MOD2-NEXT: (i64.const 0) @@ -174,18 +162,16 @@ ;; MOD2-OPTIONS: (import "custom_env" "%table" (table $timport$0 3 funcref)) - ;; MOD2-OPTIONS: (import "custom_env" "%trampoline_A" (func $trampoline_A (result i32))) + ;; MOD2-OPTIONS: (import "custom_env" "%trampoline_A" (func $trampoline_A (exact (result i32)))) - ;; MOD2-OPTIONS: (import "custom_env" "%trampoline_C" (func $trampoline_C (result f32))) + ;; MOD2-OPTIONS: (import "custom_env" "%trampoline_C" (func $trampoline_C (exact (result f32)))) ;; MOD2-OPTIONS: (elem $0 (i32.const 0) $B) ;; MOD2-OPTIONS: (func $B (result i64) ;; MOD2-OPTIONS-NEXT: (drop ;; MOD2-OPTIONS-NEXT: (call_ref $0 - ;; MOD2-OPTIONS-NEXT: (ref.cast (ref (exact $0)) - ;; MOD2-OPTIONS-NEXT: (ref.func $trampoline_A) - ;; MOD2-OPTIONS-NEXT: ) + ;; MOD2-OPTIONS-NEXT: (ref.func $trampoline_A) ;; MOD2-OPTIONS-NEXT: ) ;; MOD2-OPTIONS-NEXT: ) ;; MOD2-OPTIONS-NEXT: (drop @@ -195,9 +181,7 @@ ;; MOD2-OPTIONS-NEXT: ) ;; MOD2-OPTIONS-NEXT: (drop ;; MOD2-OPTIONS-NEXT: (call_ref $1 - ;; MOD2-OPTIONS-NEXT: (ref.cast (ref (exact $1)) - ;; MOD2-OPTIONS-NEXT: (ref.func $trampoline_C) - ;; MOD2-OPTIONS-NEXT: ) + ;; MOD2-OPTIONS-NEXT: (ref.func $trampoline_C) ;; MOD2-OPTIONS-NEXT: ) ;; MOD2-OPTIONS-NEXT: ) ;; MOD2-OPTIONS-NEXT: (i64.const 0) @@ -229,25 +213,21 @@ ;; MOD3: (import "primary" "table" (table $timport$0 3 funcref)) - ;; MOD3: (import "primary" "trampoline_A" (func $trampoline_A (result i32))) + ;; MOD3: (import "primary" "trampoline_A" (func $trampoline_A (exact (result i32)))) - ;; MOD3: (import "primary" "trampoline_B" (func $trampoline_B (result i64))) + ;; MOD3: (import "primary" "trampoline_B" (func $trampoline_B (exact (result i64)))) ;; MOD3: (elem $0 (i32.const 1) $C) ;; MOD3: (func $C (result f32) ;; MOD3-NEXT: (drop ;; MOD3-NEXT: (call_ref $0 - ;; MOD3-NEXT: (ref.cast (ref (exact $0)) - ;; MOD3-NEXT: (ref.func $trampoline_A) - ;; MOD3-NEXT: ) + ;; MOD3-NEXT: (ref.func $trampoline_A) ;; MOD3-NEXT: ) ;; MOD3-NEXT: ) ;; MOD3-NEXT: (drop ;; MOD3-NEXT: (call_ref $1 - ;; MOD3-NEXT: (ref.cast (ref (exact $1)) - ;; MOD3-NEXT: (ref.func $trampoline_B) - ;; MOD3-NEXT: ) + ;; MOD3-NEXT: (ref.func $trampoline_B) ;; MOD3-NEXT: ) ;; MOD3-NEXT: ) ;; MOD3-NEXT: (drop @@ -265,25 +245,21 @@ ;; MOD3-OPTIONS: (import "custom_env" "%table" (table $timport$0 3 funcref)) - ;; MOD3-OPTIONS: (import "custom_env" "%trampoline_A" (func $trampoline_A (result i32))) + ;; MOD3-OPTIONS: (import "custom_env" "%trampoline_A" (func $trampoline_A (exact (result i32)))) - ;; MOD3-OPTIONS: (import "custom_env" "%trampoline_B" (func $trampoline_B (result i64))) + ;; MOD3-OPTIONS: (import "custom_env" "%trampoline_B" (func $trampoline_B (exact (result i64)))) ;; MOD3-OPTIONS: (elem $0 (i32.const 1) $C) ;; MOD3-OPTIONS: (func $C (result f32) ;; MOD3-OPTIONS-NEXT: (drop ;; MOD3-OPTIONS-NEXT: (call_ref $0 - ;; MOD3-OPTIONS-NEXT: (ref.cast (ref (exact $0)) - ;; MOD3-OPTIONS-NEXT: (ref.func $trampoline_A) - ;; MOD3-OPTIONS-NEXT: ) + ;; MOD3-OPTIONS-NEXT: (ref.func $trampoline_A) ;; MOD3-OPTIONS-NEXT: ) ;; MOD3-OPTIONS-NEXT: ) ;; MOD3-OPTIONS-NEXT: (drop ;; MOD3-OPTIONS-NEXT: (call_ref $1 - ;; MOD3-OPTIONS-NEXT: (ref.cast (ref (exact $1)) - ;; MOD3-OPTIONS-NEXT: (ref.func $trampoline_B) - ;; MOD3-OPTIONS-NEXT: ) + ;; MOD3-OPTIONS-NEXT: (ref.func $trampoline_B) ;; MOD3-OPTIONS-NEXT: ) ;; MOD3-OPTIONS-NEXT: ) ;; MOD3-OPTIONS-NEXT: (drop diff --git a/test/lit/wasm-split/no-placeholders.wast b/test/lit/wasm-split/no-placeholders.wast index d3f8fd67652..79d7592c977 100644 --- a/test/lit/wasm-split/no-placeholders.wast +++ b/test/lit/wasm-split/no-placeholders.wast @@ -31,7 +31,7 @@ ;; SECONDARY: (import "primary" "table" (table $timport$0 2 funcref)) - ;; SECONDARY: (import "primary" "foo" (func $foo)) + ;; SECONDARY: (import "primary" "foo" (func $foo (exact))) ;; SECONDARY: (elem $0 (i32.const 0) $bar $baz) diff --git a/test/lit/wasm-split/ref.func.wast b/test/lit/wasm-split/ref.func.wast index 306d8b64fe3..561a63f03e9 100644 --- a/test/lit/wasm-split/ref.func.wast +++ b/test/lit/wasm-split/ref.func.wast @@ -65,7 +65,7 @@ ;; SECONDARY: (import "primary" "table_2" (table $timport$0 2 funcref)) - ;; SECONDARY: (import "primary" "prime" (func $prime (type $0))) + ;; SECONDARY: (import "primary" "prime" (func $prime (exact (type $0)))) ;; SECONDARY: (elem $0 (i32.const 0) $second $second-in-table) @@ -73,9 +73,7 @@ ;; SECONDARY: (func $second (type $0) ;; SECONDARY-NEXT: (drop - ;; SECONDARY-NEXT: (ref.cast (ref (exact $0)) - ;; SECONDARY-NEXT: (ref.func $prime) - ;; SECONDARY-NEXT: ) + ;; SECONDARY-NEXT: (ref.func $prime) ;; SECONDARY-NEXT: ) ;; SECONDARY-NEXT: (drop ;; SECONDARY-NEXT: (ref.func $second) diff --git a/test/lit/wasm-split/trampoline.wast b/test/lit/wasm-split/trampoline.wast index 20711206afc..2ba2a61b28a 100644 --- a/test/lit/wasm-split/trampoline.wast +++ b/test/lit/wasm-split/trampoline.wast @@ -39,7 +39,7 @@ ;; SECONDARY: (import "primary" "table_3" (table $timport$0 1 funcref)) - ;; SECONDARY: (import "primary" "foo" (func $foo (param i32) (result i32))) + ;; SECONDARY: (import "primary" "foo" (func $foo (exact (param i32) (result i32)))) ;; SECONDARY: (elem $0 (i32.const 0) $bar) From ab06811a6e13dd041ecc8af9afd62e46c294d58b Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Fri, 14 Nov 2025 09:25:48 -0800 Subject: [PATCH 3/3] update tests --- test/example/module-splitting.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/example/module-splitting.txt b/test/example/module-splitting.txt index b312636bf10..0db22c7855c 100644 --- a/test/example/module-splitting.txt +++ b/test/example/module-splitting.txt @@ -745,7 +745,7 @@ Secondary: (module (type $0 (func)) (import "primary" "%table" (table $0 1 funcref)) - (import "primary" "%foo_1" (func $foo (type $0))) + (import "primary" "%foo_1" (func $foo (exact (type $0)))) (elem $0 (i32.const 0) $bar) (func $bar (type $0) (call $foo) @@ -1055,7 +1055,7 @@ Secondary: (module (type $0 (func)) (import "primary" "%table_2" (table $0 1 funcref)) - (import "primary" "%foo" (func $foo (type $0))) + (import "primary" "%foo" (func $foo (exact (type $0)))) (elem $0 (i32.const 0) $bar) (func $bar (type $0) (call $foo) @@ -1102,7 +1102,7 @@ Secondary: (module (type $0 (func (param i32) (result i32))) (import "primary" "%table_2" (table $0 1 funcref)) - (import "primary" "%foo" (func $foo (type $0) (param i32) (result i32))) + (import "primary" "%foo" (func $foo (exact (type $0) (param i32) (result i32)))) (elem $0 (i32.const 0) $bar) (func $bar (type $0) (param $0 i32) (result i32) (call $foo