Apply the sbrk pointer's location to the wasm, avoiding the need to import it#9397
Conversation
The _callback function being included in EXPORT_FUNCTIONS but it is a static function which is not exportable with the wasm backend. Since this is never used simply remove it from the list.
This reverts commit dbe1523 which was mistakenly committed to master.
…This also helps wasi.
To allow #2331 to roll, I forgot that upstream and fastcomp handle sbrk differently. This fixes that, and handles the upstream case where we import sbrk itself from JS. We can simplify this after emscripten-core/emscripten#9397 lands, however, it may also be nice to keep the backwards compatibility for running on existing wasm files in the wild.
| if shared.Settings.BINARYEN_PASSES: | ||
| passes += parse_passes(shared.Settings.BINARYEN_PASSES) | ||
| else: | ||
| # Safe heap must run before post-emscripten, so post-emscripten can apply the sbrk ptr |
There was a problem hiding this comment.
Should this be enforced in binaryen itself? Or, are there other places where we might want to enforce this invariant? If a user (of binaryen, or emscripten via -s BINARYEN_PASSES) is manually specifying passes, and does this the other way around, should we do anything?
There was a problem hiding this comment.
Hmm, good question.
In theory a user may want the opposite order, if they don't want such functions to be affected. That seems unlikely though, so perhaps a warning in Binaryen would be useful. We currently don't have a mechanism for that, though (it just runs the passes blindly) but maybe we should add one. Another possible example is people running asyncify without optimizations (so not an order issue, but one pass that works better with others, maybe also worth a warning).
| #endif // ALLOW_MEMORY_GROWTH | ||
| }, | ||
|
|
||
| #if MINIMAL_RUNTIME && !ASSERTIONS && !ALLOW_MEMORY_GROWTH |
There was a problem hiding this comment.
Yay deleting code 🎉
… we can ignore the sbrk-related checks, but still do alignment and segfault checking.
…eed to be emterpreted, they are safe to run normally.
|
Some more fixes:
|
|
Ok, I worried some parts of this might be controversial, so kept open for a week, but looks like there are no concerns, landing. |
|
Hey, I arrived just in time for a post-commit drive-by comment! |
| intptr_t old_brk = *sbrk_ptr; | ||
| // TODO: overflow checks | ||
| intptr_t new_brk = old_brk + increment; | ||
| #if __wasm__ |
There was a problem hiding this comment.
Shouldn't this be #ifdef __wasm__? I don't think fastcomp defines __wasm__ == 0?
| if (new_brk > old_size) { | ||
| // Try to grow memory. | ||
| intptr_t diff = new_brk - old_size; | ||
| if (!emscripten_resize_heap(new_brk)) { |
There was a problem hiding this comment.
It seems odd that we are using __builtin_wasm_memory_size but not __builtin_wasm_grow_memory. Why the discrepancy?
There was a problem hiding this comment.
The tricky thing is that growing memory requires us to update the JS views. Doing the resizing in JS makes that easy.
|
Thanks @dschuff, will open a followup PR for those issues. |
| }[self.malloc])] | ||
| }[self.malloc]) | ||
| sbrk = shared.path_from_root('system', 'lib', 'sbrk.c') | ||
| return [malloc, sbrk] |
There was a problem hiding this comment.
Why isn't this just part of libc? Why compile it N times into each libmalloc if its the same code in each one?
There was a problem hiding this comment.
I guess it could be part of libc too.
In general there aren't N builds, though, there is normally just one build of malloc. Unless the user builds with flags that actually require a different sbrk build, like pthreads or errno etc. So it wouldn't be the same code in each one.
…mport it (emscripten-core#9397) Importing DYNAMICTOP_PTR is not compatible with wasi, and it's smaller anyhow to just have the value in the binary. This does so by computing the sbrk ptr's static location in the JS compiler, as always, and noting it in the metadata. We then call the binaryen post-emscripten pass with that data later and it applies it. As a nice result, we can get rid of a bunch of code for importing DYNAMICTOP_PTR, and replace the sbrk implementation in JS with a very simple one in C. * Since our malloc's threadsafety is done using locks, this sbrk does no additional guarding. That's more efficient than before (we used atomics in sbrk). However, in theory someone might call sbrk not through malloc, which this does not handle atm. * This slightly regresses other.test_minimal_runtime_code_size expectations, since now we use a standard sbrk in C, while before there were a bunch of custom options for the library.js version like USES_DYNAMIC_ALLOC=2. That mode 2 isn't documented so I'm not sure how to reproduce similar behavior in the new implementation. (Also it looks like MALLOC=none would achieve the same as USES_DYNAMIC_ALLOC=0, so maybe I'm misunderstanding this option, or maybe they are redundant?) In any case, the regression is quite small, and this is just on fastcomp - this sbrk refactoring helps on the wasm backend side. * Emterpreter fixes: We don't need to emterpret the new sbrk and emscripten_get_sbrk_ptr, and also it is safe to call the latter at all times (it just returns a number), so the special Emterpreter assertions that check if we are running invalid code during a sleep can ignore it.
Importing
DYNAMICTOP_PTRis not compatible with wasi, and it's smaller anyhow to just have the value in the binary.This does so by computing the sbrk ptr's static location in the JS compiler, as always, and noting it in the metadata. We then call the binaryen post-emscripten pass with that data later and it applies it.
As a nice result, we can get rid of a bunch of code for importing
DYNAMICTOP_PTR, and replace thesbrkimplementation in JS with a very simple one in C.Please note:
other.test_minimal_runtime_code_sizeexpectations, since now we use a standard sbrk in C, while before there were a bunch of custom options for the library.js version likeUSES_DYNAMIC_ALLOC=2. That mode 2 isn't documented so I'm not sure how to reproduce similar behavior in the new implementation. (Also it looks likeMALLOC=nonewould achieve the same asUSES_DYNAMIC_ALLOC=0, so maybe I'm misunderstanding this option, or maybe they are redundant?) In any case, the regression is quite small, and this is just on fastcomp - this sbrk refactoring helps on the wasm backend side. cc @jujAfter this PR, I can open a PR with a
WASIoption, as this is the last main blocker for getting "hello world" to be a valid wasi program.