Skip to content

Conversation

@kripken
Copy link
Member

@kripken kripken commented Oct 24, 2025

Defined functions remain exact, but imported ones are inexact.

This is a step along the recent Custom Descriptors spec changes.

  • New RefFunc::finalize and Literal::makeFunc variants get the module, and look up
    the type there.
  • New Builder::makeRefFunc variant gets a Type and applies it. The HeapType
    variant does a lookup on the module (so the Type one is more efficient/applicable
    if the IR is not fully built yet).
  • ReFinalize now updates RefFunc types (following the pattern of a few other places).
  • C and JS APIs now assume RefFuncs are created after imported functions (so we can
    look up the type of the import; see changelog, this seems the least-annoying way to
    update here, avoiding new APIs, and less breakage for users - hopefully none, all our
    tests here pass as is).
  • wasm-split adds a cast when a function becomes an inexact import.
  • Fix GUFA to handle inexact function literals.
  • Update types in passes and fuzzer as needed.

tlively and others added 30 commits October 8, 2025 13:44
Update the Literal constructors for funcrefs to take Type instead of
HeapType to allow them to be given inexact function references types
when the referenced function is an import. Use the new capability to
give references to imported functions inexact types in GUFA. Add a test
where this change fixes a misoptimization as well as tests where this
change simply changes the nature of the misoptimization. Future PRs will
fix these tests.
kripken added a commit that referenced this pull request Nov 6, 2025
The meaning of Global in PossibleContents changes from "an actual wasm
Global" to "an immutable global wasm thing, either a Global or a Function."
Imported wasm Functions are effectively immutable values in the global
scope - not concrete, specifically-known functions - so this is more correct.

In particular, two imported Globals (of compatible types) might or might not
be the same, and likewise with imported Functions. And that is not the case
for defined Functions - they are definitely different.

This does not fix the issues related to imported function type handling -
#7993 does that - but this refactoring makes it possible to properly
optimize imported functions afterward.

This does make the PossibleContents object grow from 32 to 40 bytes,
which might be why this adds 3-4% overhead to GUFA, but I don't see a
good way to avoid that, unfortunately. Keeping our ability to optimize
imported functions might be worth that 3-4% (we recently saw a few digits
improvement due to properly optimizing imported externs, for example,
from #8005).
@tlively
Copy link
Member

tlively commented Nov 6, 2025

Adding validation that defined (i.e. non-imported) functions must have exact types exposes a bug in the JSPI pass.

@kripken
Copy link
Member Author

kripken commented Nov 6, 2025

After merging main, which includes the GUFA change for imported functions, a fix was required here in GUFA.cpp:

https://github.com/WebAssembly/binaryen/pull/7993/files#diff-45bc50500f96fb0a98cf7229b7ccbe2c1a627b195a6bb2f317d979fb0cee6286

We used to only have globals as an exception there, and now must have functions as well (for imported ones). This becomes an issue in this PR as exactness changes make it noticeable, and this affected a new test here.

@kripken
Copy link
Member Author

kripken commented Nov 6, 2025

@tlively

Adding validation that defined (i.e. non-imported) functions must have exact types exposes a bug in the JSPI pass.

Where can I see that?

@tlively
Copy link
Member

tlively commented Nov 6, 2025

I found that when I started working on a new PR using this one as the base. Here's the diff to apply:

diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index b7487a9d1..f93da3aaf 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -4175,6 +4175,9 @@ void FunctionValidator::visitFunction(Function* curr) {
   }

   if (curr->body) {
+    shouldBeTrue(curr->type.isExact(),
+                 curr->name,
+                 "defined function should have exact type");
     if (curr->getResults().isTuple()) {
       shouldBeTrue(getModule()->features.hasMultivalue(),
                    curr->body,

@tlively
Copy link
Member

tlively commented Nov 6, 2025

Basically we should move the exactness type checking from visitRefFunc to visitFunction.

@kripken
Copy link
Member Author

kripken commented Nov 6, 2025

Done.

Copy link
Member

@tlively tlively left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM once CI and fuzzers are happy

@kripken
Copy link
Member Author

kripken commented Nov 6, 2025

good catch @tlively on that missing validation 😄 that caused a lot of things to be missed earlier...

@kripken kripken merged commit 0edd3cf into WebAssembly:main Nov 6, 2025
16 checks passed
@kripken kripken deleted the import.func.type branch November 6, 2025 23:50
HerrCai0907 added a commit to wasm-ecosystem/warpo that referenced this pull request Nov 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants