-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
Way to ask emcc to pre-reserve a bunch of slots in the function table? #20097
Comments
The llvm linker (wasm-ld) doesn't currently have any way to over-allocate the table and I'm not sure it would make sense to add one. Another approach would be to add an Lines 1997 to 2007 in ef3e4e3
We already have code for creating the table on the JS side but its currently only enabled for dynamic linking: emscripten/src/runtime_init_table.js Lines 1 to 15 in ef3e4e3
If we added |
Also, when you say "Table.grow" is slow.. is that only when its called in increments of 1? Presumably you could also just do |
Being able to basically add a constant offset to INITIAL_TABLE would do it for the grow side on my end, I think. We originally used Module.addFunction, but for thread safety we pivoted to a single big Table.grow operation at startup like you suggest. On my dev machine the call to grow takes 10-15msec. Then the process of doing a (We're reserving around 100k slots because we have a bunch of different function pointer types we need to reserve space for) |
I had another idea. We have a setting called In both cases that allows the application that then use the first N addresses for their own purpose. Would this work for you? In both cases the region, of course, can't be grown as the compiler will place its own static data at N. So you would then link with |
I think that would work great, and then I don't need to try and predict where the reserved slots are, they're always at 0. That seems like it would have serious negative code size impacts though, because now all function pointer i32.consts are 100k larger? |
Yeah, it might at one or two extra bytes to each of your |
Yeah if it won't affect vtables (since they live in the data segment, as you point out), it's probably fine. The alternative I was considering was to patch the .wasm file myself and add extra entries to the function table in the module at the end, instead of at the beginning. But if emcc can reserve the space for me at a known location, that's really good, and I can always improve on it later by patching those empty slots with the specific values I want. |
I just realized I should point out, however, that in some of our test cases our function pointer table already contains 100k+ entries (AOT compilation), so it's actually quite possible that the address of functions is taken a lot... I'm not sure how easily I could verify that or not. Reserving the slots at the end would avoid a negative impact on compiled size, I think? |
Yes that was going to be my next suggestion.. just to write a custom post-link pass (perhaps a binaryen pass) to do what you want |
In that case though, the majority of your function pointers already require encoding using 3 bytes, right? Only the first 2^14 (16384) can be encoded in 2 bytes.. so you are already paying the price of 3-byte LEB encoding in most cases. |
This is the first part of the change: https://reviews.llvm.org/D158892. Once that lands we can look at adding |
Another thing that occurred to me while reading through the spec: If I could access the |
You should be able to do that with inline assembly yes. Here is an example, albeit using a separate assembly file: There is also the Given that, |
-sTABLE_BASE would still allow pre-reserving the space, which is useful for improved startup time I think. __builtin_wasm_table_fill is the ticket for the rest of it if I can manage to integrate it, I suspect! Will let you know if I manage to get a prototype working. |
This is similar to `--global-base` but determines where to place the table segments rather than that data segments. See emscripten-core/emscripten#20097 Differential Revision: https://reviews.llvm.org/D158892
I'm guessing I would want to do something like: extern __funcref_t __indirect_function_table[0]; to be able to reach emscripten's indirect function table from my code, right? and then manipulate it like: // grab an existing function I know exists, using a function pointer I already have
__funcref_t specific_function = __builtin_wasm_table_get_funcref(__indirect_function_table, some_fn_ptr);
// now fill a bunch of table slots with that function
__builtin_wasm_table_fill(__indirect_function_table, idx, specific_function, count); Am I on the right track? It's very hard to find any documentation for any of this :-) Do I use externref here even though it's a function table? |
I'm not sure anyone has tried to do what you are trying to do here.. so I'm not surprised its not documented. You can try to get it working at the C level, but if it doesn't work you can also try just dropping down the assembly level (at the assembly level I find this kind of thing more easy to grok for some reason). |
Starting with emscripten-3.1.46, this flag to LLVM is needed. This is a backport of https://github.com/llvm/llvm-project/commit/93adcb770b99351b18553089c164fe3ef2119699.patch, with additional review at https://reviews.llvm.org/D158892 and emscripten-core/emscripten#20097.
Starting with emscripten-3.1.46, this flag to LLVM is needed. This is a backport of https://github.com/llvm/llvm-project/commit/93adcb770b99351b18553089c164fe3ef2119699.patch, with additional review at https://reviews.llvm.org/D158892 and emscripten-core/emscripten#20097.
Sorry if this already exists, I grepped the docs + source + issues and couldn't find anything.
At application startup I'm growing the function table and then filling it with a bunch of safe placeholder functions so that I can swap new ones in dynamically at runtime (pre-allocating it like this is necessary for thread safety). The grow operation and Table.set are both very expensive in v8, though, so it would be cool if there was some way to ask emcc to reserve a set number of slots for me (so I can count on them being there and being usable). If I could also specify what to populate them with that would be even better. Would emcc be able to do either of these things via a switch or other some sort of configuration?
The text was updated successfully, but these errors were encountered: