Skip to content

Commit

Permalink
Issue rust-lang#3678: Remove wrappers and call foreign functions dire…
Browse files Browse the repository at this point in the history
…ctly
  • Loading branch information
nikomatsakis committed Aug 19, 2013
1 parent c178b52 commit 303f650
Show file tree
Hide file tree
Showing 28 changed files with 1,690 additions and 1,559 deletions.
5 changes: 0 additions & 5 deletions src/librustc/back/upcall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ use lib::llvm::{ModuleRef, ValueRef};

pub struct Upcalls {
trace: ValueRef,
call_shim_on_c_stack: ValueRef,
call_shim_on_rust_stack: ValueRef,
rust_personality: ValueRef,
reset_stack_limit: ValueRef
}
Expand Down Expand Up @@ -47,9 +45,6 @@ pub fn declare_upcalls(targ_cfg: @session::config, llmod: ModuleRef) -> @Upcalls

@Upcalls {
trace: upcall!(fn trace(opaque_ptr, opaque_ptr, int_ty) -> Type::void()),
call_shim_on_c_stack: upcall!(fn call_shim_on_c_stack(opaque_ptr, opaque_ptr) -> int_ty),
call_shim_on_rust_stack:
upcall!(fn call_shim_on_rust_stack(opaque_ptr, opaque_ptr) -> int_ty),
rust_personality: upcall!(nothrow fn rust_personality -> Type::i32()),
reset_stack_limit: upcall!(nothrow fn reset_stack_limit -> Type::void())
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ pub fn phase_3_run_analysis_passes(sess: Session,
time(time_passes, ~"loop checking", ||
middle::check_loop::check_crate(ty_cx, crate));

time(time_passes, ~"stack checking", ||
middle::stack_check::stack_check_crate(ty_cx, crate));

let middle::moves::MoveMaps {moves_map, moved_variables_set,
capture_map} =
time(time_passes, ~"compute moves", ||
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/lib/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2246,6 +2246,11 @@ impl TypeNames {
self.type_to_str_depth(ty, 30)
}

pub fn types_to_str(&self, tys: &[Type]) -> ~str {
let strs = tys.map(|t| self.type_to_str(*t));
fmt!("[%s]", strs.connect(","))
}

pub fn val_to_str(&self, val: ValueRef) -> ~str {
unsafe {
let ty = Type::from_ref(llvm::LLVMTypeOf(val));
Expand Down
8 changes: 8 additions & 0 deletions src/librustc/middle/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ use syntax::{ast, oldvisit, ast_util, visit};
#[deriving(Clone, Eq)]
pub enum lint {
ctypes,
cstack,
unused_imports,
unnecessary_qualification,
while_true,
Expand Down Expand Up @@ -146,6 +147,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
default: warn
}),

("cstack",
LintSpec {
lint: cstack,
desc: "only invoke foreign functions from fixedstacksegment fns",
default: deny
}),

("unused_imports",
LintSpec {
lint: unused_imports,
Expand Down
110 changes: 110 additions & 0 deletions src/librustc/middle/stack_check.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
Lint mode to detect cases where we call non-Rust fns, which do not
have a stack growth check, from locations not annotated to request
large stacks.
*/

use middle::lint;
use middle::ty;
use syntax::ast;
use syntax::attr;
use syntax::codemap::span;
use visit = syntax::oldvisit;
use util::ppaux::Repr;

#[deriving(Clone)]
struct Context {
tcx: ty::ctxt,
safe_stack: bool
}

pub fn stack_check_crate(tcx: ty::ctxt,
crate: &ast::Crate) {
let new_cx = Context {
tcx: tcx,
safe_stack: false
};
let visitor = visit::mk_vt(@visit::Visitor {
visit_item: stack_check_item,
visit_fn: stack_check_fn,
visit_expr: stack_check_expr,
..*visit::default_visitor()
});
visit::visit_crate(crate, (new_cx, visitor));
}

fn stack_check_item(item: @ast::item,
(in_cx, v): (Context, visit::vt<Context>)) {
let safe_stack = match item.node {
ast::item_fn(*) => {
attr::contains_name(item.attrs, "fixed_stack_segment")
}
_ => {
false
}
};
let new_cx = Context {
tcx: in_cx.tcx,
safe_stack: safe_stack
};
visit::visit_item(item, (new_cx, v));
}

fn stack_check_fn<'a>(fk: &visit::fn_kind,
decl: &ast::fn_decl,
body: &ast::Block,
sp: span,
id: ast::NodeId,
(in_cx, v): (Context, visit::vt<Context>)) {
let safe_stack = match *fk {
visit::fk_item_fn(*) => in_cx.safe_stack, // see stack_check_item above
visit::fk_anon(*) | visit::fk_fn_block | visit::fk_method(*) => false,
};
let new_cx = Context {
tcx: in_cx.tcx,
safe_stack: safe_stack
};
debug!("stack_check_fn(safe_stack=%b, id=%?)", safe_stack, id);
visit::visit_fn(fk, decl, body, sp, id, (new_cx, v));
}

fn stack_check_expr<'a>(expr: @ast::expr,
(cx, v): (Context, visit::vt<Context>)) {
debug!("stack_check_expr(safe_stack=%b, expr=%s)",
cx.safe_stack, expr.repr(cx.tcx));
if !cx.safe_stack {
match expr.node {
ast::expr_call(callee, _, _) => {
let callee_ty = ty::expr_ty(cx.tcx, callee);
debug!("callee_ty=%s", callee_ty.repr(cx.tcx));
match ty::get(callee_ty).sty {
ty::ty_bare_fn(ref fty) => {
if !fty.abis.is_rust() && !fty.abis.is_intrinsic() {
cx.tcx.sess.add_lint(
lint::cstack,
callee.id,
callee.span,
fmt!("invoking non-Rust fn in fn without \
#[fixed_stack_segment]"));
}
}
_ => {}
}
}
_ => {}
}
}
visit::visit_expr(expr, (cx, v));
}
77 changes: 41 additions & 36 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,28 +203,28 @@ pub fn decl_internal_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRe
return llfn;
}

pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: @str,
pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
match externs.find_copy(&name) {
Some(n) => return n,
match externs.find_equiv(&name) {
Some(n) => return *n,
None => ()
}
let f = decl_fn(llmod, name, cc, ty);
externs.insert(name, f);
externs.insert(name.to_owned(), f);
return f;
}

pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef,
name: @str, ty: Type) -> ValueRef {
match externs.find_copy(&name) {
Some(n) => return n,
name: &str, ty: Type) -> ValueRef {
match externs.find_equiv(&name) {
Some(n) => return *n,
None => ()
}
unsafe {
let c = do name.with_c_str |buf| {
llvm::LLVMAddGlobal(llmod, ty.to_ref(), buf)
};
externs.insert(name, c);
externs.insert(name.to_owned(), c);
return c;
}
}
Expand Down Expand Up @@ -511,7 +511,6 @@ pub fn get_res_dtor(ccx: @mut CrateContext,
None,
ty::lookup_item_type(tcx, parent_id).ty);
let llty = type_of_dtor(ccx, class_ty);
let name = name.to_managed(); // :-(
get_extern_fn(&mut ccx.externs,
ccx.llmod,
name,
Expand Down Expand Up @@ -798,13 +797,13 @@ pub fn fail_if_zero(cx: @mut Block, span: span, divrem: ast::binop,
}
}
pub fn null_env_ptr(bcx: @mut Block) -> ValueRef {
C_null(Type::opaque_box(bcx.ccx()).ptr_to())
pub fn null_env_ptr(ccx: &CrateContext) -> ValueRef {
C_null(Type::opaque_box(ccx).ptr_to())
}
pub fn trans_external_path(ccx: &mut CrateContext, did: ast::def_id, t: ty::t)
-> ValueRef {
let name = csearch::get_symbol(ccx.sess.cstore, did).to_managed(); // Sad
let name = csearch::get_symbol(ccx.sess.cstore, did);
match ty::get(t).sty {
ty::ty_bare_fn(_) | ty::ty_closure(_) => {
let llty = type_of_fn_from_ty(ccx, t);
Expand Down Expand Up @@ -1572,7 +1571,7 @@ pub fn mk_return_basic_block(llfn: ValueRef) -> BasicBlockRef {
// slot where the return value of the function must go.
pub fn make_return_pointer(fcx: @mut FunctionContext, output_type: ty::t) -> ValueRef {
unsafe {
if !ty::type_is_immediate(fcx.ccx.tcx, output_type) {
if type_of::return_uses_outptr(fcx.ccx.tcx, output_type) {
llvm::LLVMGetParam(fcx.llfn, 0)
} else {
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
Expand Down Expand Up @@ -1612,7 +1611,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
ty::subst_tps(ccx.tcx, substs.tys, substs.self_ty, output_type)
}
};
let is_immediate = ty::type_is_immediate(ccx.tcx, substd_output_type);
let uses_outptr = type_of::return_uses_outptr(ccx.tcx, substd_output_type);
let fcx = @mut FunctionContext {
llfn: llfndecl,
llenv: unsafe {
Expand All @@ -1624,7 +1623,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
llreturn: None,
llself: None,
personality: None,
has_immediate_return_value: is_immediate,
caller_expects_out_pointer: uses_outptr,
llargs: @mut HashMap::new(),
lllocals: @mut HashMap::new(),
llupvars: @mut HashMap::new(),
Expand All @@ -1647,8 +1646,15 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
fcx.alloca_insert_pt = Some(llvm::LLVMGetFirstInstruction(entry_bcx.llbb));
}

if !ty::type_is_nil(substd_output_type) && !(is_immediate && skip_retptr) {
fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
if !ty::type_is_voidish(substd_output_type) {
// If the function returns nil/bot, there is no real return
// value, so do not set `llretptr`.
if !skip_retptr || uses_outptr {
// Otherwise, we normally allocate the llretptr, unless we
// have been instructed to skip it for immediate return
// values.
fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
}
}
fcx
}
Expand Down Expand Up @@ -1796,7 +1802,7 @@ pub fn finish_fn(fcx: @mut FunctionContext, last_bcx: @mut Block) {
// Builds the return block for a function.
pub fn build_return_block(fcx: &FunctionContext, ret_cx: @mut Block) {
// Return the value if this function immediate; otherwise, return void.
if fcx.llretptr.is_none() || !fcx.has_immediate_return_value {
if fcx.llretptr.is_none() || fcx.caller_expects_out_pointer {
return RetVoid(ret_cx);
}

Expand Down Expand Up @@ -1882,9 +1888,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
// translation calls that don't have a return value (trans_crate,
// trans_mod, trans_item, et cetera) and those that do
// (trans_block, trans_expr, et cetera).
if body.expr.is_none() || ty::type_is_bot(block_ty) ||
ty::type_is_nil(block_ty)
{
if body.expr.is_none() || ty::type_is_voidish(block_ty) {
bcx = controlflow::trans_block(bcx, body, expr::Ignore);
} else {
let dest = expr::SaveIn(fcx.llretptr.unwrap());
Expand Down Expand Up @@ -2129,13 +2133,14 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
ast::item_fn(ref decl, purity, _abis, ref generics, ref body) => {
if purity == ast::extern_fn {
let llfndecl = get_item_val(ccx, item.id);
foreign::trans_foreign_fn(ccx,
vec::append((*path).clone(),
[path_name(item.ident)]),
decl,
body,
llfndecl,
item.id);
foreign::trans_rust_fn_with_foreign_abi(
ccx,
&vec::append((*path).clone(),
[path_name(item.ident)]),
decl,
body,
llfndecl,
item.id);
} else if !generics.is_type_parameterized() {
let llfndecl = get_item_val(ccx, item.id);
trans_fn(ccx,
Expand Down Expand Up @@ -2196,7 +2201,7 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
}
},
ast::item_foreign_mod(ref foreign_mod) => {
foreign::trans_foreign_mod(ccx, path, foreign_mod);
foreign::trans_foreign_mod(ccx, foreign_mod);
}
ast::item_struct(struct_def, ref generics) => {
if !generics.is_type_parameterized() {
Expand Down Expand Up @@ -2291,16 +2296,15 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext,

fn create_main(ccx: @mut CrateContext, main_llfn: ValueRef) -> ValueRef {
let nt = ty::mk_nil();

let llfty = type_of_fn(ccx, [], nt);
let llfty = type_of_rust_fn(ccx, [], nt);
let llfdecl = decl_fn(ccx.llmod, "_rust_main",
lib::llvm::CCallConv, llfty);

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

// the args vector built in create_entry_fn will need
// be updated if this assertion starts to fail.
assert!(fcx.has_immediate_return_value);
assert!(!fcx.caller_expects_out_pointer);

let bcx = fcx.entry_bcx.unwrap();
// Call main.
Expand Down Expand Up @@ -2463,7 +2467,10 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
let llfn = if purity != ast::extern_fn {
register_fn(ccx, i.span, sym, i.id, ty)
} else {
foreign::register_foreign_fn(ccx, i.span, sym, i.id)
foreign::register_rust_fn_with_foreign_abi(ccx,
i.span,
sym,
i.id)
};
set_inline_hint_if_appr(i.attrs, llfn);
llfn
Expand Down Expand Up @@ -2509,9 +2516,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
match ni.node {
ast::foreign_item_fn(*) => {
let path = vec::append((*pth).clone(), [path_name(ni.ident)]);
let sym = exported_name(ccx, path, ty, ni.attrs);

register_fn(ccx, ni.span, sym, ni.id, ty)
foreign::register_foreign_item_fn(ccx, abis, &path, ni);
}
ast::foreign_item_static(*) => {
let ident = token::ident_to_str(&ni.ident);
Expand Down
Loading

0 comments on commit 303f650

Please sign in to comment.