There is only one activate function now.
This commit is contained in:
parent
2e8afc7b47
commit
0fc91b6ecc
8 changed files with 105 additions and 113 deletions
8
mk/rt.mk
8
mk/rt.mk
|
@ -33,6 +33,8 @@ RUNTIME_CS := rt/sync/timer.cpp \
|
|||
|
||||
RUNTIME_LL := rt/new_exit.ll
|
||||
|
||||
RUNTIME_S := rt/activate_glue.s
|
||||
|
||||
RUNTIME_HDR := rt/globals.h \
|
||||
rt/rust.h \
|
||||
rt/rust_dwarf.h \
|
||||
|
@ -65,7 +67,7 @@ RUNTIME_HDR := rt/globals.h \
|
|||
|
||||
RUNTIME_DEF := rt/rustrt$(CFG_DEF_SUFFIX)
|
||||
RUNTIME_INCS := -I $(S)src/rt/isaac -I $(S)src/rt/uthash
|
||||
RUNTIME_OBJS := $(RUNTIME_CS:.cpp=.o) $(RUNTIME_LL:.ll=.o)
|
||||
RUNTIME_OBJS := $(RUNTIME_CS:.cpp=.o) $(RUNTIME_LL:.ll=.o) $(RUNTIME_S:.s=.o)
|
||||
RUNTIME_LIBS := $(CFG_GCCISH_POST_LIB_FLAGS)
|
||||
|
||||
|
||||
|
@ -73,6 +75,10 @@ rt/%.o: rt/%.cpp $(MKFILES)
|
|||
@$(call E, compile: $@)
|
||||
$(Q)$(call CFG_COMPILE_C, $@, $(RUNTIME_INCS)) $<
|
||||
|
||||
rt/%.o: rt/%.s $(MKFILES)
|
||||
@$(call E, compile: $@)
|
||||
$(Q)$(call CFG_COMPILE_C, $@, $(RUNTIME_INCS)) $<
|
||||
|
||||
rt/%.o: rt/%.ll $(MKFILES)
|
||||
@$(call E, llc: $@)
|
||||
$(Q)$(LLC) -filetype=obj -relocation-model=pic -march=x86 -o $@ $<
|
||||
|
|
|
@ -99,10 +99,6 @@ fn native_glue_name(int n, native_glue_type ngt) -> str {
|
|||
ret prefix + util::common::istr(n);
|
||||
}
|
||||
|
||||
fn activate_glue_name() -> str {
|
||||
ret "rust_activate_glue";
|
||||
}
|
||||
|
||||
fn yield_glue_name() -> str {
|
||||
ret "rust_yield_glue";
|
||||
}
|
||||
|
|
|
@ -87,92 +87,6 @@ fn store_esp_to_runtime_sp_second_arg() -> vec[str] {
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* This is a bit of glue-code. It should be emitted once per
|
||||
* compilation unit.
|
||||
*
|
||||
* - save regs on C stack
|
||||
* - align sp on a 16-byte boundary
|
||||
* - save sp to task.runtime_sp (runtime_sp is thus always aligned)
|
||||
* - load saved task sp (switch stack)
|
||||
* - restore saved task regs
|
||||
* - return to saved task pc
|
||||
*
|
||||
* Our incoming stack looks like this:
|
||||
*
|
||||
* *esp+4 = [arg1 ] = task ptr
|
||||
* *esp = [retpc ]
|
||||
*/
|
||||
|
||||
fn rust_activate_glue() -> vec[str] {
|
||||
ret ["movl 4(%esp), %ecx # ecx = rust_task"]
|
||||
+ save_callee_saves()
|
||||
+ store_esp_to_runtime_sp_first_arg()
|
||||
+ load_esp_from_rust_sp_first_arg()
|
||||
|
||||
/*
|
||||
* There are two paths we can arrive at this code from:
|
||||
*
|
||||
*
|
||||
* 1. We are activating a task for the first time. When we switch
|
||||
* into the task stack and 'ret' to its first instruction, we'll
|
||||
* start doing whatever the first instruction says. Probably
|
||||
* saving registers and starting to establish a frame. Harmless
|
||||
* stuff, doesn't look at task->rust_sp again except when it
|
||||
* clobbers it during a later native call.
|
||||
*
|
||||
*
|
||||
* 2. We are resuming a task that was descheduled by the yield glue
|
||||
* below. When we switch into the task stack and 'ret', we'll be
|
||||
* ret'ing to a very particular instruction:
|
||||
*
|
||||
* "esp <- task->rust_sp"
|
||||
*
|
||||
* this is the first instruction we 'ret' to after this glue,
|
||||
* because it is the first instruction following *any* native
|
||||
* call, and the task we are activating was descheduled
|
||||
* mid-native-call.
|
||||
*
|
||||
* Unfortunately for us, we have already restored esp from
|
||||
* task->rust_sp and are about to eat the 5 words off the top of
|
||||
* it.
|
||||
*
|
||||
*
|
||||
* | ... | <-- where esp will be once we restore + ret, below,
|
||||
* | retpc | and where we'd *like* task->rust_sp to wind up.
|
||||
* | ebp |
|
||||
* | edi |
|
||||
* | esi |
|
||||
* | ebx | <-- current task->rust_sp == current esp
|
||||
*
|
||||
*
|
||||
* This is a problem. If we return to "esp <- task->rust_sp" it
|
||||
* will push esp back down by 5 words. This manifests as a rust
|
||||
* stack that grows by 5 words on each yield/reactivate. Not
|
||||
* good.
|
||||
*
|
||||
* So what we do here is just adjust task->rust_sp up 5 words as
|
||||
* well, to mirror the movement in esp we're about to
|
||||
* perform. That way the "esp <- task->rust_sp" we 'ret' to below
|
||||
* will be a no-op. Esp won't move, and the task's stack won't
|
||||
* grow.
|
||||
*/
|
||||
+ ["addl $20, " + wstr(abi::task_field_rust_sp) + "(%ecx)"]
|
||||
|
||||
|
||||
/*
|
||||
* In most cases, the function we're returning to (activating)
|
||||
* will have saved any caller-saves before it yielded via native call,
|
||||
* so no work to do here. With one exception: when we're initially
|
||||
* activating, the task needs to be in the fastcall 2nd parameter
|
||||
* expected by the rust main function. That's edx.
|
||||
*/
|
||||
+ ["mov %ecx, %edx"]
|
||||
|
||||
+ restore_callee_saves()
|
||||
+ ["ret"];
|
||||
}
|
||||
|
||||
/* More glue code, this time the 'bottom half' of yielding.
|
||||
*
|
||||
* We arrived here because an native call decided to deschedule the
|
||||
|
@ -306,12 +220,8 @@ fn get_module_asm() -> str {
|
|||
|
||||
auto glues =
|
||||
[decl_glue(align, prefix,
|
||||
abi::activate_glue_name(),
|
||||
rust_activate_glue()),
|
||||
|
||||
decl_glue(align, prefix,
|
||||
abi::yield_glue_name(),
|
||||
rust_yield_glue())]
|
||||
abi::yield_glue_name(),
|
||||
rust_yield_glue())]
|
||||
|
||||
+ vec::init_fn[str](bind decl_native_glue(align, prefix,
|
||||
abi::ngt_rust, _), (abi::n_native_glues + 1) as uint)
|
||||
|
|
|
@ -55,8 +55,7 @@ state obj namegen(mutable int i) {
|
|||
|
||||
type derived_tydesc_info = rec(ValueRef lltydesc, bool escapes);
|
||||
|
||||
type glue_fns = rec(ValueRef activate_glue,
|
||||
ValueRef yield_glue,
|
||||
type glue_fns = rec(ValueRef yield_glue,
|
||||
vec[ValueRef] native_glues_rust,
|
||||
vec[ValueRef] native_glues_pure_rust,
|
||||
vec[ValueRef] native_glues_cdecl,
|
||||
|
@ -7661,9 +7660,6 @@ fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
|
|||
|
||||
let ValueRef crate_addr = p2i(crate_ptr);
|
||||
|
||||
let ValueRef activate_glue_off =
|
||||
llvm::LLVMConstSub(p2i(glues.activate_glue), crate_addr);
|
||||
|
||||
let ValueRef yield_glue_off =
|
||||
llvm::LLVMConstSub(p2i(glues.yield_glue), crate_addr);
|
||||
|
||||
|
@ -7674,7 +7670,7 @@ fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
|
|||
C_null(T_int()), // size_t debug_abbrev_sz
|
||||
C_null(T_int()), // ptrdiff_t debug_info_off
|
||||
C_null(T_int()), // size_t debug_info_sz
|
||||
activate_glue_off, // size_t activate_glue_off
|
||||
C_null(T_int()), // size_t pad
|
||||
yield_glue_off, // size_t yield_glue_off
|
||||
C_null(T_int()), // size_t unwind_glue_off
|
||||
C_null(T_int()), // size_t gc_glue_off
|
||||
|
@ -8030,8 +8026,7 @@ fn trans_vec_append_glue(@local_ctxt cx, &ast::span sp) {
|
|||
|
||||
|
||||
fn make_glues(ModuleRef llmod, &type_names tn) -> @glue_fns {
|
||||
ret @rec(activate_glue = decl_glue(llmod, tn, abi::activate_glue_name()),
|
||||
yield_glue = decl_glue(llmod, tn, abi::yield_glue_name()),
|
||||
ret @rec(yield_glue = decl_glue(llmod, tn, abi::yield_glue_name()),
|
||||
|
||||
native_glues_rust =
|
||||
vec::init_fn[ValueRef](bind decl_native_glue(llmod, tn,
|
||||
|
|
89
src/rt/activate_glue.s
Normal file
89
src/rt/activate_glue.s
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* This is a bit of glue-code.
|
||||
*
|
||||
* - save regs on C stack
|
||||
* - save sp to task.runtime_sp (runtime_sp is thus always aligned)
|
||||
* - load saved task sp (switch stack)
|
||||
* - restore saved task regs
|
||||
* - return to saved task pc
|
||||
*
|
||||
* Our incoming stack looks like this:
|
||||
*
|
||||
* *esp+4 = [arg1 ] = task ptr
|
||||
* *esp = [retpc ]
|
||||
*/
|
||||
|
||||
.globl new_rust_activate_glue
|
||||
.balign 4
|
||||
new_rust_activate_glue:
|
||||
movl 4(%esp), %ecx # ecx = rust_task
|
||||
pushl %ebp
|
||||
pushl %edi
|
||||
pushl %esi
|
||||
pushl %ebx
|
||||
movl %esp, 12(%ecx)
|
||||
movl 16(%ecx), %esp
|
||||
|
||||
/*
|
||||
* There are two paths we can arrive at this code from:
|
||||
*
|
||||
*
|
||||
* 1. We are activating a task for the first time. When we switch
|
||||
* into the task stack and 'ret' to its first instruction, we'll
|
||||
* start doing whatever the first instruction says. Probably
|
||||
* saving registers and starting to establish a frame. Harmless
|
||||
* stuff, doesn't look at task->rust_sp again except when it
|
||||
* clobbers it during a later native call.
|
||||
*
|
||||
*
|
||||
* 2. We are resuming a task that was descheduled by the yield glue
|
||||
* below. When we switch into the task stack and 'ret', we'll be
|
||||
* ret'ing to a very particular instruction:
|
||||
*
|
||||
* "esp <- task->rust_sp"
|
||||
*
|
||||
* this is the first instruction we 'ret' to after this glue,
|
||||
* because it is the first instruction following *any* native
|
||||
* call, and the task we are activating was descheduled
|
||||
* mid-native-call.
|
||||
*
|
||||
* Unfortunately for us, we have already restored esp from
|
||||
* task->rust_sp and are about to eat the 5 words off the top of
|
||||
* it.
|
||||
*
|
||||
*
|
||||
* | ... | <-- where esp will be once we restore + ret, below,
|
||||
* | retpc | and where we'd *like* task->rust_sp to wind up.
|
||||
* | ebp |
|
||||
* | edi |
|
||||
* | esi |
|
||||
* | ebx | <-- current task->rust_sp == current esp
|
||||
*
|
||||
*
|
||||
* This is a problem. If we return to "esp <- task->rust_sp" it
|
||||
* will push esp back down by 5 words. This manifests as a rust
|
||||
* stack that grows by 5 words on each yield/reactivate. Not
|
||||
* good.
|
||||
*
|
||||
* So what we do here is just adjust task->rust_sp up 5 words as
|
||||
* well, to mirror the movement in esp we're about to
|
||||
* perform. That way the "esp <- task->rust_sp" we 'ret' to below
|
||||
* will be a no-op. Esp won't move, and the task's stack won't
|
||||
* grow.
|
||||
*/
|
||||
addl $20, 16(%ecx)
|
||||
|
||||
/*
|
||||
* In most cases, the function we're returning to (activating)
|
||||
* will have saved any caller-saves before it yielded via native call,
|
||||
* so no work to do here. With one exception: when we're initially
|
||||
* activating, the task needs to be in the fastcall 2nd parameter
|
||||
* expected by the rust main function. That's edx.
|
||||
*/
|
||||
mov %ecx, %edx
|
||||
|
||||
popl %ebx
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %ebp
|
||||
ret
|
|
@ -11,11 +11,6 @@ rust_crate::get_relocation_diff() const {
|
|||
return ((uintptr_t)this - self_addr);
|
||||
}
|
||||
|
||||
activate_glue_ty
|
||||
rust_crate::get_activate_glue() const {
|
||||
return (activate_glue_ty) ((uintptr_t)this + activate_glue_off);
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
rust_crate::get_unwind_glue() const {
|
||||
return ((uintptr_t)this + unwind_glue_off);
|
||||
|
|
|
@ -48,10 +48,13 @@ rust_dom::~rust_dom() {
|
|||
}
|
||||
}
|
||||
|
||||
extern "C" void new_rust_activate_glue(rust_task *)
|
||||
asm("new_rust_activate_glue");
|
||||
|
||||
void
|
||||
rust_dom::activate(rust_task *task) {
|
||||
curr_task = task;
|
||||
root_crate->get_activate_glue()(task);
|
||||
new_rust_activate_glue(task);
|
||||
curr_task = NULL;
|
||||
}
|
||||
|
||||
|
@ -262,7 +265,6 @@ rust_dom::start_main_loop() {
|
|||
rust_timer timer(this);
|
||||
|
||||
DLOG(this, dom, "started domain loop");
|
||||
DLOG(this, dom, "activate glue: " PTR, root_crate->get_activate_glue());
|
||||
|
||||
while (number_of_live_tasks() > 0) {
|
||||
A(this, kernel->is_deadlocked() == false, "deadlock");
|
||||
|
|
|
@ -247,7 +247,6 @@ public:
|
|||
|
||||
uintptr_t get_image_base() const;
|
||||
ptrdiff_t get_relocation_diff() const;
|
||||
activate_glue_ty get_activate_glue() const;
|
||||
uintptr_t get_yield_glue() const;
|
||||
uintptr_t get_unwind_glue() const;
|
||||
uintptr_t get_gc_glue() const;
|
||||
|
|
Loading…
Add table
Reference in a new issue