librustc: Implement fast-ffi and use it in various places

This commit is contained in:
Patrick Walton 2013-03-29 16:55:04 -07:00
parent 1a36b0f17e
commit f903ae9e72
17 changed files with 618 additions and 69 deletions

View File

@ -1109,8 +1109,10 @@ pub mod funcs {
// Omitted: putc, putchar (might be macros).
unsafe fn puts(s: *c_char) -> c_int;
unsafe fn ungetc(c: c_int, stream: *FILE) -> c_int;
#[fast_ffi]
unsafe fn fread(ptr: *mut c_void, size: size_t,
nobj: size_t, stream: *FILE) -> size_t;
#[fast_ffi]
unsafe fn fwrite(ptr: *c_void, size: size_t,
nobj: size_t, stream: *FILE) -> size_t;
unsafe fn fseek(stream: *FILE, offset: c_long,
@ -1144,9 +1146,13 @@ pub mod funcs {
-> c_long;
unsafe fn strtoul(s: *c_char, endp: **c_char, base: c_int)
-> c_ulong;
#[fast_ffi]
unsafe fn calloc(nobj: size_t, size: size_t) -> *c_void;
#[fast_ffi]
unsafe fn malloc(size: size_t) -> *c_void;
#[fast_ffi]
unsafe fn realloc(p: *c_void, size: size_t) -> *c_void;
#[fast_ffi]
unsafe fn free(p: *c_void);
unsafe fn abort() -> !;
unsafe fn exit(status: c_int) -> !;
@ -1340,6 +1346,7 @@ pub mod funcs {
textmode: c_int) -> c_int;
#[link_name = "_read"]
#[fast_ffi]
unsafe fn read(fd: c_int, buf: *mut c_void, count: c_uint)
-> c_int;
@ -1350,6 +1357,7 @@ pub mod funcs {
unsafe fn unlink(c: *c_char) -> c_int;
#[link_name = "_write"]
#[fast_ffi]
unsafe fn write(fd: c_int, buf: *c_void, count: c_uint)
-> c_int;
}
@ -1502,6 +1510,7 @@ pub mod funcs {
unsafe fn pathconf(path: *c_char, name: c_int) -> c_long;
unsafe fn pause() -> c_int;
unsafe fn pipe(fds: *mut c_int) -> c_int;
#[fast_ffi]
unsafe fn read(fd: c_int, buf: *mut c_void,
count: size_t) -> ssize_t;
unsafe fn rmdir(path: *c_char) -> c_int;
@ -1514,6 +1523,7 @@ pub mod funcs {
unsafe fn tcgetpgrp(fd: c_int) -> pid_t;
unsafe fn ttyname(fd: c_int) -> *c_char;
unsafe fn unlink(c: *c_char) -> c_int;
#[fast_ffi]
unsafe fn write(fd: c_int, buf: *c_void, count: size_t)
-> ssize_t;
}

View File

@ -35,6 +35,14 @@ pub mod rustrt {
#[rust_stack]
unsafe fn rust_upcall_free(ptr: *c_char);
#[fast_ffi]
unsafe fn rust_upcall_malloc_noswitch(td: *c_char,
size: uintptr_t)
-> *c_char;
#[fast_ffi]
unsafe fn rust_upcall_free_noswitch(ptr: *c_char);
}
}
@ -81,7 +89,7 @@ pub unsafe fn exchange_free(ptr: *c_char) {
#[lang="malloc"]
#[inline(always)]
pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
return rustrt::rust_upcall_malloc(td, size);
return rustrt::rust_upcall_malloc_noswitch(td, size);
}
// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
@ -90,7 +98,7 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
#[lang="free"]
#[inline(always)]
pub unsafe fn local_free(ptr: *c_char) {
rustrt::rust_upcall_free(ptr);
rustrt::rust_upcall_free_noswitch(ptr);
}
#[lang="borrow_as_imm"]

View File

@ -43,9 +43,11 @@ pub mod rustrt {
pub extern {
// These names are terrible. reserve_shared applies
// to ~[] and reserve_shared_actual applies to @[].
#[fast_ffi]
unsafe fn vec_reserve_shared(++t: *sys::TypeDesc,
++v: **raw::VecRepr,
++n: libc::size_t);
#[fast_ffi]
unsafe fn vec_reserve_shared_actual(++t: *sys::TypeDesc,
++v: **raw::VecRepr,
++n: libc::size_t);

View File

@ -172,10 +172,13 @@ pub enum compile_upto {
// For continuing compilation after a parsed crate has been
// modified
pub fn compile_rest(sess: Session, cfg: ast::crate_cfg,
upto: compile_upto, outputs: Option<@OutputFilenames>,
#[fixed_stack_segment]
pub fn compile_rest(sess: Session,
cfg: ast::crate_cfg,
upto: compile_upto,
outputs: Option<@OutputFilenames>,
curr: Option<@ast::crate>)
-> (@ast::crate, Option<ty::ctxt>) {
-> (@ast::crate, Option<ty::ctxt>) {
let time_passes = sess.time_passes();
let mut crate = curr.get();

File diff suppressed because it is too large Load Diff

View File

@ -1336,17 +1336,7 @@ fn roundtrip(in_item: Option<@ast::item>) {
let ebml_doc = reader::Doc(@bytes);
let out_item = decode_item_ast(ebml_doc);
let exp_str = do io::with_str_writer |w| {
in_item.encode(&prettyprint::Serializer(w))
};
let out_str = do io::with_str_writer |w| {
out_item.encode(&prettyprint::Serializer(w))
};
debug!("expected string: %s", exp_str);
debug!("actual string : %s", out_str);
assert!(exp_str == out_str);
assert_eq!(in_item, out_item);
}
#[test]

View File

@ -399,24 +399,24 @@ pub fn set_optimize_for_size(f: ValueRef) {
unsafe {
llvm::LLVMAddFunctionAttr(f,
lib::llvm::OptimizeForSizeAttribute
as c_ulonglong,
0u as c_ulonglong);
as c_uint,
0);
}
}
pub fn set_no_inline(f: ValueRef) {
unsafe {
llvm::LLVMAddFunctionAttr(f,
lib::llvm::NoInlineAttribute as c_ulonglong,
0u as c_ulonglong);
lib::llvm::NoInlineAttribute as c_uint,
0);
}
}
pub fn set_no_unwind(f: ValueRef) {
unsafe {
llvm::LLVMAddFunctionAttr(f,
lib::llvm::NoUnwindAttribute as c_ulonglong,
0u as c_ulonglong);
lib::llvm::NoUnwindAttribute as c_uint,
0);
}
}
@ -425,15 +425,16 @@ pub fn set_no_unwind(f: ValueRef) {
pub fn set_uwtable(f: ValueRef) {
unsafe {
llvm::LLVMAddFunctionAttr(f,
lib::llvm::UWTableAttribute as c_ulonglong,
0u as c_ulonglong);
lib::llvm::UWTableAttribute as c_uint,
0);
}
}
pub fn set_inline_hint(f: ValueRef) {
unsafe {
llvm::LLVMAddFunctionAttr(f, lib::llvm::InlineHintAttribute
as c_ulonglong, 0u as c_ulonglong);
llvm::LLVMAddFunctionAttr(f,
lib::llvm::InlineHintAttribute as c_uint,
0);
}
}
@ -449,14 +450,15 @@ pub fn set_inline_hint_if_appr(attrs: &[ast::attribute],
pub fn set_always_inline(f: ValueRef) {
unsafe {
llvm::LLVMAddFunctionAttr(f, lib::llvm::AlwaysInlineAttribute
as c_ulonglong, 0u as c_ulonglong);
llvm::LLVMAddFunctionAttr(f,
lib::llvm::AlwaysInlineAttribute as c_uint,
0);
}
}
pub fn set_custom_stack_growth_fn(f: ValueRef) {
pub fn set_fixed_stack_segment(f: ValueRef) {
unsafe {
llvm::LLVMAddFunctionAttr(f, 0u as c_ulonglong, 1u as c_ulonglong);
llvm::LLVMAddFunctionAttr(f, 0, 1 << (39 - 32));
}
}
@ -1774,6 +1776,7 @@ pub fn trans_closure(ccx: @CrateContext,
param_substs: Option<@param_substs>,
id: ast::node_id,
impl_id: Option<ast::def_id>,
attributes: &[ast::attribute],
maybe_load_env: &fn(fn_ctxt),
finish: &fn(block)) {
ccx.stats.n_closures += 1;
@ -1784,10 +1787,20 @@ pub fn trans_closure(ccx: @CrateContext,
param_substs.repr(ccx.tcx));
// Set up arguments to the function.
let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, impl_id, param_substs,
Some(body.span));
let raw_llargs = create_llargs_for_fn_args(fcx, ty_self,
decl.inputs);
let fcx = new_fn_ctxt_w_id(ccx,
path,
llfndecl,
id,
impl_id,
param_substs,
Some(body.span));
let raw_llargs = create_llargs_for_fn_args(fcx, ty_self, decl.inputs);
// Set the fixed stack segment flag if necessary.
if attr::attrs_contains_name(attributes, "fixed_stack_segment") {
set_no_inline(fcx.llfn);
set_fixed_stack_segment(fcx.llfn);
}
// Set GC for function.
if ccx.sess.opts.gc {
@ -1840,7 +1853,8 @@ pub fn trans_fn(ccx: @CrateContext,
ty_self: self_arg,
param_substs: Option<@param_substs>,
id: ast::node_id,
impl_id: Option<ast::def_id>) {
impl_id: Option<ast::def_id>,
attrs: &[ast::attribute]) {
let do_time = ccx.sess.trans_stats();
let start = if do_time { time::get_time() }
else { time::Timespec::new(0, 0) };
@ -1850,8 +1864,16 @@ pub fn trans_fn(ccx: @CrateContext,
let _icx = ccx.insn_ctxt("trans_fn");
ccx.stats.n_fns += 1;
let the_path_str = path_str(ccx.sess, path);
trans_closure(ccx, path, decl, body, llfndecl, ty_self,
param_substs, id, impl_id,
trans_closure(ccx,
path,
decl,
body,
llfndecl,
ty_self,
param_substs,
id,
impl_id,
attrs,
|fcx| {
if ccx.sess.opts.extra_debuginfo {
debuginfo::create_function(fcx);
@ -2023,8 +2045,16 @@ pub fn trans_struct_dtor(ccx: @CrateContext,
}
/* Translate the dtor body */
let decl = ast_util::dtor_dec();
trans_fn(ccx, path, &decl, body, lldecl,
impl_self(class_ty), psubsts, dtor_id, None);
trans_fn(ccx,
path,
&decl,
body,
lldecl,
impl_self(class_ty),
psubsts,
dtor_id,
None,
[]);
lldecl
}
@ -2073,7 +2103,14 @@ pub fn trans_item(ccx: @CrateContext, item: ast::item) {
let llfndecl = get_item_val(ccx, item.id);
trans_fn(ccx,
vec::append(/*bad*/copy *path, ~[path_name(item.ident)]),
decl, body, llfndecl, no_self, None, item.id, None);
decl,
body,
llfndecl,
no_self,
None,
item.id,
None,
item.attrs);
} else {
for body.node.stmts.each |stmt| {
match stmt.node {

View File

@ -416,9 +416,16 @@ pub fn trans_expr_fn(bcx: block,
None => None};
let ClosureResult {llbox, cdata_ty, bcx}
= build_closure(bcx, cap_vars, sigil, ret_handle);
trans_closure(ccx, sub_path, decl,
body, llfn, no_self,
/*bad*/ copy bcx.fcx.param_substs, user_id, None,
trans_closure(ccx,
sub_path,
decl,
body,
llfn,
no_self,
/*bad*/ copy bcx.fcx.param_substs,
user_id,
None,
[],
|fcx| load_environment(fcx, cdata_ty, cap_vars,
ret_handle.is_some(), sigil),
|bcx| {

View File

@ -316,11 +316,11 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
{
let llwrapfn = get_item_val(ccx, id);
let tys = shim_types(ccx, id);
if attr::attrs_contains_name(
foreign_item.attrs, "rust_stack")
{
if attr::attrs_contains_name(foreign_item.attrs, "rust_stack") {
build_direct_fn(ccx, llwrapfn, foreign_item,
&tys, cc);
} else if attr::attrs_contains_name(foreign_item.attrs, "fast_ffi") {
build_fast_ffi_fn(ccx, llwrapfn, foreign_item, &tys, cc);
} else {
let llshimfn = build_shim_fn(ccx, foreign_item,
&tys, cc);
@ -380,6 +380,8 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
fn build_direct_fn(ccx: @CrateContext, decl: ValueRef,
item: @ast::foreign_item, tys: &ShimTypes,
cc: lib::llvm::CallConv) {
debug!("build_direct_fn(%s)", *link_name(ccx, item));
let fcx = new_fn_ctxt(ccx, ~[], decl, None);
let bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
let llbasefn = base_fn(ccx, *link_name(ccx, item), tys, cc);
@ -389,7 +391,36 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
get_param(decl, i + first_real_arg)
});
let retval = Call(bcx, llbasefn, args);
if !ty::type_is_nil(ty::ty_fn_ret(ty)) {
let ret_ty = ty::ty_fn_ret(ty);
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr);
}
build_return(bcx);
finish_fn(fcx, lltop);
}
// FIXME (#2535): this is very shaky and probably gets ABIs wrong all
// over the place
fn build_fast_ffi_fn(ccx: @CrateContext,
decl: ValueRef,
item: @ast::foreign_item,
tys: &ShimTypes,
cc: lib::llvm::CallConv) {
debug!("build_fast_ffi_fn(%s)", *link_name(ccx, item));
let fcx = new_fn_ctxt(ccx, ~[], decl, None);
let bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
let llbasefn = base_fn(ccx, *link_name(ccx, item), tys, cc);
set_no_inline(fcx.llfn);
set_fixed_stack_segment(fcx.llfn);
let ty = ty::lookup_item_type(ccx.tcx,
ast_util::local_def(item.id)).ty;
let args = vec::from_fn(ty::ty_fn_args(ty).len(), |i| {
get_param(decl, i + first_real_arg)
});
let retval = Call(bcx, llbasefn, args);
let ret_ty = ty::ty_fn_ret(ty);
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr);
}
build_return(bcx);
@ -1006,7 +1037,16 @@ pub fn trans_foreign_fn(ccx: @CrateContext,
)));
let llty = type_of_fn_from_ty(ccx, t);
let llfndecl = decl_internal_cdecl_fn(ccx.llmod, ps, llty);
trans_fn(ccx, path, decl, body, llfndecl, no_self, None, id, None);
trans_fn(ccx,
path,
decl,
body,
llfndecl,
no_self,
None,
id,
None,
[]);
return llfndecl;
}

View File

@ -116,7 +116,8 @@ pub fn maybe_instantiate_inline(ccx: @CrateContext, fn_id: ast::def_id,
self_kind,
None,
mth.id,
Some(impl_did));
Some(impl_did),
[]);
}
local_def(mth.id)
}

View File

@ -137,7 +137,8 @@ pub fn trans_method(ccx: @CrateContext,
self_arg,
param_substs,
method.id,
Some(impl_id));
Some(impl_id),
[]);
}
pub fn trans_self_arg(bcx: block,

View File

@ -195,7 +195,16 @@ pub fn monomorphic_fn(ccx: @CrateContext,
}, _) => {
let d = mk_lldecl();
set_inline_hint_if_appr(/*bad*/copy i.attrs, d);
trans_fn(ccx, pt, decl, body, d, no_self, psubsts, fn_id.node, None);
trans_fn(ccx,
pt,
decl,
body,
d,
no_self,
psubsts,
fn_id.node,
None,
[]);
d
}
ast_map::node_item(*) => {

View File

@ -457,8 +457,9 @@ rust_task::get_next_stack_size(size_t min, size_t current, size_t requested) {
"min: %" PRIdPTR " current: %" PRIdPTR " requested: %" PRIdPTR,
min, current, requested);
// Allocate at least enough to accomodate the next frame
size_t sz = std::max(min, requested);
// Allocate at least enough to accomodate the next frame, plus a little
// slack to avoid thrashing
size_t sz = std::max(min, requested + (requested / 2));
// And double the stack size each allocation
const size_t max = 1024 * 1024;

View File

@ -191,6 +191,14 @@ rust_upcall_malloc(type_desc *td, uintptr_t size) {
return upcall_malloc(td, size);
}
extern "C" CDECL uintptr_t
rust_upcall_malloc_noswitch(type_desc *td, uintptr_t size) {
rust_task *task = rust_get_current_task();
s_malloc_args args = {task, 0, td, size};
upcall_s_malloc(&args);
return args.retval;
}
/**********************************************************************
* Called whenever an object in the task-local heap is freed.
*/
@ -231,6 +239,13 @@ rust_upcall_free(void* ptr) {
upcall_free(ptr);
}
extern "C" CDECL void
rust_upcall_free_noswitch(void* ptr) {
rust_task *task = rust_get_current_task();
s_free_args args = {task,ptr};
upcall_s_free(&args);
}
/**********************************************************************/
extern "C" _Unwind_Reason_Code

View File

@ -66,7 +66,9 @@ upcall_del_stack
upcall_reset_stack_limit
rust_upcall_fail
rust_upcall_free
rust_upcall_free_noswitch
rust_upcall_malloc
rust_upcall_malloc_noswitch
rust_uv_loop_new
rust_uv_loop_delete
rust_uv_walk

View File

@ -451,6 +451,7 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR,
TargetOptions Options;
Options.NoFramePointerElim = true;
Options.EnableSegmentedStacks = EnableSegmentedStacks;
Options.FixedStackSegmentSize = 2 * 1024 * 1024; // XXX: This is too big.
PassManager *PM = unwrap<PassManager>(PMR);

View File

@ -25,20 +25,6 @@ use std::ebml;
use std::serialize::{Decodable, Encodable};
use std::time;
<<<<<<< HEAD
=======
fn test_prettyprint<A:Encodable<prettyprint::Serializer>>(
a: &A,
expected: &~str
) {
let s = do io::with_str_writer |w| {
a.encode(&prettyprint::Serializer(w))
};
debug!("s == %?", s);
assert!(s == *expected);
}
>>>>>>> librustc: Remove `fail_unless!`
fn test_ebml<A:
Eq +
Encodable<EBWriter::Encoder> +