-
Notifications
You must be signed in to change notification settings - Fork 828
Avoid fp$ access in MAIN_MODULES #2704
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
Conversation
|
I wonder if there is some way we could do this wasm-ld directly? |
|
Should we do that same for gotMemEntries for consistency? |
Good question, yeah, please see this PR as a proof-of-concept: it shows that if the Table entries are unique then we can just avoid the But it would mean that
That's not as easy, as this depends on the dynamic loader scanning the Table to avoid duplication. There isn't such a thing for memory entries. We could avoid |
|
We already exports that address of all non-local symbols, but we export the addresses relative to __memory_base. I think the following algorithm would work: That way the |
I was under the impression that |
|
@sbc100 oh, if we export the relative global addresses already, then we can use that in the loader for globals, yes. It would require some work on the JS side too, but seems possible. (How important is that, btw?) @awtcode I'm not sure if wasm-ld creates a unique Table or not by itself, but that does seem likely. But regardless what this approach would change is that a module would place its own items in the Table, and assume that the loader knows how to reuse those indices properly. That's a new contract between wasm-ld and the loader, compared to before: instead of the loader doing everything, wasm-ld is emitting code that needs to work with the loader. |
I'm not sure I understand. What extra would would it require any work on the JS side? The JS already has to implement There is no need to make it part of this PR I guess, but I do think I think it should be doable, and without any JS-side changes.
|
|
Oh, I see, the JS is already doing that? (I just read the function pointer code for this, not the globals code.) Sounds good then, yeah, should be just to internalize in binaryen as an optimization basically. Yeah, let's keep that a separate PR. |
| } | ||
| } | ||
| }; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should FlatTable go in this new namespace too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I think it's excessive to add it - it's name already implies what type of thing it does. But I don't feel strongly. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just seems odd to have a TableUtils that is declared in table-utils.h but not all the stuff in that header ends up in the namespace. No need to hold up this PR on that though. I don't feel super strongly about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, if it seems odd to you, I'll change that.
src/wasm/wasm-emscripten.cpp
Outdated
| wasm.addFunction(post_instantiate); | ||
|
|
||
| if (Function* F = generateAssignGOTEntriesFunction()) { | ||
| if (Function* F = generateAssignGOTEntriesFunction(true /*isSideModule*/)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The chromium/llvm style for this is /*isSideModule=*/true (with no spaces I think). Not sure if this is a common pattern in binaryen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking around, it seems like we mostly use bools with .setX() functions. I'll adapt to that.
| ExpressionManipulator::copy(wasm.table.segments[0].offset, wasm); | ||
| auto* add = builder.makeBinary(AddInt32, getBase, c); | ||
| auto* globalSet = builder.makeGlobalSet(g->name, add); | ||
| block->list.push_back(globalSet); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we may have forgotten to take into account __table_base here, and also the tablesize in the dylink section?
If we create the table during this pass we will most likely also need to create __table_base which would otherwise have been created by lld.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the ::copy operation: we are copying the base of the segment, and adding that. The tests show we handle the case of __table_base as well as if it's a constant.
If we create the table here, then we create it with a constant offset. I think that won't happen in dynamic linking since we will always import the table there, though?
About dylink, yeah, thinking on that now, it seems like we need to update it if it exists. Looks like we have no handling of that at all in binaryen yet.
What do you think about doing this in binaryen vs wasm-ld? After your comments here it is starting to seem to me like wasm-ld might be simpler (but I don't know the code there).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about it and I think doing in lld would require more re-design. I'm OK with landing this change first/now, while I look at perhaps trying do this in wasm-ld.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to do it here.
Meanwhile I looked into the dylink section issue. It would require first adding full parsing and writing support for that section, and for updating it through operations, so basically adding IR support for it. If we want that we should do it separately from this PR I think. And that doesn't need to block this PR as this one only works on main modules where there is no dylink section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The MAIN_MODULE does have a dylink section. We should probably fix binaryen to preserve that section by I agree that is a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh interesting, that's a difference in upstream compared to fastcomp that I didn't realize.
Emscripten never uses it in a main module, though, I verified.
| } | ||
| } | ||
| }; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just seems odd to have a TableUtils that is declared in table-utils.h but not all the stuff in that header ends up in the namespace. No need to hold up this PR on that though. I don't feel super strongly about it.
src/wasm/wasm-emscripten.cpp
Outdated
| // We may be able to do something for side modules as well, however, | ||
| // that would require at least updating the dylink section. | ||
| if (f->imported()) { | ||
| Fatal() << "GOT.func entry export but not implemented: " << g->base; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error could be better maybe? if you hit this does it mean that GOT.func.foo is both imported and exported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's equivalent. I'll rephrase the error that way.
WebAssembly/binaryen#2704 will require some minor updates to the main module test, as we will be optimizing out some fp$ things.
Depends on emscripten-core/emscripten#10741
which ensures that table indexes are unique. With that guarantee,
a main module can just add its function pointers into the table, and
use them based on that index. The loader will then see them in the
table and then give other modules the identical function pointer for
a function, ensuring function pointer equality.
This avoids calling
fp$functions during startup for the mainmodule's own functions (which are slow). We do still call
fp$sof things we import from outside, as we don't have anything to
put in the table for them, we depend on the loader for that.
I suspect this can also be done with SIDE_MODULES, but did not
want to try too much at once.