Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm-split: Handle RefFuncs #6513

Merged
merged 15 commits into from
May 8, 2024
Merged

Conversation

kripken
Copy link
Member

@kripken kripken commented Apr 18, 2024

One of the first issues I see when fuzzing wasm-split. This one looked easy to fix (famous
last words?) so I wrote up a quick patch.

When we have a ref.func, if it refers to a function in the other module then make it
refer to a trampoline in this function instead. The trampoline does a direct call to the
target, and the normal wasm-split fixups handle getting that to work.

@kripken kripken requested a review from tlively April 18, 2024 22:46
src/ir/module-splitting.cpp Outdated Show resolved Hide resolved
Comment on lines 359 to 365
// Collect RefFuncs in a map from the function name to all RefFuncs that
// refer to it. We have one such map for the primary and secondary modules
// (that is, the primary map contains RefFuncs that are present in the
// primary module, and that refer to the secondary module, hence they are in
// need of fixing).
using Map = InsertOrderedMap<Name, std::vector<RefFunc*>>;
Map primaryMap, secondaryMap;
Copy link
Member

Choose a reason for hiding this comment

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

It would be best to handle secondary function references in the primary module and primary function references in the secondary module separately.

For primary-to-secondary references, these thunks are the best strategy, but for secondary-to-primary references, we almost don't need to do anything since the primary functions are imported into the secondary module and can be referred to directly. For the latter case, all you need to do is replace the TODO that was down in exportImportCalledPrimaryFunctions to collect referred-to primary functions as well.

For the former case, where we still need these thunks, it would be simpler to run this pass only on the primary module after moveSecondaryFunctions is called so you can assume that the parent function will always be a primary function.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, done.

Comment on lines +92 to +94
;; This empty function is in the table. Just being present in the table is not
;; enough of a reason for us to make a trampoline, even though in our IR the
;; table is a list of ref.funcs.
Copy link
Member

Choose a reason for hiding this comment

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

How does the code differentiate RefFuncs in a table from other RefFuncs?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, this was a part I meant to write Friday evening and somehow forgot 😄 Added now + testing.

Comment on lines 557 to 558
// Find all RefFuncs in elems, which we can ignore: tables are the means by
// which we connect the modules, and are handled directly.
Copy link
Member

Choose a reason for hiding this comment

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

Does this still work if the reference is in a passive element segment or an active element segment for a table other than the "active table" to which we are adding items?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, that shows my ignorance of wasm-split. Are all those not handled the same? I was assuming they are all kept in the primary module and that logic already existed to handle accessing them from secondary modules - is that not so?

Copy link
Member

Choose a reason for hiding this comment

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

Taking a closer look at the code, it appears that we apply the same transformation to all active segments. There is a concerning TODO on line 149 ("TODO: Reject or handle passive element segments") that suggests we have pre-existing problems with passive segments.

I think we need to apply your thunk strategy to all secondary function references that appear in passive element segments.

Copy link
Member Author

Choose a reason for hiding this comment

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

I see, yeah, looks like passive segments are not already handled. And yeah, it looks like we can handle them using this PR so I guess it makes sense to fix both here. I added that now.

The TODO on line 149 looks separate to me though? I suspect that is related to #6572

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.

Great, thanks!


(global $glob2 (ref func) (ref.func $second))

(elem (i32.const 0) $in-table $second-in-table)
Copy link
Member

Choose a reason for hiding this comment

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

If you give this a name, its output line will be attached above it.

@kripken kripken merged commit ed2cec4 into WebAssembly:main May 8, 2024
13 checks passed
@kripken kripken deleted the split.ref.func branch May 8, 2024 17:07
@gkdn gkdn mentioned this pull request Aug 31, 2024
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