1 unstable release
new 0.2.0 | Mar 15, 2025 |
---|---|
0.1.0 |
|
#778 in Embedded development
47 downloads per month
30KB
576 lines
Safer[^1], cheaper and more ergonomic setjmp/longjmp in Rust[^2]
[^1]: long_jump
is still unsafe and is technically UB, though.
See more about safety in docs of long_jump
.
[^2]: ...and assembly. No C trampoline is involved!
See more in documentations.
lib.rs
:
Safer[^1], cheaper and more ergonomic setjmp/longjmp in Rust[^2].
[^1]: long_jump
is still unsafe and is technically UB, though.
See more about safety in long_jump
.
[^2]: ...and assembly. No C trampoline is involved!
-
Ergonomic and safer* Rusty API for typical usages. Closure API instead of multiple-return.
Multiple-return functions are undefined behaviors due to fatal interaction with optimizer. This crate does not suffer from the misoptimization (covered in
tests/smoke.rs
).⚠️ We admit that since it's not yet undefined to force unwind Rust POFs and/or longjmp's half execution semantic,
long_jump
is still technically undefined behavior. But this crate is an attempt to make a semantically-correct abstraction free from misoptimization, and you accept the risk by using this crate. If you find any misoptimization in practice, please open an issue. -
Single-use jump checkpoint.
No jump-after-jump disaster. No coroutine-at-home.
-
Minimal memory and performance footprint.
Single
usize
JumpPoint
. Let optimizer save only necessary states rather than bulk saving all callee-saved registers. Inline-ableset_jump
without procedure call cost.- 2.3ns
set_jump
setup and 3.2nslong_jump
on a modern x86_64 CPU. ~300-490x faster thancatch_unwind
-panic_any!
.
- 2.3ns
-
No std.
This crate is
#[no_std]
and does not usealloc
either. It is suitable for embedded environment.
use std::num::NonZero;
use sjlj2::JumpPoint;
let mut a = 42;
// Execute with a jump checkpoint. Both closures can return a value.
let b = JumpPoint::set_jump(
// The ordinary path that is always executed.
|jump_point| {
a = 13;
// Jump back to the alternative path with a `NonZero<usize>` value.
// SAFETY: All frames between `set_jump` and `long_jump` are POFs.
unsafe {
jump_point.long_jump(NonZero::new(99).unwrap());
}
},
// The alternative path which is only executed once `long_jump` is called.
|v| {
// The carried value.
v.get()
}
);
assert_eq!(a, 13);
assert_eq!(b, 99);
Features
-
unstable-asm-goto
: enable use ofasm_goto
andasm_goto_with_outputs
unstable features.This requires a nightly rustc, but produces more optimal code with one-less conditional jump.
⚠️ Warning:
asm_goto_with_outputs
is reported to be buggy in some cases. It is unknown that if our code is affected. Do NOT enable this feature unless you accept the risk. aarch64-apple-darwin is known to be buggy with this feature, thus is incompatible.
Supported architecture
- x86 (i686)
- x86_64
- riscv64
- riscv32 (with and without E-extension)
- aarch64 (ARMv8)
- arm
Similar crates
-
- Generates from C thus needs a correctly-setup C compiler to build.
- Unknown performance because it fails to build for me. (Poor compatibility?)
- Suffers from misoptimization.
-
- Uses inline assembly but involving an un-inline-able call instruction.
- Only x86_64 is supported.
- Suffers from misoptimization.
- Slower
long_jump
because of more register restoring.