-
-
Notifications
You must be signed in to change notification settings - Fork 42
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
Don't pass the state and current process as arguments #617
Comments
Using external thread-local variables in Rust requires nightly, and probably will continue to require this for a long time: rust-lang/rust#29594 |
A tricky thing about using the stack is that LLVM doesn't seem to provide any intrinsics for obtaining any kind of stack information. This means we'd have to use raw assembly somehow to get the data from the stack. |
For thread-local code, the following Rust code compiles to the same as regular/raw thread-locals: thread_local! {
static PTR1: Cell<*mut ()> = const { Cell::new(std::ptr::null_mut()) };
} This can be seen at https://rust.godbolt.org/z/v16va86aq. The problem is that I'm not sure if this is true for every platform. Some additional details are found at https://matklad.github.io/2020/10/03/fast-thread-locals-in-rust.html. |
A quick dive through the current code reveals we don't use the current process value in all that many places, mostly to pass it as an implicit argument to methods. The few runtime routines that require it could instead just use a thread-local variable kept entirely on the runtime side of things. The only instruction that really needs it is the |
It seems that when one uses |
Looking at the assembly, it also seems Rust uses LLVM's |
The compiler generated code no longer passes the runtime state and the current process as hidden arguments. Instead, the state is stored in a global variable when the program starts up. For the current process we change the stack layout to the following: ╭───────────────────╮ │ Private page │ ├───────────────────┤ │ Guard page │ ├───────────────────┤ │ Stack data │ ↑ Stack grows towards the guard ╰───────────────────╯ The private page stores extra data, such as a pointer to the process that owns the stack and the epoch at which it started running. This entire chunk of data is then aligned to its size. This makes it possible to get a pointer to the private data page by applying a bitmask to the stack pointer. The bitmask depends on the stack size, which is runtime configurable and depends on the page size, and is loaded into a global variable at startup. This entire approach removes the need for more expensive thread-local operations, which we can't use anyway due to Rust's "thread_local" attribute not being stable (and likely not becoming stable for another few years). This fixes #617. Changelog: changed
For every compiled method, the first two arguments are the runtime state and the current process. This means that
fn foo(a: Int)
translates to essentiallyfn foo(state: Pointer[UInt8], process: Pointer[UInt8], a: Int)
.This approach isn't great, as we're wasting up to two registers to pass this data around, and in many cases the data likely isn't used much.
To optimize this, I'm thinking of the following:
The text was updated successfully, but these errors were encountered: