-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Part two of dynCall removal #12059
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
Part two of dynCall removal #12059
Conversation
"a.wasm.gz": 6935, | ||
"total": 16029, | ||
"total_gz": 9552 | ||
"a.js": 4651, |
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.
what causes the increase here?
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 this is the JS side code in dynCall
and makeDynCaller
. The wasm gets smaller in proportion to the number of signatures and the JS grows by a fixed amount I think.
In summary:
- Small JS size increase.
- Only paid by programs that use dynCalls.
- Should be removable once we can switch 100% to table calls.
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.
-1 for this change: the old code is both smaller and more performance, as it avoids dynamic signature binding. I think we should switch to this only after we have step 3. from above in-place in this same PR. That way we will not have to accept a regression on a promise of things improving back to old form later on.
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.
OK that makes sense. I'll keep going with this until its all done rather then try to land this incremental change.
src/library_async.js
Outdated
@@ -340,6 +340,7 @@ mergeInto(LibraryManager.library, { | |||
}); | |||
}, | |||
|
|||
emscripten_scan_registers__deps: ['$getDynCaller'], |
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.
Why is this dep added? I don't see the function used in the body. I'd guess it's expanded from {{{ makeDynCall }}}
? It seems confusing to not see the function in the dep actually used, and could make us forget deps later on. Could the one in the body be changed?
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, any function with a makeDynCall
need to depend on getDynCaller
for now.
getDynCaller
then selects between the legacy native thunks and the direct table access. Once we can remove the legacy thunks completely we can look at making this more efficient.
src/library_html5.js
Outdated
@@ -2656,6 +2656,7 @@ var LibraryJSEvents = { | |||
cancelAnimationFrame(id); | |||
}, | |||
|
|||
emscripten_request_animation_frame_loop__deps: ['$getDynCaller'], |
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 kind of deps mechanism is a bit awkward since it leaks the need to know internal names from makeDynCall
out to the JS code. Can we align the naming so that one would type the same string into the __deps field that one puts inside the {{{ }}} block. That way there is at least a visual hint to suggest where the dependency comes from. (otherwise it can be hard to discover)
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 manged to remove the need for these.
5a7eb1e
to
122c607
Compare
OK I went all the way to managed to get a codeside win for both wasm and js sides! We still have three different cases where we need to use the legacy system:
Both of these cases needs to be investigated and fixed so that we can completely remove the non-i64 dynCalls from 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.
Nice progress!
} | ||
return Module['dynCall_' + sig].call(null, ptr); | ||
}, | ||
$dynCall__deps: ['$dynCallLegacy'], |
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.
it's odd to have the deps not near the function - why is this?
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.
Because the dependency is conditional in the exact same way the this functions existence is conditions.
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 guess I don't feel strongly but I believe this is the one place in the entire codebase not to have the two adjacent. Maybe it's worth the benefit though.
And good idea about the internal API change, yes, that's a bunch of work to update all the places as you've done, but I think it's the right thing. |
I manged to make vim do it for me after doing about 10 by hand: |
Add two bugs for followup on ASYNCIFY and WASM2C |
0ccdcbc
to
c60a031
Compare
Instead, this calls the Table directly. This takes a little more effort at compile time because we need to find the index of the function type for the signature we are calling with (so that we trap if the target function has the wrong type). To do that, scan the wasm2c output - which is at risk of breaking if that output changes, sadly (another option might be to disassemble the wasm and scan that, which would at least be a stable format - but this seems fine for now). Helps #12059 Fixes #12065
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.
lgtm % last comment on always including $dynCall
.
tools/ports/sdl2.py
Outdated
@@ -90,7 +90,7 @@ def clear(ports, settings, shared): | |||
|
|||
|
|||
def process_dependencies(settings): | |||
settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$autoResumeAudioContext'] | |||
settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$autoResumeAudioContext', '$dynCall'] |
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 it would be safer to always do this for dynCall in all (non-minimal runtime) builds - that is, to do this in emcc.py. That would make this change less noticeable to users.
Separately, removing it from DEFAULT_LIBRARY_FUNCS_TO_INCLUDE
later might make sense, but it would be good at that later time to document that in the changelog + make sure it gives a clear error to users if they need to add it manually from then onwards.
I did some benchmarking of this and see no issues, in fact it may be a slight bit faster. |
This change now passes flags to binaryen to limit the creation of the dynCall functions and removes more internal use of the legacy dynCall functions. See #12002
This removes callStackIdToFunc, the map of ids to functions. Instead it makes us always use the map of ids to function names. That removes one of the two mechanisms and makes the code simpler, which will help in a followup PR that adds support for direct table calls, which we need for #12059. I think we kept both mechanisms because I was worried about performance, but I think I was wrong. After debugging for #12059 I think I have a better understanding of things and it seems fine to use names - it's just a single JS map lookup for asyncify operation, which is small compared to the actual asyncify overhead. Move some code to maybeStopUnwind, with no changes. That code will be useful in the followup as well. Also clean up some debugging code to make it more useful.
This change now passes flags to binaryen to limit the creation
of the dynCall functions and removes more internal use of the
legacy dynCall functions.
See #12002