Skip to content

Commit 303f650

Browse files
committed
Issue #3678: Remove wrappers and call foreign functions directly
1 parent c178b52 commit 303f650

28 files changed

+1690
-1559
lines changed

src/librustc/back/upcall.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ use lib::llvm::{ModuleRef, ValueRef};
1616

1717
pub struct Upcalls {
1818
trace: ValueRef,
19-
call_shim_on_c_stack: ValueRef,
20-
call_shim_on_rust_stack: ValueRef,
2119
rust_personality: ValueRef,
2220
reset_stack_limit: ValueRef
2321
}
@@ -47,9 +45,6 @@ pub fn declare_upcalls(targ_cfg: @session::config, llmod: ModuleRef) -> @Upcalls
4745

4846
@Upcalls {
4947
trace: upcall!(fn trace(opaque_ptr, opaque_ptr, int_ty) -> Type::void()),
50-
call_shim_on_c_stack: upcall!(fn call_shim_on_c_stack(opaque_ptr, opaque_ptr) -> int_ty),
51-
call_shim_on_rust_stack:
52-
upcall!(fn call_shim_on_rust_stack(opaque_ptr, opaque_ptr) -> int_ty),
5348
rust_personality: upcall!(nothrow fn rust_personality -> Type::i32()),
5449
reset_stack_limit: upcall!(nothrow fn reset_stack_limit -> Type::void())
5550
}

