Description
Right now, if you want to do any of the following:
- Write libraries in Rust that can be called from other languages
- Write Linux kernel modules in Rust
- Write the Rust runtime in Rust
you are thwarted by the inability of Rust code to escape the Rust runtime. This ticket is intended to centralize discussion of how this could be done.
Some old random comments:
"This might be useful for other things too, such as drivers or libraries to be embedded into other software. (The latter is obviously of interest to us at Mozilla.) Rust programs compiled in this mode would disable the task system, would be vulnerable to stack overflow (although we might be able to mitigate that with guard pages), and would require extra work to avoid leaks, but would be able to run without a runtime." ~ @pcwalton
"Rust does currently depend on a language runtime which expects to control the execution of all Rust code (in particular managing the task scheduler), and the runtime does not have an embedding story yet. Even with an embeddable runtime though, the process would be more involved than loading a library through
dlopen
and executing a function.
"As part of the effort to rewrite the remaining bits of C++ runtime code in Rust (almost all of Rust is written in Rust), there are further plans to make Rust code runnable without an underlying runtime and without split stacks." ~ @brson
<pcwalton> well, we'd need to do something about stack growth
<pcwalton> a crate-level attribute to disable it, I guess
<pcwalton> also I guess we'd probably want to convert all the residual upcalls to lang items.
<pcwalton> and the ability to disable linking against librustrt
<pcwalton> but yeah, those are quite easy
<pcwalton> disabling stack growth is the big one. that would also be useful if you want to write dynamic libraries in pure Rust callable from C
<pcwalton> I *think* if you do that, and you avoid @ boxes, and you don't use the task system, and your entry points are extern "C", and we change the exchange heap to be allocable without a task pointer, then you are probably OK
"The runtime does three things: (a) set up the initial task and allocates new tasks when a task runs out of stack; (b) schedules tasks; (c) provides a few implementations of magic functions that aren't written in Rust yet.
"For (a), this is because we have segmented stacks, and there needs to be some hooks to set this up. Eventually this magic should be written in Rust, not in C++. (We needed C++ to bootstrap.) (b) is basically the same story; note that the language itself knows nothing about tasks and they're solely in the standard library. And for (c), the number of these functions is dwindling and more of them are being moved into the standard library." ~ pcwalton
< dylukes> How feasible do you guys think a Rust -> JS compiler is at this stage?
< dylukes> (restatement: how pluggable is the backend of rustc)
< dylukes> (last time I went through the code it was pretty well divided into front/middle/back)
<@nmatsakis> the right approach is not to change rustc
<@nmatsakis> but rather to use emscripten
<@nmatsakis> this is basically dependent on the runtime-less rust
<@nmatsakis> efforts
< dylukes> Oh that's true. I forgot about emscripten.
< dylukes> Alternatively you provide a runtime in JS.
< dylukes> I assume emscripten converts calls to external functions to javascript calls, so you'd just have
to stub out the runtime, no?
< dylukes> Or you know, compile the runtime with emscripten as well...
<@pcwalton> you'd need to write a new runtime
<@nmatsakis> it's conceivable we could write a very minimal runtime that just fails if you enter the hard
parts.
<@nmatsakis> "runtime-less rust" is clearly the "right way"
<@nmatsakis> array bound checks would presumably still be present in a standalone Rust
<@nmatsakis> we have to decide what failure means though
<@pcwalton> probably abort()
<@nmatsakis> :(
<@nmatsakis> that's not how I was thinking of it
<@nmatsakis> that is, I was thinking that all rust programs would be standalone, basically
<@nmatsakis> but things like tasks would be an optional library
<@nmatsakis> as a long term goal I guess
<@pcwalton> oh sure, I mean it would be a call to upcall_fail() or whatever
<@nmatsakis> a separate mode would be a good place to start
< bstrie> how would a program that uses tasks call into a standalone program if the latter has split stacks
disabled?
<@pcwalton> but in the standalone RT it would just call abort()
<@nmatsakis> currently, we throw a C++ exception (except on Windows, I know)
<@nmatsakis> that would be quite tolerable
<@nmatsakis> actually it'd be nice if upcall_fail() were pluggable
<@nmatsakis> perhaps some minimal set of upcalls could be given virtually
<@pcwalton> nmatsakis: it has to be a separate mode to some degree because of the current llvm all-or-nothing
support for split stacks
<@pcwalton> although that should be changed
<@nmatsakis> pcwalton: I was assuming that we'd always keep split-stacks, and we'd just have the "top" of the
stack be initialized to infinity or what have you. We can presumably compile C-invokable
wrappers for the external interface points. In any case, there are plenty of details to be
worked out....