Skip to content

Commit 33a2a66

Browse files
committed
---
yaml --- r: 6406 b: refs/heads/master c: 6072dda h: refs/heads/master v: v3
1 parent 921c1b8 commit 33a2a66

File tree

2 files changed

+99
-55
lines changed

2 files changed

+99
-55
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: d6ab8ebb07d0f6360d2aa32dec71c24a32c21ea6
2+
refs/heads/master: 6072ddad33e034a63bddd1ef577492b2842e8136

trunk/src/comp/middle/trans.rs

Lines changed: 98 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5366,7 +5366,7 @@ fn c_stack_tys(ccx: @crate_ctxt,
53665366
ty::ty_native_fn(_, arg_tys, ret_ty) {
53675367
let llargtys = type_of_explicit_args(ccx, sp, arg_tys);
53685368
check non_ty_var(ccx, ret_ty); // NDM does this truly hold?
5369-
let llretty = type_of_inner(ccx, sp, ret_ty);
5369+
let llretty = T_ptr(type_of_inner(ccx, sp, ret_ty));
53705370
let bundle_ty = T_struct(llargtys + [llretty]);
53715371
ret @{
53725372
arg_tys: llargtys,
@@ -5385,31 +5385,58 @@ fn c_stack_tys(ccx: @crate_ctxt,
53855385
}
53865386
}
53875387

5388-
// For c-stack ABIs, we must generate shim functions for making
5389-
// the call. These shim functions will unpack arguments out of
5390-
// a struct and then invoke the base function.
5388+
// For each native function F, we generate a wrapper function W and a shim
5389+
// function S that all work together. The wrapper function W is the function
5390+
// that other rust code actually invokes. Its job is to marshall the
5391+
// arguments into a struct. It then uses a small bit of assembly to switch
5392+
// over to the C stack and invoke the shim function. The shim function S then
5393+
// unpacks the arguments from the struct and invokes the actual function F
5394+
// according to its specified calling convention.
53915395
//
53925396
// Example: Given a native c-stack function F(x: X, y: Y) -> Z,
5393-
// we generate a shim function S that is something like:
5397+
// we generate a wrapper function W that looks like:
53945398
//
5395-
// void S(struct F_Args { X x; Y y; Z *z; } *args) {
5399+
// void W(Z* dest, void *env, X x, Y y) {
5400+
// struct { X x; Y y; Z *z; } args = { x, y, z };
5401+
// call_on_c_stack_shim(S, &args);
5402+
// }
5403+
//
5404+
// The shim function S then looks something like:
5405+
//
5406+
// void S(struct { X x; Y y; Z *z; } *args) {
53965407
// *args->z = F(args->x, args->y);
53975408
// }
53985409
//
5410+
// However, if the return type of F is dynamically sized or of aggregate type,
5411+
// the shim function looks like:
5412+
//
5413+
// void S(struct { X x; Y y; Z *z; } *args) {
5414+
// F(args->z, args->x, args->y);
5415+
// }
5416+
//
5417+
// Note: on i386, the layout of the args struct is generally the same as the
5418+
// desired layout of the arguments on the C stack. Therefore, we could use
5419+
// upcall_alloc_c_stack() to allocate the `args` structure and switch the
5420+
// stack pointer appropriately to avoid a round of copies. (In fact, the shim
5421+
// function itself is unnecessary). We used to do this, in fact, and will
5422+
// perhaps do so in the future.
53995423
fn trans_native_mod(lcx: @local_ctxt, native_mod: ast::native_mod) {
54005424
fn build_shim_fn(lcx: @local_ctxt,
54015425
native_item: @ast::native_item,
5402-
llshimfn: ValueRef,
5403-
cc: uint) {
5426+
tys: @c_stack_tys,
5427+
cc: uint) -> ValueRef {
54045428
let lname = link_name(native_item);
54055429
let ccx = lcx_ccx(lcx);
54065430
let span = native_item.span;
5407-
let id = native_item.id;
5408-
let tys = c_stack_tys(ccx, span, id);
54095431

54105432
// Declare the "prototype" for the base function F:
54115433
let llbasefn = decl_fn(ccx.llmod, lname, cc, tys.base_fn_ty);
54125434

5435+
// Create the shim function:
5436+
let shim_name = lname + "__c_stack_shim";
5437+
let llshimfn = decl_internal_cdecl_fn(
5438+
ccx.llmod, shim_name, tys.shim_fn_ty);
5439+
54135440
// Declare the body of the shim function:
54145441
let fcx = new_fn_ctxt(lcx, span, llshimfn);
54155442
let bcx = new_top_block_ctxt(fcx);
@@ -5423,11 +5450,39 @@ fn trans_native_mod(lcx: @local_ctxt, native_mod: ast::native_mod) {
54235450
i += 1u;
54245451
}
54255452

5426-
// Create the call itself:
5453+
// Create the call itself and store the return value:
54275454
let llretval = CallWithConv(bcx, llbasefn, llargvals, cc);
5428-
store_inbounds(bcx, llretval, llargbundle, [0, n as int]);
5455+
store_inbounds(bcx, llretval, llargbundle, [0, n as int, 0]);
5456+
5457+
// Finish up:
5458+
build_return(bcx);
5459+
finish_fn(fcx, lltop);
5460+
5461+
ret llshimfn;
5462+
}
5463+
5464+
fn build_wrap_fn(lcx: @local_ctxt,
5465+
native_item: @ast::native_item,
5466+
tys: @c_stack_tys,
5467+
llshimfn: ValueRef,
5468+
llwrapfn: ValueRef) {
5469+
let fcx = new_fn_ctxt(lcx, span, llshimfn);
5470+
let bcx = new_top_block_ctxt(fcx);
5471+
let lltop = bcx.llbb;
5472+
5473+
// Allocate the struct and write the arguments into it.
5474+
let llargbundle = alloca(bcx, tys.bundle_ty);
5475+
let imp = 2u, i = 0u, n = vec::len(tys.arg_tys);
5476+
while i < n {
5477+
let llargval = llvm::LLVMGetParam(llwrapfn, i + imp);
5478+
store_inbounds(bcx, llargval, llargbundle, [0, i as int]);
5479+
i += 1u;
5480+
}
5481+
let llretptr = llvm::LLVMGetParam(llwrapfn, 0);
5482+
store_inbounds(bcx, llretptr, llargbundle, [0, n as int]);
5483+
5484+
// Create call itself:
54295485

5430-
// Finish up.
54315486
build_return(bcx);
54325487
finish_fn(fcx, lltop);
54335488
}
@@ -5445,9 +5500,11 @@ fn trans_native_mod(lcx: @local_ctxt, native_mod: ast::native_mod) {
54455500
ast::native_item_ty. {}
54465501
ast::native_item_fn(fn_decl, _) {
54475502
let id = native_item.id;
5503+
let tys = c_stack_tys(ccx, span, id);
54485504
alt ccx.item_ids.find(id) {
5449-
some(llshimfn) {
5450-
build_shim_fn(lcx, native_item, llshimfn, cc);
5505+
some(llwrapfn) {
5506+
let llshimfn = build_shim_fn(lcx, native_item, cc, tys);
5507+
build_wrap_fn(lcx, native_item, tys, llshimfn, llwrapfn);
54515508
}
54525509

54535510
none. {
@@ -5548,14 +5605,6 @@ fn register_fn_full(ccx: @crate_ctxt, sp: span, path: [str], _flav: str,
55485605
let path = path;
55495606
let llfty =
55505607
type_of_fn_from_ty(ccx, sp, node_type, std::vec::len(ty_params));
5551-
alt ty::struct(ccx.tcx, node_type) {
5552-
ty::ty_fn(_, inputs, output, rs, _) {
5553-
check non_ty_var(ccx, output);
5554-
llfty = type_of_fn(ccx, sp, false, ast_util::ret_by_ref(rs), inputs,
5555-
output, vec::len(ty_params));
5556-
}
5557-
_ { ccx.sess.bug("register_fn(): fn item doesn't have fn type!"); }
5558-
}
55595608
let ps: str = mangle_exported_name(ccx, path, node_type);
55605609
let llfn: ValueRef = decl_cdecl_fn(ccx.llmod, ps, llfty);
55615610
ccx.item_ids.insert(node_id, llfn);
@@ -5715,33 +5764,6 @@ fn raw_native_fn_type(ccx: @crate_ctxt, sp: span, args: [ty::arg],
57155764
ret T_fn(type_of_explicit_args(ccx, sp, args), type_of(ccx, sp, ret_ty));
57165765
}
57175766

5718-
fn register_native_fn(ccx: @crate_ctxt, sp: span, _path: [str], name: str,
5719-
id: ast::node_id) {
5720-
let fn_type = node_id_type(ccx, id); // NB: has no type params
5721-
let abi = ty::ty_fn_abi(ccx.tcx, fn_type);
5722-
5723-
alt abi {
5724-
ast::native_abi_rust_intrinsic. {
5725-
let num_ty_param = native_fn_ty_param_count(ccx, id);
5726-
let fn_type = native_fn_wrapper_type(ccx, sp, num_ty_param, fn_type);
5727-
let ri_name = "rust_intrinsic_" + name;
5728-
let llnativefn = get_extern_fn(ccx.externs, ccx.llmod, ri_name,
5729-
lib::llvm::LLVMCCallConv, fn_type);
5730-
ccx.item_ids.insert(id, llnativefn);
5731-
ccx.item_symbols.insert(id, ri_name);
5732-
}
5733-
5734-
ast::native_abi_cdecl. | ast::native_abi_stdcall. {
5735-
let tys = c_stack_tys(ccx, sp, id);
5736-
let shim_name = name + "__c_stack_shim";
5737-
let llshimfn = decl_internal_cdecl_fn(
5738-
ccx.llmod, shim_name, tys.shim_fn_ty);
5739-
ccx.item_ids.insert(id, llshimfn);
5740-
ccx.item_symbols.insert(id, shim_name);
5741-
}
5742-
}
5743-
}
5744-
57455767
fn item_path(item: @ast::item) -> [str] { ret [item.ident]; }
57465768

57475769
fn link_name(i: @ast::native_item) -> str {
@@ -5751,14 +5773,36 @@ fn link_name(i: @ast::native_item) -> str {
57515773
}
57525774
}
57535775

5754-
57555776
fn collect_native_item(ccx: @crate_ctxt, i: @ast::native_item, &&pt: [str],
57565777
_v: vt<[str]>) {
57575778
alt i.node {
5758-
ast::native_item_fn(_, _) {
5779+
ast::native_item_fn(_, tps) {
57595780
if !ccx.obj_methods.contains_key(i.id) {
5760-
let name = link_name(i);
5761-
register_native_fn(ccx, i.span, pt, name, i.id);
5781+
// FIXME NDM abi should come from attr
5782+
let abi = ty::ty_fn_abi(ccx.tcx, fn_type);
5783+
5784+
alt abi {
5785+
ast::native_abi_rust_intrinsic. {
5786+
// For intrinsics: link the function directly to the intrinsic
5787+
// function itself.
5788+
let num_ty_param = vec::len(tps);
5789+
let node_type = node_id_type(ccx, id);
5790+
let fn_type = type_of_fn_from_ty(ccx, sp, node_type, num_ty_param);
5791+
let ri_name = "rust_intrinsic_" + name;
5792+
let llnativefn = get_extern_fn(ccx.externs, ccx.llmod, ri_name,
5793+
lib::llvm::LLVMCCallConv, fn_type);
5794+
ccx.item_ids.insert(id, llnativefn);
5795+
ccx.item_symbols.insert(id, ri_name);
5796+
}
5797+
5798+
ast::native_abi_cdecl. | ast::native_abi_stdcall. {
5799+
// For true external functions: create a rust wrapper
5800+
// and link to that. The rust wrapper will handle
5801+
// switching to the C stack.
5802+
let new_pt = pt + [i.ident];
5803+
register_fn(ccx, i.span, new_pt, "native fn", tps, i.id);
5804+
}
5805+
}
57625806
}
57635807
}
57645808
_ { }

0 commit comments

Comments
 (0)