On 01/31/2013 03:41 PM, Brian Anderson wrote:
On 01/31/2013 03:35 PM, Brian Anderson wrote:
On 01/31/2013 02:37 PM, Patrick Walton wrote:
Hi everyone,
With the revamp of the scheduler underway, I'd like to propose a
change to the way C functions work.
Currently, we generate a shim and a stack switch for every function
call from Rust to C and likewise from C to Rust, except for
functions annotated with `#[rust_stack]`. These wrappers result in a
significant performance overhead. For some workloads this
performance overhead is acceptable in order to maintain small
stacks. For some workloads the performance overhead is undesirable.
For instance, the DOM in Servo requires lots of very small calls
from JavaScript to Rust. The overhead of stack switching swamps most
of the time here. Popular Web benchmarks will do things like
`someElement.clientX;` over and over, which require calls from
JavaScript to Rust to retrieve a cached value. So we must carefully
consider every CPU cycle spent in the C-to-Rust transition.
To address these issues I would like to propose a somewhat radical
change: don't have the compiler generate stack switching stubs at
all. Instead, the scheduler can expose a primitive that generates
the stack switch, and it's the programmer's responsibility to
perform the stack switch to call out to C functions. To avoid the
obvious footgun here, I propose a lint pass, on by default, that
ensures that functions not annotated with `#[rust_stack]` are called
inside a stack switching helper.
The rationale here is as follows:
1. It should be possible to group many C calls under a single stack
switching operation. For example:
do stackswitch {
c_function_1();
c_function_2();
c_function_3();
}
This amortizes the cost of the stack switch over many native
function calls.
I think this API requires #4479 and #4480 to be safe. Currently, the
execution environment after the stack switch is very different, so
running arbitrary Rust code there is dangerous. We may want to think
of 'stack switching' instead as 'make sure I'm running on a stack
segment that is big'. Then whatever code executes after that doesn't
matter - if it's C code it will run till it runs off the stack, if
it's Rust code it will request a new segment when it hits the end.
https://github.com/mozilla/rust/issues/4479
https://github.com/mozilla/rust/issues/4480
An API that was more like `stackswitch!(function, args)` wouldn't
have that problem.
There's also the problem with failure after switching stacks. Right
now there is a guard in the stack switch that catches exceptions
thrown by foreign code and aborts the process, which makes this bogus:
do stackswitch {
fail;
}
We could remove that guard and leave the behavior undefined ...
I'm going to stop replying to myself, but with return-based unwinding
the story here will be changing. Probably we can thread the return flag
through the stack switch and leave the DWARF unwinding case undefined.
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev