Trans nomenclature tidy-up: upcall vs. native vs. extern.
This commit is contained in:
parent
b2427509e2
commit
661f1c541e
3 changed files with 76 additions and 56 deletions
|
@ -58,7 +58,7 @@ const int closure_elt_ty_params = 3;
|
||||||
|
|
||||||
const int worst_case_glue_call_args = 7;
|
const int worst_case_glue_call_args = 7;
|
||||||
|
|
||||||
const int n_upcall_glues = 7;
|
const int n_native_glues = 7;
|
||||||
|
|
||||||
const int abi_x86_rustboot_cdecl = 1;
|
const int abi_x86_rustboot_cdecl = 1;
|
||||||
const int abi_x86_rustc_fastcall = 2;
|
const int abi_x86_rustc_fastcall = 2;
|
||||||
|
@ -75,11 +75,11 @@ fn vec_append_glue_name() -> str {
|
||||||
ret "rust_vec_append_glue";
|
ret "rust_vec_append_glue";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upcall_glue_name(int n, bool pass_task) -> str {
|
fn native_glue_name(int n, bool pass_task) -> str {
|
||||||
if (pass_task) {
|
if (pass_task) {
|
||||||
ret "rust_upcall_rust_" + util.common.istr(n);
|
ret "rust_native_rust_" + util.common.istr(n);
|
||||||
}
|
}
|
||||||
ret "rust_upcall_cdecl_" + util.common.istr(n);
|
ret "rust_native_cdecl_" + util.common.istr(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate_glue_name() -> str {
|
fn activate_glue_name() -> str {
|
||||||
|
|
|
@ -90,7 +90,7 @@ fn rust_activate_glue() -> vec[str] {
|
||||||
* start doing whatever the first instruction says. Probably
|
* start doing whatever the first instruction says. Probably
|
||||||
* saving registers and starting to establish a frame. Harmless
|
* saving registers and starting to establish a frame. Harmless
|
||||||
* stuff, doesn't look at task->rust_sp again except when it
|
* stuff, doesn't look at task->rust_sp again except when it
|
||||||
* clobbers it during a later upcall.
|
* clobbers it during a later native call.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 2. We are resuming a task that was descheduled by the yield glue
|
* 2. We are resuming a task that was descheduled by the yield glue
|
||||||
|
@ -100,8 +100,9 @@ fn rust_activate_glue() -> vec[str] {
|
||||||
* "esp <- task->rust_sp"
|
* "esp <- task->rust_sp"
|
||||||
*
|
*
|
||||||
* this is the first instruction we 'ret' to after this glue,
|
* this is the first instruction we 'ret' to after this glue,
|
||||||
* because it is the first instruction following *any* upcall,
|
* because it is the first instruction following *any* native
|
||||||
* and the task we are activating was descheduled mid-upcall.
|
* call, and the task we are activating was descheduled
|
||||||
|
* mid-native-call.
|
||||||
*
|
*
|
||||||
* Unfortunately for us, we have already restored esp from
|
* Unfortunately for us, we have already restored esp from
|
||||||
* task->rust_sp and are about to eat the 5 words off the top of
|
* task->rust_sp and are about to eat the 5 words off the top of
|
||||||
|
@ -132,7 +133,7 @@ fn rust_activate_glue() -> vec[str] {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In most cases, the function we're returning to (activating)
|
* In most cases, the function we're returning to (activating)
|
||||||
* will have saved any caller-saves before it yielded via upcalling,
|
* 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
|
* so no work to do here. With one exception: when we're initially
|
||||||
* activating, the task needs to be in the fastcall 2nd parameter
|
* activating, the task needs to be in the fastcall 2nd parameter
|
||||||
* expected by the rust main function. That's edx.
|
* expected by the rust main function. That's edx.
|
||||||
|
@ -145,14 +146,14 @@ fn rust_activate_glue() -> vec[str] {
|
||||||
|
|
||||||
/* 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 upcall decided to deschedule the
|
* We arrived here because an native call decided to deschedule the
|
||||||
* running task. So the upcall's return address got patched to the
|
* running task. So the native call's return address got patched to the
|
||||||
* first instruction of this glue code.
|
* first instruction of this glue code.
|
||||||
*
|
*
|
||||||
* When the upcall does 'ret' it will come here, and its esp will be
|
* When the native call does 'ret' it will come here, and its esp will be
|
||||||
* pointing to the last argument pushed on the C stack before making
|
* pointing to the last argument pushed on the C stack before making
|
||||||
* the upcall: the 0th argument to the upcall, which is always the
|
* the native call: the 0th argument to the native call, which is always
|
||||||
* task ptr performing the upcall. That's where we take over.
|
* the task ptr performing the native call. That's where we take over.
|
||||||
*
|
*
|
||||||
* Our goal is to complete the descheduling
|
* Our goal is to complete the descheduling
|
||||||
*
|
*
|
||||||
|
@ -179,7 +180,7 @@ fn rust_yield_glue() -> vec[str] {
|
||||||
+ vec("ret");
|
+ vec("ret");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upcall_glue(int n_args, bool pass_task) -> vec[str] {
|
fn native_glue(int n_args, bool pass_task) -> vec[str] {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 0, 4, 8, 12 are callee-saves
|
* 0, 4, 8, 12 are callee-saves
|
||||||
|
@ -242,11 +243,11 @@ fn decl_glue(int align, str prefix, str name, vec[str] insns) -> str {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn decl_upcall_glue(int align, str prefix, bool pass_task, uint n) -> str {
|
fn decl_native_glue(int align, str prefix, bool pass_task, uint n) -> str {
|
||||||
let int i = n as int;
|
let int i = n as int;
|
||||||
ret decl_glue(align, prefix,
|
ret decl_glue(align, prefix,
|
||||||
abi.upcall_glue_name(i, pass_task),
|
abi.native_glue_name(i, pass_task),
|
||||||
upcall_glue(i, pass_task));
|
native_glue(i, pass_task));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_symbol_prefix() -> str {
|
fn get_symbol_prefix() -> str {
|
||||||
|
@ -272,10 +273,10 @@ fn get_module_asm() -> str {
|
||||||
abi.yield_glue_name(),
|
abi.yield_glue_name(),
|
||||||
rust_yield_glue()))
|
rust_yield_glue()))
|
||||||
|
|
||||||
+ _vec.init_fn[str](bind decl_upcall_glue(align, prefix, true, _),
|
+ _vec.init_fn[str](bind decl_native_glue(align, prefix, true, _),
|
||||||
(abi.n_upcall_glues + 1) as uint)
|
(abi.n_native_glues + 1) as uint)
|
||||||
+ _vec.init_fn[str](bind decl_upcall_glue(align, prefix, false, _),
|
+ _vec.init_fn[str](bind decl_native_glue(align, prefix, false, _),
|
||||||
(abi.n_upcall_glues + 1) as uint);
|
(abi.n_native_glues + 1) as uint);
|
||||||
|
|
||||||
|
|
||||||
ret _str.connect(glues, "\n\n");
|
ret _str.connect(glues, "\n\n");
|
||||||
|
|
|
@ -53,8 +53,8 @@ state obj namegen(mutable int i) {
|
||||||
type glue_fns = rec(ValueRef activate_glue,
|
type glue_fns = rec(ValueRef activate_glue,
|
||||||
ValueRef yield_glue,
|
ValueRef yield_glue,
|
||||||
ValueRef exit_task_glue,
|
ValueRef exit_task_glue,
|
||||||
vec[ValueRef] upcall_glues_rust,
|
vec[ValueRef] native_glues_rust,
|
||||||
vec[ValueRef] upcall_glues_cdecl,
|
vec[ValueRef] native_glues_cdecl,
|
||||||
ValueRef no_op_type_glue,
|
ValueRef no_op_type_glue,
|
||||||
ValueRef memcpy_glue,
|
ValueRef memcpy_glue,
|
||||||
ValueRef bzero_glue,
|
ValueRef bzero_glue,
|
||||||
|
@ -64,12 +64,31 @@ type tydesc_info = rec(ValueRef tydesc,
|
||||||
ValueRef take_glue,
|
ValueRef take_glue,
|
||||||
ValueRef drop_glue);
|
ValueRef drop_glue);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A note on nomenclature of linking: "upcall", "extern" and "native".
|
||||||
|
*
|
||||||
|
* An "extern" is an LLVM symbol we wind up emitting an undefined external
|
||||||
|
* reference to. This means "we don't have the thing in this compilation unit,
|
||||||
|
* please make sure you link it in at runtime". This could be a reference to
|
||||||
|
* C code found in a C library, or rust code found in a rust crate.
|
||||||
|
*
|
||||||
|
* A "native" is a combination of an extern that references C code, plus a
|
||||||
|
* glue-code stub that "looks like" a rust function, emitted here, plus a
|
||||||
|
* generic N-ary bit of asm glue (found over in back/x86.rs) that performs a
|
||||||
|
* control transfer into C from rust. Natives may be normal C library code.
|
||||||
|
*
|
||||||
|
* An upcall is a native call generated by the compiler (not corresponding to
|
||||||
|
* any user-written call in the code) into librustrt, to perform some helper
|
||||||
|
* task such as bringing a task to life, allocating memory, etc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
state type crate_ctxt = rec(session.session sess,
|
state type crate_ctxt = rec(session.session sess,
|
||||||
ModuleRef llmod,
|
ModuleRef llmod,
|
||||||
target_data td,
|
target_data td,
|
||||||
type_names tn,
|
type_names tn,
|
||||||
ValueRef crate_ptr,
|
ValueRef crate_ptr,
|
||||||
hashmap[str, ValueRef] upcalls,
|
hashmap[str, ValueRef] externs,
|
||||||
hashmap[str, ValueRef] intrinsics,
|
hashmap[str, ValueRef] intrinsics,
|
||||||
hashmap[str, ValueRef] item_names,
|
hashmap[str, ValueRef] item_names,
|
||||||
hashmap[ast.def_id, ValueRef] item_ids,
|
hashmap[ast.def_id, ValueRef] item_ids,
|
||||||
|
@ -852,14 +871,14 @@ fn decl_glue(ModuleRef llmod, type_names tn, str s) -> ValueRef {
|
||||||
ret decl_cdecl_fn(llmod, s, T_fn(vec(T_taskptr(tn)), T_void()));
|
ret decl_cdecl_fn(llmod, s, T_fn(vec(T_taskptr(tn)), T_void()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decl_upcall_glue(ModuleRef llmod, type_names tn,
|
fn decl_native_glue(ModuleRef llmod, type_names tn,
|
||||||
bool pass_task, uint _n) -> ValueRef {
|
bool pass_task, uint _n) -> ValueRef {
|
||||||
// It doesn't actually matter what type we come up with here, at the
|
// It doesn't actually matter what type we come up with here, at the
|
||||||
// moment, as we cast the upcall function pointers to int before passing
|
// moment, as we cast the native function pointers to int before passing
|
||||||
// them to the indirect upcall-invocation glue. But eventually we'd like
|
// them to the indirect native-invocation glue. But eventually we'd like
|
||||||
// to call them directly, once we have a calling convention worked out.
|
// to call them directly, once we have a calling convention worked out.
|
||||||
let int n = _n as int;
|
let int n = _n as int;
|
||||||
let str s = abi.upcall_glue_name(n, pass_task);
|
let str s = abi.native_glue_name(n, pass_task);
|
||||||
let vec[TypeRef] args = vec(T_int()); // callee
|
let vec[TypeRef] args = vec(T_int()); // callee
|
||||||
if (!pass_task) {
|
if (!pass_task) {
|
||||||
args += vec(T_int()); // taskptr, will not be passed
|
args += vec(T_int()); // taskptr, will not be passed
|
||||||
|
@ -869,15 +888,15 @@ fn decl_upcall_glue(ModuleRef llmod, type_names tn,
|
||||||
ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
|
ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_upcall(&hashmap[str, ValueRef] upcalls,
|
fn get_extern(&hashmap[str, ValueRef] externs,
|
||||||
ModuleRef llmod, str name, int n_args) -> ValueRef {
|
ModuleRef llmod, str name, int n_args) -> ValueRef {
|
||||||
if (upcalls.contains_key(name)) {
|
if (externs.contains_key(name)) {
|
||||||
ret upcalls.get(name);
|
ret externs.get(name);
|
||||||
}
|
}
|
||||||
auto inputs = _vec.init_elt[TypeRef](T_int(), n_args as uint);
|
auto inputs = _vec.init_elt[TypeRef](T_int(), n_args as uint);
|
||||||
auto output = T_int();
|
auto output = T_int();
|
||||||
auto f = decl_cdecl_fn(llmod, name, T_fn(inputs, output));
|
auto f = decl_cdecl_fn(llmod, name, T_fn(inputs, output));
|
||||||
upcalls.insert(name, f);
|
externs.insert(name, f);
|
||||||
ret f;
|
ret f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -885,26 +904,26 @@ fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
|
||||||
auto cxx = cx.fcx.ccx;
|
auto cxx = cx.fcx.ccx;
|
||||||
auto lltaskptr = cx.build.PtrToInt(cx.fcx.lltaskptr, T_int());
|
auto lltaskptr = cx.build.PtrToInt(cx.fcx.lltaskptr, T_int());
|
||||||
auto args2 = vec(lltaskptr) + args;
|
auto args2 = vec(lltaskptr) + args;
|
||||||
auto t = trans_upcall2(cx.build, cxx.glues, lltaskptr,
|
auto t = trans_native(cx.build, cxx.glues, lltaskptr,
|
||||||
cxx.upcalls, cxx.tn, cxx.llmod, name, true, args2);
|
cxx.externs, cxx.tn, cxx.llmod, name, true, args2);
|
||||||
ret res(cx, t);
|
ret res(cx, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_upcall2(builder b, @glue_fns glues, ValueRef lltaskptr,
|
fn trans_native(builder b, @glue_fns glues, ValueRef lltaskptr,
|
||||||
&hashmap[str, ValueRef] upcalls,
|
&hashmap[str, ValueRef] externs,
|
||||||
type_names tn, ModuleRef llmod, str name,
|
type_names tn, ModuleRef llmod, str name,
|
||||||
bool pass_task, vec[ValueRef] args) -> ValueRef {
|
bool pass_task, vec[ValueRef] args) -> ValueRef {
|
||||||
let int n = (_vec.len[ValueRef](args) as int);
|
let int n = (_vec.len[ValueRef](args) as int);
|
||||||
let ValueRef llupcall = get_upcall(upcalls, llmod, name, n);
|
let ValueRef llnative = get_extern(externs, llmod, name, n);
|
||||||
llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());
|
llnative = llvm.LLVMConstPointerCast(llnative, T_int());
|
||||||
|
|
||||||
let ValueRef llglue;
|
let ValueRef llglue;
|
||||||
if (pass_task) {
|
if (pass_task) {
|
||||||
llglue = glues.upcall_glues_rust.(n);
|
llglue = glues.native_glues_rust.(n);
|
||||||
} else {
|
} else {
|
||||||
llglue = glues.upcall_glues_cdecl.(n);
|
llglue = glues.native_glues_cdecl.(n);
|
||||||
}
|
}
|
||||||
let vec[ValueRef] call_args = vec(llupcall);
|
let vec[ValueRef] call_args = vec(llnative);
|
||||||
|
|
||||||
if (!pass_task) {
|
if (!pass_task) {
|
||||||
call_args += vec(lltaskptr);
|
call_args += vec(lltaskptr);
|
||||||
|
@ -5771,8 +5790,8 @@ fn decl_native_fn_and_pair(@crate_ctxt cx,
|
||||||
arg_n += 1u;
|
arg_n += 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto r = trans_upcall2(bcx.build, cx.glues, lltaskptr, cx.upcalls, cx.tn,
|
auto r = trans_native(bcx.build, cx.glues, lltaskptr, cx.externs, cx.tn,
|
||||||
cx.llmod, name, pass_task, call_args);
|
cx.llmod, name, pass_task, call_args);
|
||||||
auto rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));
|
auto rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));
|
||||||
bcx.build.Store(r, rptr);
|
bcx.build.Store(r, rptr);
|
||||||
bcx.build.RetVoid();
|
bcx.build.RetVoid();
|
||||||
|
@ -5967,7 +5986,7 @@ fn i2p(ValueRef v, TypeRef t) -> ValueRef {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_exit_task_glue(@glue_fns glues,
|
fn trans_exit_task_glue(@glue_fns glues,
|
||||||
&hashmap[str, ValueRef] upcalls,
|
&hashmap[str, ValueRef] externs,
|
||||||
type_names tn, ModuleRef llmod) {
|
type_names tn, ModuleRef llmod) {
|
||||||
let vec[TypeRef] T_args = vec();
|
let vec[TypeRef] T_args = vec();
|
||||||
let vec[ValueRef] V_args = vec();
|
let vec[ValueRef] V_args = vec();
|
||||||
|
@ -5979,8 +5998,8 @@ fn trans_exit_task_glue(@glue_fns glues,
|
||||||
auto build = new_builder(entrybb);
|
auto build = new_builder(entrybb);
|
||||||
auto tptr = build.PtrToInt(lltaskptr, T_int());
|
auto tptr = build.PtrToInt(lltaskptr, T_int());
|
||||||
auto V_args2 = vec(tptr) + V_args;
|
auto V_args2 = vec(tptr) + V_args;
|
||||||
trans_upcall2(build, glues, lltaskptr,
|
trans_native(build, glues, lltaskptr,
|
||||||
upcalls, tn, llmod, "upcall_exit", true, V_args2);
|
externs, tn, llmod, "upcall_exit", true, V_args2);
|
||||||
build.RetVoid();
|
build.RetVoid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6415,7 +6434,7 @@ fn make_glues(ModuleRef llmod, type_names tn) -> @glue_fns {
|
||||||
yield_glue = decl_glue(llmod, tn, abi.yield_glue_name()),
|
yield_glue = decl_glue(llmod, tn, abi.yield_glue_name()),
|
||||||
/*
|
/*
|
||||||
* Note: the signature passed to decl_cdecl_fn here looks unusual
|
* Note: the signature passed to decl_cdecl_fn here looks unusual
|
||||||
* because it is. It corresponds neither to an upcall signature
|
* because it is. It corresponds neither to a native signature
|
||||||
* nor a normal rust-ABI signature. In fact it is a fake
|
* nor a normal rust-ABI signature. In fact it is a fake
|
||||||
* signature, that exists solely to acquire the task pointer as
|
* signature, that exists solely to acquire the task pointer as
|
||||||
* an argument to the upcall. It so happens that the runtime sets
|
* an argument to the upcall. It so happens that the runtime sets
|
||||||
|
@ -6430,14 +6449,14 @@ fn make_glues(ModuleRef llmod, type_names tn) -> @glue_fns {
|
||||||
T_taskptr(tn)),
|
T_taskptr(tn)),
|
||||||
T_void())),
|
T_void())),
|
||||||
|
|
||||||
upcall_glues_rust =
|
native_glues_rust =
|
||||||
_vec.init_fn[ValueRef](bind decl_upcall_glue(llmod, tn, true,
|
_vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn, true,
|
||||||
_),
|
_),
|
||||||
abi.n_upcall_glues + 1 as uint),
|
abi.n_native_glues + 1 as uint),
|
||||||
upcall_glues_cdecl =
|
native_glues_cdecl =
|
||||||
_vec.init_fn[ValueRef](bind decl_upcall_glue(llmod, tn, false,
|
_vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn, false,
|
||||||
_),
|
_),
|
||||||
abi.n_upcall_glues + 1 as uint),
|
abi.n_native_glues + 1 as uint),
|
||||||
no_op_type_glue = decl_no_op_type_glue(llmod, tn),
|
no_op_type_glue = decl_no_op_type_glue(llmod, tn),
|
||||||
memcpy_glue = decl_memcpy_glue(llmod),
|
memcpy_glue = decl_memcpy_glue(llmod),
|
||||||
bzero_glue = decl_bzero_glue(llmod),
|
bzero_glue = decl_bzero_glue(llmod),
|
||||||
|
@ -6503,7 +6522,7 @@ fn trans_crate(session.session sess, @ast.crate crate, str output,
|
||||||
td = td,
|
td = td,
|
||||||
tn = tn,
|
tn = tn,
|
||||||
crate_ptr = crate_ptr,
|
crate_ptr = crate_ptr,
|
||||||
upcalls = new_str_hash[ValueRef](),
|
externs = new_str_hash[ValueRef](),
|
||||||
intrinsics = intrinsics,
|
intrinsics = intrinsics,
|
||||||
item_names = new_str_hash[ValueRef](),
|
item_names = new_str_hash[ValueRef](),
|
||||||
item_ids = new_def_hash[ValueRef](),
|
item_ids = new_def_hash[ValueRef](),
|
||||||
|
|
Loading…
Reference in a new issue