[wasm-split] Pre-create trampolines for global initializers#8542
[wasm-split] Pre-create trampolines for global initializers#8542aheejin wants to merge 1 commit intoWebAssembly:mainfrom
Conversation
Before WebAssembly#8443, we scanned `ref.func`s in global initizliers early in `indirectReferencesToSecondaryFunctions` and created trampolines for them and replaced `ref.func $func`s with `ref.func $trampoline_func` if `func` was set to move to a secondary module. But in case the global containing `ref.func $trampoline_func` also ends up moving to the same secondary module, creating trampoline and using it was not necessary, because the global can simply use `ref.func $func` because `func` is in the same secondary module. To fix this, in WebAssembly#8443, we postponed creating trampolines for `ref.func`s in global initializers until `shareImportableItems`. This had a problem, because we end up creating new trampolines late in `shareImportableItems`. But trampolines were designed to go through `indirectCallsToSecondaryFunctions` and `setupTablePatching`, so those late trampolines were invalid, like ```wast (func $trampoline_foo (call $foo) ) ``` when `foo` is in a secondary module. This was supposed to be converted to a `call_indirect` in `indirectCallsToSecondaryFunctions` and the table elements were supposed to set up in `setupTablePatching`. --- To fix the issue, this PR pre-creates trampolines for `ref.func`s in all global initializers in `indirectReferencesToSecondaryFunctions`, before `indirectCallsToSecondaryFunctions` and `setupTablePatching`, but doesn't make `ref.func`s reference them just yet. We make `ref.func`s in global initializers reference the trampolines only when it is decided they are not moving to the same secondary module, in `shareImportableItems`. But this can leave unused trampolines in the primary module. So in `cleanupUnusedTrampolines`, we remove unused trampolines. This increases acx_gallery code size only by 0.6%. If we didn't clean up the unnecessary trampolines, the increase was 3.6%. This only removes unused trampoline functions and not placeholder imports and elements yet, but they don't affect acx_gallery because it uses `--no-placeholders`. Fixes WebAssembly#8510. (Both tests fail for the same reason)
| @@ -0,0 +1,51 @@ | |||
| ;; RUN: wasm-split %s -all -g -o1 %t.1.wasm -o2 %t.2.wasm --keep-funcs=keep | |||
There was a problem hiding this comment.
This file was renamed from global-funcref.wast, and the expectations were rewritten. Previously I tried to put each line of expectation above the corresponding code line, but it's not easy when we have many other things like imports, exports, and trampolines.
| // Generate the call and the function. We generate a direct call here, but | ||
| // this will be converted to a call_indirect in | ||
| // indirectCallsToSecondaryFunctions. |
There was a problem hiding this comment.
Drive-by comment improvement. Not related to this PR
| ;; SECONDARY: (import "primary" "prime" (func $prime (exact (type $0)))) | ||
|
|
||
| ;; SECONDARY: (elem $0 (i32.const 0) $second-in-table $second) | ||
| ;; SECONDARY: (elem $0 (i32.const 0) $second $second-in-table) |
There was a problem hiding this comment.
This depends on the trampoline creating order. Not meaningful
| exportImportCalledPrimaryFunctions(); | ||
| setupTablePatching(); | ||
| shareImportableItems(); | ||
| cleanupUnusedTrampolines(); |
There was a problem hiding this comment.
It would be good to update the big comment at the top of the file to include this new step.
| // primary module, it means it was created for a global initializer but that | ||
| // global ended up moving to the same secondary module as the function | ||
| // referenced in the global initializer's ref.func. We can remove them here. | ||
| // TODO Remove placeholders and table elements created by unused trampolines |
There was a problem hiding this comment.
This fix conservatively creates extra trampolines, but then we have to clean them up afterwards. What would it look like to fix the bug by instead moving the globals to secondary modules earlier or being more precise about which globals need to use trampolines in their initializers? That way we wouldn't have to clean up afterwards.
Before #8443, we scanned
ref.funcs in global initizliers early inindirectReferencesToSecondaryFunctionsand created trampolines for them and replacedref.func $funcs withref.func $trampoline_funciffuncwas set to move to a secondary module. But in case the global containingref.func $trampoline_funcalso ends up moving to the same secondary module, creating trampoline and using it was not necessary, because the global can simply useref.func $funcbecausefuncis in the same secondary module.To fix this, in #8443, we postponed creating trampolines for
ref.funcs in global initializers untilshareImportableItems. This had a problem, because we end up creating new trampolines late inshareImportableItems. But trampolines were designed to go throughindirectCallsToSecondaryFunctionsandsetupTablePatching, so those late trampolines were invalid, likewhen
foowas in a secondary module. This was supposed to be converted to acall_indirectinindirectCallsToSecondaryFunctionsand the table elements were supposed to set up insetupTablePatching.To fix the issue, this PR pre-creates trampolines for
ref.funcs in all global initializers inindirectReferencesToSecondaryFunctions, beforeindirectCallsToSecondaryFunctionsandsetupTablePatching, but doesn't makeref.funcs reference them just yet. We makeref.funcs in global initializers reference the trampolines only when it is decided they are not moving to the same secondary module, inshareImportableItems.But this can leave unused trampolines in the primary module. So in
cleanupUnusedTrampolines, we remove unused trampolines.This increases acx_gallery code size only by 0.6%. If we didn't clean up the unnecessary trampolines, the increase was 3.6%. This only removes unused trampoline functions and not placeholder imports and elements yet, but they don't affect acx_gallery because it uses
--no-placeholders. The running time hasn't meaningfully changed.Fixes #8510. (Both tests fail for the same reason)