-
Couldn't load subscription status.
- Fork 75
Document a setjmp/longjmp convention #225
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
Changes from 6 commits
8d80cb0
7a3233a
ddd1e17
933eba3
afc947c
07dfc54
871cab8
544f148
cf83c3e
a9689fe
13891ab
c2feeb4
119de61
a0cdee8
862948e
1f28a42
ed850b7
4a4d448
54ca9fb
6da62fc
c91b637
680e18f
82a90db
baa023e
8c2c54f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,194 @@ | ||||||||||||||||||||||||||||||||||
| # C setjmp/longjmp in WebAssembly | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| ## Overview | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| This document describes a convention to implement C setjmp/longjmp via | ||||||||||||||||||||||||||||||||||
| [WebAssembly exception-handling proposal]. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| [WebAssembly exception-handling proposal]: https://github.com/WebAssembly/exception-handling | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 80% of what this doc describes does not seem to be wasm EH-specific. They also apply to the old Emscripten (JS-based) SjLj. How about stating that most of this doc applies to both ways of SjLj handling described in https://emscripten.org/docs/porting/setjmp-longjmp.html and explaining about some wasm-EH specific parts within the doc, such as |
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| ## Runtime ABI | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| ### Linear memory structures | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| This convention uses a few structures on the WebAssembly linear memory. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| #### Reserved area in jmp_buf | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| The first 6 words of C jmp_buf is reserved for the use by the runtime. | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add a note here making it explicit that the contents of these 6 words are not public? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok. |
||||||||||||||||||||||||||||||||||
| It should also have large enough alignment to store C pointers. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
| The contents of this area is private to the runtime implementation. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| ##### Notes about the size of reserved area in jmp_buf | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Emscripten has been using 6 words. (`unsigned long [6]`) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| GCC and Clang uses `intptr_t [5]` for their [setjmp/longjmp builtins]. | ||||||||||||||||||||||||||||||||||
| It isn't relevant right now though, because LLVM's WebAssembly target | ||||||||||||||||||||||||||||||||||
| doesn't provide these builtins. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| [setjmp/longjmp builtins]: https://gcc.gnu.org/onlinedocs/gcc/Nonlocal-Gotos.html | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| #### __WasmLongjmpArgs | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| An equivalent of the following structure is used to associate necessary | ||||||||||||||||||||||||||||||||||
| data to the WebAssembly exception. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||
| struct __WasmLongjmpArgs { | ||||||||||||||||||||||||||||||||||
| void *env; // a pointer to jmp_buf | ||||||||||||||||||||||||||||||||||
| int val; | ||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| The lifetime of this structure is rather short. It lives only during a | ||||||||||||||||||||||||||||||||||
| single longjmp execution. | ||||||||||||||||||||||||||||||||||
| A runtime can use a part of `jmp_buf` for this structure. It's also ok to use | ||||||||||||||||||||||||||||||||||
| a separate thread-local storage to place this structure. A runtime without | ||||||||||||||||||||||||||||||||||
| multi-threading support can simply place this structure in a global variable. | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's a part of the ABI. the compiler-generated code needs to know how to read members of this structure. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I misunderstood that part then. In that case, I wonder if it would make sense to further simplify the ABI, from this: to this: doing the loading of That way, we'd have less code inline. Would that make sense? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. well, at least $val needs to be visible to the catching logic as it's the return value of setjmp() There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As @yamt said, this part cannot go into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
i guess it can. why not? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, yeah, you're right. Would you like to submit a PR to the LLVM repo doing this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
do you only mean "make __wasm_setjmp_test rethrow"? i added them to the "Future directions" section for now. |
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| ### Exception | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| This convention uses a WebAssembly exception to perform a non-local jump | ||||||||||||||||||||||||||||||||||
| for C `longjmp`. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| The name of exception is `__c_longjmp`. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
| The type of exception is `(param i32)`. (Or, `(param i64)` for [memory64]) | ||||||||||||||||||||||||||||||||||
| The parameter of the exception is the address of `__WasmLongjmpArgs` structure | ||||||||||||||||||||||||||||||||||
| on the linear memory. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| [memory64]: https://github.com/WebAssembly/memory64 | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| ### functions | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||
| void __wasm_setjmp(jmp_buf env, uint32_t label, void *func_invocation_id); | ||||||||||||||||||||||||||||||||||
| uint32_t __wasm_setjmp_test(jmp_buf env, void *func_invocation_id); | ||||||||||||||||||||||||||||||||||
| void __wasm_longjmp(jmp_buf env, int val); | ||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| `__wasm_setjmp` records the necessary data in the `env` so that it can be | ||||||||||||||||||||||||||||||||||
| used by `__wasm_longjmp` later. | ||||||||||||||||||||||||||||||||||
| `label` is a non-zero identifier to distinguish setjmp call-sites within | ||||||||||||||||||||||||||||||||||
| the function. Note that a C function can contain multiple setjmp() calls. | ||||||||||||||||||||||||||||||||||
| `func_invocation_id` is the identifier to distinguish invocations of this | ||||||||||||||||||||||||||||||||||
| C function. Note that, when a C function which calls setjmp() is invoked | ||||||||||||||||||||||||||||||||||
| recursively, setjmp/longjmp needs to distinguish them. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| `__wasm_setjmp_test` tests if the longjmp target belongs to the current | ||||||||||||||||||||||||||||||||||
| function invocation. if it does, this function returns the `label` value | ||||||||||||||||||||||||||||||||||
| saved by `__wasm_setjmp`. Otherwise, it returns 0. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| `__wasm_longjmp` is similar to C `longjmp`. | ||||||||||||||||||||||||||||||||||
| If `val` is 0, it's `__wasm_longjmp`'s responsibility to convert it to 1. | ||||||||||||||||||||||||||||||||||
| It performs a long jump by filling a `__WasmLongjmpArgs` structure and | ||||||||||||||||||||||||||||||||||
| throwing `__c_longjmp` exception with its address. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| ## Code conversion | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| The C compiler detects `setjmp` and `longjmp` calls in a program and | ||||||||||||||||||||||||||||||||||
| converts them into the corresponding WebAssembly exception-handling | ||||||||||||||||||||||||||||||||||
| instructions and calls to the above mentioned runtime ABI. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| ### functions calling setjmp() | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| On the function entry, the compiler would generate the logic to create | ||||||||||||||||||||||||||||||||||
| the identifier of this function invocation, typically by performing an | ||||||||||||||||||||||||||||||||||
| equivalent of `alloca(1)`. Note that the alloca size is not important | ||||||||||||||||||||||||||||||||||
| because the pointer is merely used as an identifier and never be dereferenced. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Also, the compiler converts C `setjmp` calls to `__wasm_setjmp` calls. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Also, for code blocks which possibly call `longjmp` directly or indirectly, | ||||||||||||||||||||||||||||||||||
| the compiler generates instructions to catch and process the | ||||||||||||||||||||||||||||||||||
| `__c_longjmp` exception accordingly. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| For an example, a C function like this would be converted like | ||||||||||||||||||||||||||||||||||
| the following pseudo code. | ||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||
| void | ||||||||||||||||||||||||||||||||||
| f(void) | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| jmp_buf env; | ||||||||||||||||||||||||||||||||||
| if (!setjmp(env)) { | ||||||||||||||||||||||||||||||||||
| might_call_longjmp(env); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
| ``` | |
| void | |
| f(void) | |
| { | |
| jmp_buf env; | |
| if (!setjmp(env)) { | |
| might_call_longjmp(env); | |
| } | |
| } | |
| ```c | |
| void f(void) { | |
| jmp_buf env; | |
| if (!setjmp(env)) { | |
| might_call_longjmp(env); | |
| } | |
| } |
- Nit: LLVM and Emscripten's clang-format style
- Specify the block is in C for (slightly) better highlighting
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.
Nit: LLVM and Emscripten's clang-format style
well, although i have no strong opinions about the style, this is not llvm or emscripten.
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 not? I pasted the code block into any LLVM source file and clang-formatted it, and it showed no changes (from what I suggested). LLVM's clang-format style is two-space indentation. Which part do you think this is different from LLVM's clang-format style? (And Emscripten's .clang-format uses two-space indentation 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.
i meant that this repo (tool-conventions) is not a part of emscripten or llvm. thus does not necessarily follow their coding style.
if you like their coding style for some reasons, it's fine. i can change.
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.
Ah I see what you meant. Yeah I know it's a nitpick (which is the reason I said 'Nit') but I just preferred it to be more like the code style we work on most of the times. Also having a separate line for the return type doesn't seem to be very common either (unless the line exceeds 80-col). I'd appreciate if you change it. Thanks!
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.
but I just preferred it to be more like the code style we work on most of the times. Also having a separate line for the return type doesn't seem to be very common either (unless the line exceeds 80-col).
well, projects i work on most of the times use different styles.
i suspect there is no single "very common" style even among wasm related projects.
cf.
https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/.clang-format
https://github.com/yamt/toywasm/blob/master/.clang-format
i guess C++ projects tend to prefer smaller indentation width than C projects for obvious reasons.
Outdated
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.
| ``` | |
| ```wat |
Also how about using 2-space indentation?
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.
Ping
Outdated
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 somehow looks we have to do this code block for every maybe-longjmping call. But in Wasm EH the whole function can be within a giant try-catch and this code block calling __wasm_setjmp_test and __wasm_longjmp only happens once within a function. This is only for Wasm EH and for JS-based (Emscripten) EH this code happens for every maybe-longjmping call.
Also this code doesn't contain that we split the BB after the setjmp call:
https://github.com/llvm/llvm-project/blob/4e85e1ffcaf161736e27a24c291c1177be865976/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp#L147-L148
And there should be a basic block called setjmp-dispatch BB:
https://github.com/llvm/llvm-project/blob/4e85e1ffcaf161736e27a24c291c1177be865976/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp#L236-L242
Without this what label in this code block means is not explained.
I'm not sure how in detail we should describe the code transformation, but if we do this at all, I think it'd be better if we be more detailed; unless many parts of this block cannot be explained. Copy-pasting the code block comments in https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
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 just wanted to give an example of possible transformation.
describing what llvm does in detail is not in the scope of this document i suppose.
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'm not sure what part of the LLVM transformation belongs to the ABI and what part is a detail that's not the scope of the ABI. But I think giving only the half of the code transformation can be confusing. If we don't want to give the full transformation detail, we could not give the transformation example at all and just try to be handwavy about this and give a link to the LLVM file for more reference.
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.
part of the ABI:
- the exception and __WasmLongjmpArgs layout
- abi funcitons (__wasm_longjmp etc)
- label (eg. 0 is not used)
not a part of the ABI:
- how specifically label values are allocated
- a single giant try-block or smaller ones
- how specifically label dispatching is implemented (eg. setjmp-dispatch BB)
- anything in LLVM IR
Outdated
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 do these two lines of colons mean?
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 meant "omitted"
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.
Are colons used to specify omitted part? I've seen something like '...' but haven't seen colons, but it can be just I don't know about them.
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 used them as a vertical version of "...". i dunno how common it is.
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.
Perhaps the Unicode vertical ellipsis might make these more clear? "⋮"
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.
do you mean the top-level indentation?
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.
Also how about using 2-space indentation?
This in #225 (comment)
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.
is this what you meant? 54ca9fb
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.
Huh, I missed it. Sorry.
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.
well, i pushed the change to ask you if it's what you meant. (because i was not sure if i understand what you meant.)
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.
Again, maybe we could mention emscripten_longjmp too
Outdated
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.
| Note: older LLVM versions have been using a slightly different runtime ABI, | |
| which is supported by Emscripten. It has been switched to the ABI documented | |
| above by https://github.com/llvm/llvm-project/pull/84137. |
Not sure if we need to have a link to the PR, and given that presumably it is a non-goal of this doc to describe the history, I think it's fine to describe only the current status quo.
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.
removed
Outdated
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 meant the Emscripten version which contains emscripten-core/emscripten#21502 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.
The next release, which I expect to be done within a few days now, will contain this, so I think we can remove the 'TBD' part. Also we can have a link to the file here:
https://github.com/emscripten-core/emscripten/blob/main/system/lib/compiler-rt/emscripten_setjmp.c
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.
will it be 3.1.57?
i prefer to mention versions for each components as not everyone uses the latest.
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.
Yeah 3.1.57 is the next one
Outdated
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.
Given that the PR was merged, can we have a link to a specific file, like https://github.com/WebAssembly/wasi-libc/blob/main/libc-top-half/musl/src/setjmp/wasm32/rt.c ?
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.
updated
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.
| [WebAssemblyLowerEmscriptenEHSjLj.cpp]: https://github.com/llvm/llvm-project/blob/70deb7bfe90af91c68454b70683fbe98feaea87d/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp | |
| [WebAssemblyLowerEmscriptenEHSjLj.cpp]: https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp |
Not sure if this needs to be from a specific commit version, given that we are not specifying specific lines
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 prefer to always use permalink as the files can be renamed/removed in future.
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 in that case we should fix the link, because it means the doc is pointing to a wrong file.
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.
well, after all, what this doc refers to is today's version of the file.
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.
If I understand correctly, this is just an internal implementation detail, right? If so, would it make sense to omit it in this document?
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.
no. as mentioned above, it's a part of the current ABI. (thus making it use multivalue is unfortunately another ABI change.)
Outdated
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.
Do we need this? We don't have any problem-exploring design doc links elsewhere in this repo, once we settle on a solution.
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.
removed
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.
My understanding is that this convention is now the default for LLVM, right? I think this document should say that.
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 documented in the "Implementations" section.