src/librustc/driver/driver.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,9 @@ pub fn phase_3_run_analysis_passes(sess: Session,
265265
time(time_passes, ~"loop checking", ||
266266
middle::check_loop::check_crate(ty_cx, crate));
267267

268+
time(time_passes, ~"stack checking", ||
269+
middle::stack_check::stack_check_crate(ty_cx, crate));
270+
268271
let middle::moves::MoveMaps {moves_map, moved_variables_set,
269272
capture_map} =
270273
time(time_passes, ~"compute moves", ||

src/librustc/lib/llvm.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2246,6 +2246,11 @@ impl TypeNames {
22462246
self.type_to_str_depth(ty, 30)
22472247
}
22482248

2249+
pub fn types_to_str(&self, tys: &[Type]) -> ~str {
2250+
let strs = tys.map(|t| self.type_to_str(*t));
2251+
fmt!("[%s]", strs.connect(","))
2252+
}
2253+
22492254
pub fn val_to_str(&self, val: ValueRef) -> ~str {
22502255
unsafe {
22512256
let ty = Type::from_ref(llvm::LLVMTypeOf(val));

src/librustc/middle/lint.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ use syntax::{ast, oldvisit, ast_util, visit};
7373
#[deriving(Clone, Eq)]
7474
pub enum lint {
7575
ctypes,
76+
cstack,
7677
unused_imports,
7778
unnecessary_qualification,
7879
while_true,
@@ -146,6 +147,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
146147
default: warn
147148
}),
148149

150+
("cstack",
151+
LintSpec {
152+
lint: cstack,
153+
desc: "only invoke foreign functions from fixedstacksegment fns",
154+
default: deny
155+
}),
156+
149157
("unused_imports",
150158
LintSpec {
151159
lint: unused_imports,

src/librustc/middle/stack_check.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
/*!
12+
13+
Lint mode to detect cases where we call non-Rust fns, which do not
14+
have a stack growth check, from locations not annotated to request
15+
large stacks.
16+
17+
*/
18+
19+
use middle::lint;
20+
use middle::ty;
21+
use syntax::ast;
22+
use syntax::attr;
23+
use syntax::codemap::span;
24+
use visit = syntax::oldvisit;
25+
use util::ppaux::Repr;
26+
27+
#[deriving(Clone)]
28+
struct Context {
29+
tcx: ty::ctxt,
30+
safe_stack: bool
31+
}
32+
33+
pub fn stack_check_crate(tcx: ty::ctxt,
34+
crate: &ast::Crate) {
35+
let new_cx = Context {
36+
tcx: tcx,
37+
safe_stack: false
38+
};
39+
let visitor = visit::mk_vt(@visit::Visitor {
40+
visit_item: stack_check_item,
41+
visit_fn: stack_check_fn,
42+
visit_expr: stack_check_expr,
43+
..*visit::default_visitor()
44+
});
45+
visit::visit_crate(crate, (new_cx, visitor));
46+
}
47+
48+
fn stack_check_item(item: @ast::item,
49+
(in_cx, v): (Context, visit::vt<Context>)) {
50+
let safe_stack = match item.node {
51+
ast::item_fn(*) => {
52+
attr::contains_name(item.attrs, "fixed_stack_segment")
53+
}
54+
_ => {
55+
false
56+
}
57+
};
58+
let new_cx = Context {
59+
tcx: in_cx.tcx,
60+
safe_stack: safe_stack
61+
};
62+
visit::visit_item(item, (new_cx, v));
63+
}
64+
65+
fn stack_check_fn<'a>(fk: &visit::fn_kind,
66+
decl: &ast::fn_decl,
67+
body: &ast::Block,
68+
sp: span,
69+
id: ast::NodeId,
70+
(in_cx, v): (Context, visit::vt<Context>)) {
71+
let safe_stack = match *fk {
72+
visit::fk_item_fn(*) => in_cx.safe_stack, // see stack_check_item above
73+
visit::fk_anon(*) | visit::fk_fn_block | visit::fk_method(*) => false,
74+
};
75+
let new_cx = Context {
76+
tcx: in_cx.tcx,
77+
safe_stack: safe_stack
78+
};
79+
debug!("stack_check_fn(safe_stack=%b, id=%?)", safe_stack, id);
80+
visit::visit_fn(fk, decl, body, sp, id, (new_cx, v));
81+
}
82+
83+
fn stack_check_expr<'a>(expr: @ast::expr,
84+
(cx, v): (Context, visit::vt<Context>)) {
85+
debug!("stack_check_expr(safe_stack=%b, expr=%s)",
86+
cx.safe_stack, expr.repr(cx.tcx));
87+
if !cx.safe_stack {
88+
match expr.node {
89+
ast::expr_call(callee, _, _) => {
90+
let callee_ty = ty::expr_ty(cx.tcx, callee);
91+
debug!("callee_ty=%s", callee_ty.repr(cx.tcx));
92+
match ty::get(callee_ty).sty {
93+
ty::ty_bare_fn(ref fty) => {
94+
if !fty.abis.is_rust() && !fty.abis.is_intrinsic() {
95+
cx.tcx.sess.add_lint(
96+
lint::cstack,
97+
callee.id,
98+
callee.span,
99+
fmt!("invoking non-Rust fn in fn without \
100+
#[fixed_stack_segment]"));
101+
}
102+
}
103+
_ => {}
104+
}
105+
}
106+
_ => {}
107+
}
108+
}
109+
visit::visit_expr(expr, (cx, v));
110+
}

src/librustc/middle/trans/base.rs

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -203,28 +203,28 @@ pub fn decl_internal_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRe
203203
return llfn;
204204
}
205205

206-
pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: @str,
206+
pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
207207
cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
208-
match externs.find_copy(&name) {
209-
Some(n) => return n,
208+
match externs.find_equiv(&name) {
209+
Some(n) => return *n,
210210
None => ()
211211
}
212212
let f = decl_fn(llmod, name, cc, ty);
213-
externs.insert(name, f);
213+
externs.insert(name.to_owned(), f);
214214
return f;
215215
}
216216

217217
pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef,
218-
name: @str, ty: Type) -> ValueRef {
219-
match externs.find_copy(&name) {
220-
Some(n) => return n,
218+
name: &str, ty: Type) -> ValueRef {
219+
match externs.find_equiv(&name) {
220+
Some(n) => return *n,
221221
None => ()
222222
}
223223
unsafe {
224224
let c = do name.with_c_str |buf| {
225225
llvm::LLVMAddGlobal(llmod, ty.to_ref(), buf)
226226
};
227-
externs.insert(name, c);
227+
externs.insert(name.to_owned(), c);
228228
return c;
229229
}
230230
}
@@ -511,7 +511,6 @@ pub fn get_res_dtor(ccx: @mut CrateContext,
511511
None,
512512
ty::lookup_item_type(tcx, parent_id).ty);
513513
let llty = type_of_dtor(ccx, class_ty);
514-
let name = name.to_managed(); // :-(
515514
get_extern_fn(&mut ccx.externs,
516515
ccx.llmod,
517516
name,
@@ -798,13 +797,13 @@ pub fn fail_if_zero(cx: @mut Block, span: span, divrem: ast::binop,
798797
}
799798
}
800799
801-
pub fn null_env_ptr(bcx: @mut Block) -> ValueRef {
802-
C_null(Type::opaque_box(bcx.ccx()).ptr_to())
800+
pub fn null_env_ptr(ccx: &CrateContext) -> ValueRef {
801+
C_null(Type::opaque_box(ccx).ptr_to())
803802
}
804803
805804
pub fn trans_external_path(ccx: &mut CrateContext, did: ast::def_id, t: ty::t)
806805
-> ValueRef {
807-
let name = csearch::get_symbol(ccx.sess.cstore, did).to_managed(); // Sad
806+
let name = csearch::get_symbol(ccx.sess.cstore, did);
808807
match ty::get(t).sty {
809808
ty::ty_bare_fn(_) | ty::ty_closure(_) => {
810809
let llty = type_of_fn_from_ty(ccx, t);
@@ -1572,7 +1571,7 @@ pub fn mk_return_basic_block(llfn: ValueRef) -> BasicBlockRef {
15721571
// slot where the return value of the function must go.
15731572
pub fn make_return_pointer(fcx: @mut FunctionContext, output_type: ty::t) -> ValueRef {
15741573
unsafe {
1575-
if !ty::type_is_immediate(fcx.ccx.tcx, output_type) {
1574+
if type_of::return_uses_outptr(fcx.ccx.tcx, output_type) {
15761575
llvm::LLVMGetParam(fcx.llfn, 0)
15771576
} else {
15781577
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
@@ -1612,7 +1611,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
16121611
ty::subst_tps(ccx.tcx, substs.tys, substs.self_ty, output_type)
16131612
}
16141613
};
1615-
let is_immediate = ty::type_is_immediate(ccx.tcx, substd_output_type);
1614+
let uses_outptr = type_of::return_uses_outptr(ccx.tcx, substd_output_type);
16161615
let fcx = @mut FunctionContext {
16171616
llfn: llfndecl,
16181617
llenv: unsafe {
@@ -1624,7 +1623,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
16241623
llreturn: None,
16251624
llself: None,
16261625
personality: None,
1627-
has_immediate_return_value: is_immediate,
1626+
caller_expects_out_pointer: uses_outptr,
16281627
llargs: @mut HashMap::new(),
16291628
lllocals: @mut HashMap::new(),
16301629
llupvars: @mut HashMap::new(),
@@ -1647,8 +1646,15 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
16471646
fcx.alloca_insert_pt = Some(llvm::LLVMGetFirstInstruction(entry_bcx.llbb));
16481647
}
16491648

1650-
if !ty::type_is_nil(substd_output_type) && !(is_immediate && skip_retptr) {
1651-
fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
1649+
if !ty::type_is_voidish(substd_output_type) {
1650+
// If the function returns nil/bot, there is no real return
1651+
// value, so do not set `llretptr`.
1652+
if !skip_retptr || uses_outptr {
1653+
// Otherwise, we normally allocate the llretptr, unless we
1654+
// have been instructed to skip it for immediate return
1655+
// values.
1656+
fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
1657+
}
16521658
}
16531659
fcx
16541660
}
@@ -1796,7 +1802,7 @@ pub fn finish_fn(fcx: @mut FunctionContext, last_bcx: @mut Block) {
17961802
// Builds the return block for a function.
17971803
pub fn build_return_block(fcx: &FunctionContext, ret_cx: @mut Block) {
17981804
// Return the value if this function immediate; otherwise, return void.
1799-
if fcx.llretptr.is_none() || !fcx.has_immediate_return_value {
1805+
if fcx.llretptr.is_none() || fcx.caller_expects_out_pointer {
18001806
return RetVoid(ret_cx);
18011807
}
18021808

@@ -1882,9 +1888,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
18821888
// translation calls that don't have a return value (trans_crate,
18831889
// trans_mod, trans_item, et cetera) and those that do
18841890
// (trans_block, trans_expr, et cetera).
1885-
if body.expr.is_none() || ty::type_is_bot(block_ty) ||
1886-
ty::type_is_nil(block_ty)
1887-
{
1891+
if body.expr.is_none() || ty::type_is_voidish(block_ty) {
18881892
bcx = controlflow::trans_block(bcx, body, expr::Ignore);
18891893
} else {
18901894
let dest = expr::SaveIn(fcx.llretptr.unwrap());
@@ -2129,13 +2133,14 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
21292133
ast::item_fn(ref decl, purity, _abis, ref generics, ref body) => {
21302134
if purity == ast::extern_fn {
21312135
let llfndecl = get_item_val(ccx, item.id);
2132-
foreign::trans_foreign_fn(ccx,
2133-
vec::append((*path).clone(),
2134-
[path_name(item.ident)]),
2135-
decl,
2136-
body,
2137-
llfndecl,
2138-
item.id);
2136+
foreign::trans_rust_fn_with_foreign_abi(
2137+
ccx,
2138+
&vec::append((*path).clone(),
2139+
[path_name(item.ident)]),
2140+
decl,
2141+
body,
2142+
llfndecl,
2143+
item.id);
21392144
} else if !generics.is_type_parameterized() {
21402145
let llfndecl = get_item_val(ccx, item.id);
21412146
trans_fn(ccx,
@@ -2196,7 +2201,7 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
21962201
}
21972202
},
21982203
ast::item_foreign_mod(ref foreign_mod) => {
2199-
foreign::trans_foreign_mod(ccx, path, foreign_mod);
2204+
foreign::trans_foreign_mod(ccx, foreign_mod);
22002205
}
22012206
ast::item_struct(struct_def, ref generics) => {
22022207
if !generics.is_type_parameterized() {
@@ -2291,16 +2296,15 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext,
22912296

22922297
fn create_main(ccx: @mut CrateContext, main_llfn: ValueRef) -> ValueRef {
22932298
let nt = ty::mk_nil();
2294-
2295-
let llfty = type_of_fn(ccx, [], nt);
2299+
let llfty = type_of_rust_fn(ccx, [], nt);
22962300
let llfdecl = decl_fn(ccx.llmod, "_rust_main",
22972301
lib::llvm::CCallConv, llfty);
22982302

22992303
let fcx = new_fn_ctxt(ccx, ~[], llfdecl, nt, None);
23002304

23012305
// the args vector built in create_entry_fn will need
23022306
// be updated if this assertion starts to fail.
2303-
assert!(fcx.has_immediate_return_value);
2307+
assert!(!fcx.caller_expects_out_pointer);
23042308

23052309
let bcx = fcx.entry_bcx.unwrap();
23062310
// Call main.
@@ -2463,7 +2467,10 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
24632467
let llfn = if purity != ast::extern_fn {
24642468
register_fn(ccx, i.span, sym, i.id, ty)
24652469
} else {
2466-
foreign::register_foreign_fn(ccx, i.span, sym, i.id)
2470+
foreign::register_rust_fn_with_foreign_abi(ccx,
2471+
i.span,
2472+
sym,
2473+
i.id)
24672474
};
24682475
set_inline_hint_if_appr(i.attrs, llfn);
24692476
llfn
@@ -2509,9 +2516,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
25092516
match ni.node {
25102517
ast::foreign_item_fn(*) => {
25112518
let path = vec::append((*pth).clone(), [path_name(ni.ident)]);
2512-
let sym = exported_name(ccx, path, ty, ni.attrs);
2513-
2514-
register_fn(ccx, ni.span, sym, ni.id, ty)
2519+
foreign::register_foreign_item_fn(ccx, abis, &path, ni);
25152520
}
25162521
ast::foreign_item_static(*) => {
25172522
let ident = token::ident_to_str(&ni.ident);

0 commit comments

Comments
 (0)