`longjmp` can be called to raise `NoMemoryError` or to trigger GC when
`malloc` fails to allocate memory in `ruby_xmalloc` family. In such
case, `malloc` call in `longjmp` will fail again, and Asyncify unwinding
operation corrupts the memory space by using the failed pointer as
Asyncify buffer. This commit uses statically allocated buffer to avoid
such situation.
[wasm] Fix Asyncify loop exit condition for normal return
Stop calling `asyncify_stop_unwind` when the main function returns
without any unwinding. In the era when Asyncify buffers were allocated
on the stack, the `top` and `end` fields were remained in the stack
space even after the main function returned, so buffer-overflow check in
the `asyncify_stop_unwind` function passed. But now, the `top` and `end`
fields are part of the jump buffer allocated on the heap and they are
deallocated with `free` when the corresponding VM tag is popped. So, the
buffer-overflow check in the `asyncify_stop_unwind` function failed when
the main fuction returned without any unwinding, and we have to break
the asyncify loop before calling `asyncify_stop_unwind`.
Related commit: bc46b12b12
The Ruby built for wasm cannot be execute without a WebAssembly runtime.
```
$ ruby-wasm32-wasi/usr/local/bin/ruby -e 'puts "a"'
bash: ruby-wasm32-wasi/usr/local/bin/ruby: cannot execute binary file: Exec format error
```
Because the Ruby's file type is different from the one built normally, that is
the `/usr/local/ruby-3.2.0-preview2/bin/ruby` below.
```
$ file ruby-wasm32-wasi/usr/local/bin/ruby
ruby-wasm32-wasi/usr/local/bin/ruby: WebAssembly (wasm) binary module version 0x1 (MVP)
$ file /usr/local/ruby-3.2.0-preview2/bin/ruby
/usr/local/ruby-3.2.0-preview2/bin/ruby: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a37822085e285c0971159982e7642dda88cea606, for GNU/Linux 3.2.0, with debug_info, not stripped
```
fiber machine stack is placed outside of C stack allocated by wasm-ld,
so highest stack address recorded by `rb_wasm_record_stack_base` is
invalid when running on non-main fiber.
Therefore, we should scan `stack_{start,end}` which always point a valid
stack range in any context.
Autoconf distributed with Ubuntu 22.04 is very old and doesn't support
WASI as an OS, so add instructions to download the latest config.guess,
then run `./autogen.sh`.
See also: 2297012efd
the original rb_wasm_setjmp implementation always unwinds to the root
call frame to have setjmp compatible interface, and simulate sjlj's
undefined behavior. Therefore, every vm_exec call unwinds to main, and
a deep call stack makes setjmp call very expensive. The following
snippet from optcarrot takes 5s even though it takes less than 0.3s on
native.
```
[0x0, 0x4, 0x8, 0xc].map do |attr|
(0..7).map do |j|
(0...0x10000).map do |i|
clr = i[15 - j] * 2 + i[7 - j]
clr != 0 ? attr | clr : 0
end
end
end
```
This patch adds a WASI specialized vm_exec which uses lightweight
try-catch API without unwinding to the root frame. After this patch, the
above snippet takes only 0.5s.
Tabs were expanded because the file did not have any tab indentation in unedited lines.
Please update your editor config, and use misc/expand_tabs.rb in the pre-commit hook.
configure.ac: setup build tools and register objects
main.c: wrap main with rb_wasm_rt_start to handle asyncify unwinds
tool/m4/ruby_wasm_tools.m4: setup default command based on WASI_SDK_PATH
environment variable. checks wasm-opt which is used for asyncify.
tool/wasm-clangw wasm/wasm-opt: a clang wrapper which replaces real
wasm-opt with do-nothing wasm-opt to avoid misoptimization before
asyncify. asyncify is performed at POSTLINK, but clang linker driver
tries to run optimization by wasm-opt unconditionally. inlining pass
at wasm level breaks asyncify's assumption, so should not optimize
before POSTLIK.
wasm/GNUmakefile.in: wasm specific rules to compile objects