rustc: Translate calls on the C stack

This commit is contained in:
Patrick Walton 2011-09-29 17:33:41 -07:00
parent f22601321f
commit a5b422fe6b

View file

@ -3897,6 +3897,11 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
// with trans_call.
let tcx = bcx_tcx(in_cx);
let fn_expr_ty = ty::expr_ty(tcx, f);
if check type_is_native_fn_on_c_stack(tcx, fn_expr_ty) {
ret trans_c_stack_native_call(in_cx, f, args);
}
let by_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(tcx, fn_expr_ty));
let cx = new_scope_block_ctxt(in_cx, "call");
let f_res = trans_callee(cx, f);
@ -3977,6 +3982,63 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
ret {res: rslt(bcx, retval), by_ref: by_ref};
}
// Translates a native call on the C stack. Calls into the runtime to perform
// the stack switching operation.
fn trans_c_stack_native_call(bcx: @block_ctxt, f: @ast::expr,
args: [@ast::expr])
-> {res: result, by_ref: bool} {
let ccx = bcx_ccx(bcx);
let f_res = trans_callee(bcx, f);
let llfn = f_res.val; bcx = f_res.bcx;
// Translate the callee.
let fn_ty = ty::expr_ty(bcx_tcx(bcx), f);
let fn_arg_tys = ty::ty_fn_args(bcx_tcx(bcx), fn_ty);
// Translate arguments.
let (to_zero, to_revoke) = ([], []);
let llargs = vec::map2({ |ty_arg, arg|
let arg_ty = ty_arg.ty;
check type_has_static_size(ccx, arg_ty);
let llargty = type_of(ccx, f.span, arg_ty);
let r = trans_arg_expr(bcx, ty_arg, llargty, to_zero, to_revoke, arg);
let llargval = r.val; bcx = r.bcx;
{ llval: llargval, llty: llargty }
}, fn_arg_tys, args);
// Allocate the argument bundle.
let llargbundlety = T_struct(vec::map({ |r| r.llty }, llargs));
let llargbundlesz = llsize_of(llargbundlety);
let llrawargbundle = Call(bcx, ccx.upcalls.alloc_c_stack,
[llargbundlesz]);
let llargbundle = PointerCast(bcx, llrawargbundle, T_ptr(llargbundlety));
// Copy in arguments.
log_err ("bundle type", val_str(ccx.tn, llargbundle));
vec::eachi({ |llarg, i|
// FIXME: This load is unfortunate.
let llargval = Load(bcx, llarg.llval);
log_err ("llarg type", val_str(ccx.tn, llargval), i);
store_inbounds(bcx, llargval, llargbundle, [C_int(0), C_uint(i)]);
}, llargs);
// Call.
// TODO: Invoke instead.
let llrawretval = Call(bcx, ccx.upcalls.call_c_stack,
[llfn, llrawargbundle]);
// Cast return type.
let ret_ty = ty::ty_fn_ret(bcx_tcx(bcx), fn_ty);
check type_has_static_size(ccx, ret_ty);
let llretty = type_of(ccx, f.span, ret_ty);
let llretval = TruncOrBitCast(bcx, llrawretval, llretty);
// Forget about anything we moved out.
bcx = zero_and_revoke(bcx, to_zero, to_revoke);
ret {res: rslt(bcx, llretval), by_ref: false};
}
fn zero_and_revoke(bcx: @block_ctxt,
to_zero: [{v: ValueRef, t: ty::t}],
to_revoke: [{v: ValueRef, t: ty::t}]) -> @block_ctxt {
@ -5662,7 +5724,7 @@ fn native_fn_ty_param_count(cx: @crate_ctxt, id: ast::node_id) -> uint {
ret count;
}
fn native_abi_requires_pair(abi: ast::native_abi) -> bool {
pure fn native_abi_requires_pair(abi: ast::native_abi) -> bool {
alt abi {
ast::native_abi_rust. | ast::native_abi_cdecl. |
ast::native_abi_llvm. | ast::native_abi_rust_intrinsic. |
@ -5671,6 +5733,13 @@ fn native_abi_requires_pair(abi: ast::native_abi) -> bool {
}
}
pure fn type_is_native_fn_on_c_stack(tcx: ty::ctxt, t: ty::t) -> bool {
alt ty::struct(tcx, t) {
ty::ty_native_fn(abi, _, _) { ret !native_abi_requires_pair(abi); }
_ { ret false; }
}
}
fn native_fn_wrapper_type(cx: @crate_ctxt, sp: span, ty_param_count: uint,
x: ty::t) -> TypeRef {
alt ty::struct(cx.tcx, x) {
@ -5690,32 +5759,8 @@ fn raw_native_fn_type(ccx: @crate_ctxt, sp: span, args: [ty::arg],
fn register_native_fn(ccx: @crate_ctxt, sp: span, path: [str], name: str,
id: ast::node_id) {
let path = path;
let num_ty_param = native_fn_ty_param_count(ccx, id);
// Declare the wrapper.
let t = node_id_type(ccx, id);
let wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t);
let ps: str = mangle_exported_name(ccx, path, node_id_type(ccx, id));
let wrapper_fn = decl_cdecl_fn(ccx.llmod, ps, wrapper_type);
ccx.item_ids.insert(id, wrapper_fn);
ccx.item_symbols.insert(id, ps);
// Build the wrapper.
let fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, wrapper_fn);
let bcx = new_top_block_ctxt(fcx);
let lltop = bcx.llbb;
// Declare the function itself.
let fn_type = node_id_type(ccx, id); // NB: has no type params
let abi = ty::ty_fn_abi(ccx.tcx, fn_type);
// FIXME: If the returned type is not nil, then we assume it's 32 bits
// wide. This is obviously wildly unsafe. We should have a better FFI
// that allows types of different sizes to be returned.
let rty = ty::ty_fn_ret(ccx.tcx, fn_type);
let rty_is_nil = ty::type_is_nil(ccx.tcx, rty);
let pass_task;
let uses_retptr;
@ -5747,10 +5792,37 @@ fn register_native_fn(ccx: @crate_ctxt, sp: span, path: [str], name: str,
cast_to_i32 = true;
}
ast::native_abi_c_stack_cdecl. {
fail "C stack cdecl ABI shouldn't have a wrapper";
let llfn = decl_cdecl_fn(ccx.llmod, name, T_fn([], T_void()));
ccx.item_ids.insert(id, llfn);
ccx.item_symbols.insert(id, name);
ret;
}
}
let path = path;
let num_ty_param = native_fn_ty_param_count(ccx, id);
// Declare the wrapper.
let t = node_id_type(ccx, id);
let wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t);
let ps: str = mangle_exported_name(ccx, path, node_id_type(ccx, id));
let wrapper_fn = decl_cdecl_fn(ccx.llmod, ps, wrapper_type);
ccx.item_ids.insert(id, wrapper_fn);
ccx.item_symbols.insert(id, ps);
// Build the wrapper.
let fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, wrapper_fn);
let bcx = new_top_block_ctxt(fcx);
let lltop = bcx.llbb;
// Declare the function itself.
// FIXME: If the returned type is not nil, then we assume it's 32 bits
// wide. This is obviously wildly unsafe. We should have a better FFI
// that allows types of different sizes to be returned.
let rty = ty::ty_fn_ret(ccx.tcx, fn_type);
let rty_is_nil = ty::type_is_nil(ccx.tcx, rty);
let lltaskptr;
if cast_to_i32 {
lltaskptr = vp2i(bcx, fcx.lltaskptr);