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_LL := rt/new_exit.ll
|
||||||
|
|
||||||
|
RUNTIME_S := rt/activate_glue.s
|
||||||
|
|
||||||
RUNTIME_HDR := rt/globals.h \
|
RUNTIME_HDR := rt/globals.h \
|
||||||
rt/rust.h \
|
rt/rust.h \
|
||||||
rt/rust_dwarf.h \
|
rt/rust_dwarf.h \
|
||||||
|
@ -65,7 +67,7 @@ RUNTIME_HDR := rt/globals.h \
|
||||||
|
|
||||||
RUNTIME_DEF := rt/rustrt$(CFG_DEF_SUFFIX)
|
RUNTIME_DEF := rt/rustrt$(CFG_DEF_SUFFIX)
|
||||||
RUNTIME_INCS := -I $(S)src/rt/isaac -I $(S)src/rt/uthash
|
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)
|
RUNTIME_LIBS := $(CFG_GCCISH_POST_LIB_FLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,6 +75,10 @@ rt/%.o: rt/%.cpp $(MKFILES)
|
||||||
@$(call E, compile: $@)
|
@$(call E, compile: $@)
|
||||||
$(Q)$(call CFG_COMPILE_C, $@, $(RUNTIME_INCS)) $<
|
$(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)
|
rt/%.o: rt/%.ll $(MKFILES)
|
||||||
@$(call E, llc: $@)
|
@$(call E, llc: $@)
|
||||||
$(Q)$(LLC) -filetype=obj -relocation-model=pic -march=x86 -o $@ $<
|
$(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);
|
ret prefix + util::common::istr(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate_glue_name() -> str {
|
|
||||||
ret "rust_activate_glue";
|
|
||||||
}
|
|
||||||
|
|
||||||
fn yield_glue_name() -> str {
|
fn yield_glue_name() -> str {
|
||||||
ret "rust_yield_glue";
|
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.
|
/* More glue code, this time the 'bottom half' of yielding.
|
||||||
*
|
*
|
||||||
* We arrived here because an native call decided to deschedule the
|
* We arrived here because an native call decided to deschedule the
|
||||||
|
@ -306,12 +220,8 @@ fn get_module_asm() -> str {
|
||||||
|
|
||||||
auto glues =
|
auto glues =
|
||||||
[decl_glue(align, prefix,
|
[decl_glue(align, prefix,
|
||||||
abi::activate_glue_name(),
|
abi::yield_glue_name(),
|
||||||
rust_activate_glue()),
|
rust_yield_glue())]
|
||||||
|
|
||||||
decl_glue(align, prefix,
|
|
||||||
abi::yield_glue_name(),
|
|
||||||
rust_yield_glue())]
|
|
||||||
|
|
||||||
+ vec::init_fn[str](bind decl_native_glue(align, prefix,
|
+ vec::init_fn[str](bind decl_native_glue(align, prefix,
|
||||||
abi::ngt_rust, _), (abi::n_native_glues + 1) as uint)
|
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 derived_tydesc_info = rec(ValueRef lltydesc, bool escapes);
|
||||||
|
|
||||||
type glue_fns = rec(ValueRef activate_glue,
|
type glue_fns = rec(ValueRef yield_glue,
|
||||||
ValueRef yield_glue,
|
|
||||||
vec[ValueRef] native_glues_rust,
|
vec[ValueRef] native_glues_rust,
|
||||||
vec[ValueRef] native_glues_pure_rust,
|
vec[ValueRef] native_glues_pure_rust,
|
||||||
vec[ValueRef] native_glues_cdecl,
|
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 crate_addr = p2i(crate_ptr);
|
||||||
|
|
||||||
let ValueRef activate_glue_off =
|
|
||||||
llvm::LLVMConstSub(p2i(glues.activate_glue), crate_addr);
|
|
||||||
|
|
||||||
let ValueRef yield_glue_off =
|
let ValueRef yield_glue_off =
|
||||||
llvm::LLVMConstSub(p2i(glues.yield_glue), crate_addr);
|
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()), // size_t debug_abbrev_sz
|
||||||
C_null(T_int()), // ptrdiff_t debug_info_off
|
C_null(T_int()), // ptrdiff_t debug_info_off
|
||||||
C_null(T_int()), // size_t debug_info_sz
|
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
|
yield_glue_off, // size_t yield_glue_off
|
||||||
C_null(T_int()), // size_t unwind_glue_off
|
C_null(T_int()), // size_t unwind_glue_off
|
||||||
C_null(T_int()), // size_t gc_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 {
|
fn make_glues(ModuleRef llmod, &type_names tn) -> @glue_fns {
|
||||||
ret @rec(activate_glue = decl_glue(llmod, tn, abi::activate_glue_name()),
|
ret @rec(yield_glue = decl_glue(llmod, tn, abi::yield_glue_name()),
|
||||||
yield_glue = decl_glue(llmod, tn, abi::yield_glue_name()),
|
|
||||||
|
|
||||||
native_glues_rust =
|
native_glues_rust =
|
||||||
vec::init_fn[ValueRef](bind decl_native_glue(llmod, tn,
|
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);
|
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
|
uintptr_t
|
||||||
rust_crate::get_unwind_glue() const {
|
rust_crate::get_unwind_glue() const {
|
||||||
return ((uintptr_t)this + unwind_glue_off);
|
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
|
void
|
||||||
rust_dom::activate(rust_task *task) {
|
rust_dom::activate(rust_task *task) {
|
||||||
curr_task = task;
|
curr_task = task;
|
||||||
root_crate->get_activate_glue()(task);
|
new_rust_activate_glue(task);
|
||||||
curr_task = NULL;
|
curr_task = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +265,6 @@ rust_dom::start_main_loop() {
|
||||||
rust_timer timer(this);
|
rust_timer timer(this);
|
||||||
|
|
||||||
DLOG(this, dom, "started domain loop");
|
DLOG(this, dom, "started domain loop");
|
||||||
DLOG(this, dom, "activate glue: " PTR, root_crate->get_activate_glue());
|
|
||||||
|
|
||||||
while (number_of_live_tasks() > 0) {
|
while (number_of_live_tasks() > 0) {
|
||||||
A(this, kernel->is_deadlocked() == false, "deadlock");
|
A(this, kernel->is_deadlocked() == false, "deadlock");
|
||||||
|
|
|
@ -247,7 +247,6 @@ public:
|
||||||
|
|
||||||
uintptr_t get_image_base() const;
|
uintptr_t get_image_base() const;
|
||||||
ptrdiff_t get_relocation_diff() const;
|
ptrdiff_t get_relocation_diff() const;
|
||||||
activate_glue_ty get_activate_glue() const;
|
|
||||||
uintptr_t get_yield_glue() const;
|
uintptr_t get_yield_glue() const;
|
||||||
uintptr_t get_unwind_glue() const;
|
uintptr_t get_unwind_glue() const;
|
||||||
uintptr_t get_gc_glue() const;
|
uintptr_t get_gc_glue() const;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue