auto merge of #8535 : nikomatsakis/rust/issue-3678-wrappers-be-gone-2, r=graydon

Long-standing branch to remove foreign function wrappers altogether. Calls to C functions are done "in place" with no stack manipulation; the scheme relies entirely on the correct use of `#[fixed_stack_segment]` to guarantee adequate stack space. A linter is added to detect when `#[fixed_stack_segment]` annotations are missing. An `externfn!` macro is added to make it easier to declare foreign fns and wrappers in one go: this macro may need some refinement, though, for example it might be good to be able to declare a group of foreign fns. I leave that for future work (hopefully somebody else's work :) ).

Fixes #3678.
This commit is contained in:
bors 2013-08-19 04:32:04 -07:00
commit 81a78161b5
103 changed files with 2619 additions and 1684 deletions

View file

@ -19,6 +19,7 @@ extern {
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
}
#[fixed_stack_segment]
fn main() {
let x = unsafe { snappy_max_compressed_length(100) };
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
@ -35,6 +36,11 @@ interfaces that aren't thread-safe, and almost any function that takes a pointer
valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of
Rust's safe memory model.
Finally, the `#[fixed_stack_segment]` annotation that appears on
`main()` instructs the Rust compiler that when `main()` executes, it
should request a "very large" stack segment. More details on
stack management can be found in the following sections.
When declaring the argument types to a foreign function, the Rust compiler will not check if the
declaration is correct, so specifying it correctly is part of keeping the binding correct at
runtime.
@ -75,6 +81,8 @@ length is number of elements currently contained, and the capacity is the total
the allocated memory. The length is less than or equal to the capacity.
~~~~ {.xfail-test}
#[fixed_stack_segment]
#[inline(never)]
pub fn validate_compressed_buffer(src: &[u8]) -> bool {
unsafe {
snappy_validate_compressed_buffer(vec::raw::to_ptr(src), src.len() as size_t) == 0
@ -86,6 +94,36 @@ The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, b
guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
signature.
The `validate_compressed_buffer` wrapper is also annotated with two
attributes `#[fixed_stack_segment]` and `#[inline(never)]`. The
purpose of these attributes is to guarantee that there will be
sufficient stack for the C function to execute. This is necessary
because Rust, unlike C, does not assume that the stack is allocated in
one continuous chunk. Instead, we rely on a *segmented stack* scheme,
in which the stack grows and shrinks as necessary. C code, however,
expects one large stack, and so callers of C functions must request a
large stack segment to ensure that the C routine will not run off the
end of the stack.
The compiler includes a lint mode that will report an error if you
call a C function without a `#[fixed_stack_segment]` attribute. More
details on the lint mode are given in a later section.
You may be wondering why we include a `#[inline(never)]` directive.
This directive informs the compiler never to inline this function.
While not strictly necessary, it is usually a good idea to use an
`#[inline(never)]` directive in concert with `#[fixed_stack_segment]`.
The reason is that if a fn annotated with `fixed_stack_segment` is
inlined, then its caller also inherits the `fixed_stack_segment`
annotation. This means that rather than requesting a large stack
segment only for the duration of the call into C, the large stack
segment would be used for the entire duration of the caller. This is
not necessarily *bad* -- it can for example be more efficient,
particularly if `validate_compressed_buffer()` is called multiple
times in a row -- but it does work against the purpose of the
segmented stack scheme, which is to keep stacks small and thus
conserve address space.
The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be
allocated to hold the output too.
@ -96,6 +134,8 @@ the true length after compression for setting the length.
~~~~ {.xfail-test}
pub fn compress(src: &[u8]) -> ~[u8] {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let srclen = src.len() as size_t;
let psrc = vec::raw::to_ptr(src);
@ -116,6 +156,8 @@ format and `snappy_uncompressed_length` will retrieve the exact buffer size requ
~~~~ {.xfail-test}
pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let srclen = src.len() as size_t;
let psrc = vec::raw::to_ptr(src);
@ -139,6 +181,99 @@ pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
For reference, the examples used here are also available as an [library on
GitHub](https://github.com/thestinger/rust-snappy).
# Automatic wrappers
Sometimes writing Rust wrappers can be quite tedious. For example, if
function does not take any pointer arguments, often there is no need
for translating types. In such cases, it is usually still a good idea
to have a Rust wrapper so as to manage the segmented stacks, but you
can take advantage of the (standard) `externfn!` macro to remove some
of the tedium.
In the initial section, we showed an extern block that added a call
to a specific snappy API:
~~~~ {.xfail-test}
use std::libc::size_t;
#[link_args = "-lsnappy"]
extern {
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
}
#[fixed_stack_segment]
fn main() {
let x = unsafe { snappy_max_compressed_length(100) };
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
}
~~~~
To avoid the need to create a wrapper fn for `snappy_max_compressed_length()`,
and also to avoid the need to think about `#[fixed_stack_segment]`, we
could simply use the `externfn!` macro instead, as shown here:
~~~~ {.xfail-test}
use std::libc::size_t;
externfn!(#[link_args = "-lsnappy"]
fn snappy_max_compressed_length(source_length: size_t) -> size_t)
fn main() {
let x = unsafe { snappy_max_compressed_length(100) };
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
}
~~~~
As you can see from the example, `externfn!` replaces the extern block
entirely. After macro expansion, it will create something like this:
~~~~ {.xfail-test}
use std::libc::size_t;
// Automatically generated by
// externfn!(#[link_args = "-lsnappy"]
// fn snappy_max_compressed_length(source_length: size_t) -> size_t)
unsafe fn snappy_max_compressed_length(source_length: size_t) -> size_t {
#[fixed_stack_segment]; #[inline(never)];
return snappy_max_compressed_length(source_length);
#[link_args = "-lsnappy"]
extern {
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
}
}
fn main() {
let x = unsafe { snappy_max_compressed_length(100) };
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
}
~~~~
# Segmented stacks and the linter
By default, whenever you invoke a non-Rust fn, the `cstack` lint will
check that one of the following conditions holds:
1. The call occurs inside of a fn that has been annotated with
`#[fixed_stack_segment]`;
2. The call occurs inside of an `extern fn`;
3. The call occurs within a stack closure created by some other
safe fn.
All of these conditions ensure that you are running on a large stack
segmented. However, they are sometimes too strict. If your application
will be making many calls into C, it is often beneficial to promote
the `#[fixed_stack_segment]` attribute higher up the call chain. For
example, the Rust compiler actually labels main itself as requiring a
`#[fixed_stack_segment]`. In such cases, the linter is just an
annoyance, because all C calls that occur from within the Rust
compiler are made on a large stack. Another situation where this
frequently occurs is on a 64-bit architecture, where large stacks are
the default. In cases, you can disable the linter by including a
`#[allow(cstack)]` directive somewhere, which permits violations of
the "cstack" rules given above (you can also use `#[warn(cstack)]` to
convert the errors into warnings, if you prefer).
# Destructors
Foreign libraries often hand off ownership of resources to the calling code,
@ -161,6 +296,9 @@ pub struct Unique<T> {
impl<T: Send> Unique<T> {
pub fn new(value: T) -> Unique<T> {
#[fixed_stack_segment];
#[inline(never)];
unsafe {
let ptr = malloc(std::sys::size_of::<T>() as size_t) as *mut T;
assert!(!ptr::is_null(ptr));
@ -184,6 +322,9 @@ impl<T: Send> Unique<T> {
#[unsafe_destructor]
impl<T: Send> Drop for Unique<T> {
fn drop(&self) {
#[fixed_stack_segment];
#[inline(never)];
unsafe {
let x = intrinsics::init(); // dummy value to swap in
// moving the object out is needed to call the destructor

View file

@ -155,12 +155,20 @@ mod tests {
use std::libc;
fn malloc(n: size_t) -> CVec<u8> {
#[fixed_stack_segment];
#[inline(never)];
unsafe {
let mem = libc::malloc(n);
assert!(mem as int != 0);
c_vec_with_dtor(mem as *mut u8, n as uint, || free(mem))
return c_vec_with_dtor(mem as *mut u8, n as uint, || f(mem));
}
fn f(mem: *c_void) {
#[fixed_stack_segment]; #[inline(never)];
unsafe { libc::free(mem) }
}
}

View file

@ -47,6 +47,8 @@ static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adle
static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
#[fixed_stack_segment]; #[inline(never)];
do bytes.as_imm_buf |b, len| {
unsafe {
let mut outsz : size_t = 0;
@ -73,6 +75,8 @@ pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
}
fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
#[fixed_stack_segment]; #[inline(never)];
do bytes.as_imm_buf |b, len| {
unsafe {
let mut outsz : size_t = 0;

View file

@ -19,15 +19,25 @@ use std::str;
pub mod rustrt {
use std::libc::{c_char, c_int};
extern {
pub fn linenoise(prompt: *c_char) -> *c_char;
pub fn linenoiseHistoryAdd(line: *c_char) -> c_int;
pub fn linenoiseHistorySetMaxLen(len: c_int) -> c_int;
pub fn linenoiseHistorySave(file: *c_char) -> c_int;
pub fn linenoiseHistoryLoad(file: *c_char) -> c_int;
pub fn linenoiseSetCompletionCallback(callback: *u8);
pub fn linenoiseAddCompletion(completions: *(), line: *c_char);
#[cfg(stage0)]
mod macro_hack {
#[macro_escape];
macro_rules! externfn(
(fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
extern {
fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
}
)
)
}
externfn!(fn linenoise(prompt: *c_char) -> *c_char)
externfn!(fn linenoiseHistoryAdd(line: *c_char) -> c_int)
externfn!(fn linenoiseHistorySetMaxLen(len: c_int) -> c_int)
externfn!(fn linenoiseHistorySave(file: *c_char) -> c_int)
externfn!(fn linenoiseHistoryLoad(file: *c_char) -> c_int)
externfn!(fn linenoiseSetCompletionCallback(callback: *u8))
externfn!(fn linenoiseAddCompletion(completions: *(), line: *c_char))
}
/// Add a line to history
@ -84,7 +94,7 @@ pub unsafe fn complete(cb: CompletionCb) {
rustrt::linenoiseAddCompletion(completions, buf);
}
}
}
}
}
}

View file

@ -188,6 +188,8 @@ fn optgroups() -> ~[getopts::groups::OptGroup] {
}
fn usage(binary: &str, helpstr: &str) -> ! {
#[fixed_stack_segment]; #[inline(never)];
let message = fmt!("Usage: %s [OPTIONS] [FILTER]", binary);
println(groups::usage(message, optgroups()));
println("");

View file

@ -64,6 +64,8 @@ impl Ord for Timespec {
* nanoseconds since 1970-01-01T00:00:00Z.
*/
pub fn get_time() -> Timespec {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let mut sec = 0i64;
let mut nsec = 0i32;
@ -78,6 +80,8 @@ pub fn get_time() -> Timespec {
* in nanoseconds since an unspecified epoch.
*/
pub fn precise_time_ns() -> u64 {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let mut ns = 0u64;
rustrt::precise_time_ns(&mut ns);
@ -95,6 +99,8 @@ pub fn precise_time_s() -> float {
}
pub fn tzset() {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
rustrt::rust_tzset();
}
@ -135,6 +141,8 @@ pub fn empty_tm() -> Tm {
/// Returns the specified time in UTC
pub fn at_utc(clock: Timespec) -> Tm {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let Timespec { sec, nsec } = clock;
let mut tm = empty_tm();
@ -150,6 +158,8 @@ pub fn now_utc() -> Tm {
/// Returns the specified time in the local timezone
pub fn at(clock: Timespec) -> Tm {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let Timespec { sec, nsec } = clock;
let mut tm = empty_tm();
@ -176,6 +186,8 @@ pub fn strftime(format: &str, tm: &Tm) -> ~str {
impl Tm {
/// Convert time to the seconds from January 1, 1970
pub fn to_timespec(&self) -> Timespec {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let sec = match self.tm_gmtoff {
0_i32 => rustrt::rust_timegm(self),

View file

@ -229,6 +229,8 @@ fn usage() {
}
pub fn main() {
#[fixed_stack_segment]; #[inline(never)];
let os_args = os::args();
if (os_args.len() > 1 && (os_args[1] == ~"-v" || os_args[1] == ~"--version")) {

View file

@ -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
}
@ -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())
}

View file

@ -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", ||
@ -642,9 +645,13 @@ pub fn build_session_options(binary: @str,
}
debugging_opts |= this_bit;
}
if debugging_opts & session::debug_llvm != 0 {
unsafe {
llvm::LLVMSetDebug(1);
set_llvm_debug();
fn set_llvm_debug() {
#[fixed_stack_segment]; #[inline(never)];
unsafe { llvm::LLVMSetDebug(1); }
}
}

View file

@ -8,6 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// LLVM wrappers are intended to be called from trans,
// which already runs in a #[fixed_stack_segment]
#[allow(cstack)];
use std::c_str::ToCStr;
use std::hashmap::HashMap;
use std::libc::{c_uint, c_ushort};
@ -2246,6 +2250,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));

View file

@ -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,
@ -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,

View file

@ -0,0 +1,159 @@
// 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::ast_map;
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>)) {
match item.node {
ast::item_fn(_, ast::extern_fn, _, _, _) => {
// an extern fn is already being called from C code...
let new_cx = Context {safe_stack: true, ..in_cx};
visit::visit_item(item, (new_cx, v));
}
ast::item_fn(*) => {
let safe_stack = fixed_stack_segment(item.attrs);
let new_cx = Context {safe_stack: safe_stack, ..in_cx};
visit::visit_item(item, (new_cx, v));
}
ast::item_impl(_, _, _, ref methods) => {
// visit_method() would make this nicer
for &method in methods.iter() {
let safe_stack = fixed_stack_segment(method.attrs);
let new_cx = Context {safe_stack: safe_stack, ..in_cx};
visit::visit_method_helper(method, (new_cx, v));
}
}
_ => {
visit::visit_item(item, (in_cx, v));
}
}
fn fixed_stack_segment(attrs: &[ast::Attribute]) -> bool {
attr::contains_name(attrs, "fixed_stack_segment")
}
}
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_method(*) | visit::fk_item_fn(*) => {
in_cx.safe_stack // see stack_check_item above
}
visit::fk_anon(*) | visit::fk_fn_block => {
match ty::get(ty::node_id_to_type(in_cx.tcx, id)).sty {
ty::ty_bare_fn(*) |
ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) |
ty::ty_closure(ty::ClosureTy {sigil: ast::ManagedSigil, _}) => {
false
}
_ => {
in_cx.safe_stack
}
}
}
};
let new_cx = Context {safe_stack: safe_stack, ..in_cx};
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() {
call_to_extern_fn(cx, callee);
}
}
_ => {}
}
}
_ => {}
}
}
visit::visit_expr(expr, (cx, v));
}
fn call_to_extern_fn(cx: Context, callee: @ast::expr) {
// Permit direct calls to extern fns that are annotated with
// #[rust_stack]. This is naturally a horrible pain to achieve.
match callee.node {
ast::expr_path(*) => {
match cx.tcx.def_map.find(&callee.id) {
Some(&ast::def_fn(id, _)) if id.crate == ast::LOCAL_CRATE => {
match cx.tcx.items.find(&id.node) {
Some(&ast_map::node_foreign_item(item, _, _, _)) => {
if attr::contains_name(item.attrs, "rust_stack") {
return;
}
}
_ => {}
}
}
_ => {}
}
}
_ => {}
}
cx.tcx.sess.add_lint(lint::cstack,
callee.id,
callee.span,
fmt!("invoking non-Rust fn in fn without \
#[fixed_stack_segment]"));
}

View file

@ -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;
}
}
@ -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,
@ -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);
@ -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);
@ -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 {
@ -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(),
@ -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
}
@ -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);
}
@ -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());
@ -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,
@ -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() {
@ -2291,8 +2296,7 @@ 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);
@ -2300,7 +2304,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext,
// 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.
@ -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
@ -2502,16 +2509,14 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
register_method(ccx, id, pth, m)
}
ast_map::node_foreign_item(ni, _, _, pth) => {
ast_map::node_foreign_item(ni, abis, _, pth) => {
let ty = ty::node_id_to_type(ccx.tcx, ni.id);
exprt = true;
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);

View file

@ -8,19 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use lib::llvm::{llvm, ValueRef, Attribute, Void};
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::common::*;
use middle::trans::type_::Type;
use std::libc::c_uint;
use lib::llvm::Attribute;
use std::option;
pub trait ABIInfo {
fn compute_info(&self, atys: &[Type], rty: Type, ret_def: bool) -> FnType;
}
use middle::trans::context::CrateContext;
use middle::trans::cabi_x86;
use middle::trans::cabi_x86_64;
use middle::trans::cabi_arm;
use middle::trans::cabi_mips;
use middle::trans::type_::Type;
use syntax::abi::{X86, X86_64, Arm, Mips};
#[deriving(Clone)]
pub struct LLVMType {
@ -28,149 +24,38 @@ pub struct LLVMType {
ty: Type
}
/// Metadata describing how the arguments to a native function
/// should be passed in order to respect the native ABI.
///
/// I will do my best to describe this structure, but these
/// comments are reverse-engineered and may be inaccurate. -NDM
pub struct FnType {
/// The LLVM types of each argument. If the cast flag is true,
/// then the argument should be cast, typically because the
/// official argument type will be an int and the rust type is i8
/// or something like that.
arg_tys: ~[LLVMType],
ret_ty: LLVMType,
/// A list of attributes to be attached to each argument (parallel
/// the `arg_tys` array). If the attribute for a given is Some,
/// then the argument should be passed by reference.
attrs: ~[option::Option<Attribute>],
/// LLVM return type.
ret_ty: LLVMType,
/// If true, then an implicit pointer should be added for the result.
sret: bool
}
impl FnType {
pub fn decl_fn(&self, decl: &fn(fnty: Type) -> ValueRef) -> ValueRef {
let atys = self.arg_tys.iter().map(|t| t.ty).collect::<~[Type]>();
let rty = self.ret_ty.ty;
let fnty = Type::func(atys, &rty);
let llfn = decl(fnty);
for (i, a) in self.attrs.iter().enumerate() {
match *a {
option::Some(attr) => {
unsafe {
let llarg = get_param(llfn, i);
llvm::LLVMAddAttribute(llarg, attr as c_uint);
}
}
_ => ()
}
}
return llfn;
}
pub fn build_shim_args(&self, bcx: @mut Block, arg_tys: &[Type], llargbundle: ValueRef)
-> ~[ValueRef] {
let mut atys: &[LLVMType] = self.arg_tys;
let mut attrs: &[option::Option<Attribute>] = self.attrs;
let mut llargvals = ~[];
let mut i = 0u;
let n = arg_tys.len();
if self.sret {
let llretptr = GEPi(bcx, llargbundle, [0u, n]);
let llretloc = Load(bcx, llretptr);
llargvals = ~[llretloc];
atys = atys.tail();
attrs = attrs.tail();
}
while i < n {
let llargval = if atys[i].cast {
let arg_ptr = GEPi(bcx, llargbundle, [0u, i]);
let arg_ptr = BitCast(bcx, arg_ptr, atys[i].ty.ptr_to());
Load(bcx, arg_ptr)
} else if attrs[i].is_some() {
GEPi(bcx, llargbundle, [0u, i])
} else {
load_inbounds(bcx, llargbundle, [0u, i])
};
llargvals.push(llargval);
i += 1u;
}
return llargvals;
}
pub fn build_shim_ret(&self, bcx: @mut Block, arg_tys: &[Type], ret_def: bool,
llargbundle: ValueRef, llretval: ValueRef) {
for (i, a) in self.attrs.iter().enumerate() {
match *a {
option::Some(attr) => {
unsafe {
llvm::LLVMAddInstrAttribute(llretval, (i + 1u) as c_uint, attr as c_uint);
}
}
_ => ()
}
}
if self.sret || !ret_def {
return;
}
let n = arg_tys.len();
// R** llretptr = &args->r;
let llretptr = GEPi(bcx, llargbundle, [0u, n]);
// R* llretloc = *llretptr; /* (args->r) */
let llretloc = Load(bcx, llretptr);
if self.ret_ty.cast {
let tmp_ptr = BitCast(bcx, llretloc, self.ret_ty.ty.ptr_to());
// *args->r = r;
Store(bcx, llretval, tmp_ptr);
} else {
// *args->r = r;
Store(bcx, llretval, llretloc);
};
}
pub fn build_wrap_args(&self, bcx: @mut Block, ret_ty: Type,
llwrapfn: ValueRef, llargbundle: ValueRef) {
let mut atys: &[LLVMType] = self.arg_tys;
let mut attrs: &[option::Option<Attribute>] = self.attrs;
let mut j = 0u;
let llretptr = if self.sret {
atys = atys.tail();
attrs = attrs.tail();
j = 1u;
get_param(llwrapfn, 0u)
} else if self.ret_ty.cast {
let retptr = alloca(bcx, self.ret_ty.ty, "");
BitCast(bcx, retptr, ret_ty.ptr_to())
} else {
alloca(bcx, ret_ty, "")
};
let mut i = 0u;
let n = atys.len();
while i < n {
let mut argval = get_param(llwrapfn, i + j);
if attrs[i].is_some() {
argval = Load(bcx, argval);
store_inbounds(bcx, argval, llargbundle, [0u, i]);
} else if atys[i].cast {
let argptr = GEPi(bcx, llargbundle, [0u, i]);
let argptr = BitCast(bcx, argptr, atys[i].ty.ptr_to());
Store(bcx, argval, argptr);
} else {
store_inbounds(bcx, argval, llargbundle, [0u, i]);
}
i += 1u;
}
store_inbounds(bcx, llretptr, llargbundle, [0u, n]);
}
pub fn build_wrap_ret(&self, bcx: @mut Block, arg_tys: &[Type], llargbundle: ValueRef) {
if self.ret_ty.ty.kind() == Void {
return;
}
if bcx.fcx.llretptr.is_some() {
let llretval = load_inbounds(bcx, llargbundle, [ 0, arg_tys.len() ]);
let llretval = if self.ret_ty.cast {
let retptr = BitCast(bcx, llretval, self.ret_ty.ty.ptr_to());
Load(bcx, retptr)
} else {
Load(bcx, llretval)
};
let llretptr = BitCast(bcx, bcx.fcx.llretptr.unwrap(), self.ret_ty.ty.ptr_to());
Store(bcx, llretval, llretptr);
}
pub fn compute_abi_info(ccx: &mut CrateContext,
atys: &[Type],
rty: Type,
ret_def: bool) -> FnType {
match ccx.sess.targ_cfg.arch {
X86 => cabi_x86::compute_abi_info(ccx, atys, rty, ret_def),
X86_64 => cabi_x86_64::compute_abi_info(ccx, atys, rty, ret_def),
Arm => cabi_arm::compute_abi_info(ccx, atys, rty, ret_def),
Mips => cabi_mips::compute_abi_info(ccx, atys, rty, ret_def),
}
}

View file

@ -10,7 +10,8 @@
use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
use lib::llvm::{Attribute, StructRetAttribute};
use middle::trans::cabi::{ABIInfo, FnType, LLVMType};
use middle::trans::cabi::{FnType, LLVMType};
use middle::trans::context::CrateContext;
use middle::trans::type_::Type;
@ -124,45 +125,37 @@ fn is_reg_ty(ty: Type) -> bool {
}
}
enum ARM_ABIInfo { ARM_ABIInfo }
impl ABIInfo for ARM_ABIInfo {
fn compute_info(&self,
atys: &[Type],
rty: Type,
ret_def: bool) -> FnType {
let mut arg_tys = ~[];
let mut attrs = ~[];
for &aty in atys.iter() {
let (ty, attr) = classify_arg_ty(aty);
arg_tys.push(ty);
attrs.push(attr);
}
let (ret_ty, ret_attr) = if ret_def {
classify_ret_ty(rty)
} else {
(LLVMType { cast: false, ty: Type::void() }, None)
};
let mut ret_ty = ret_ty;
let sret = ret_attr.is_some();
if sret {
arg_tys.unshift(ret_ty);
attrs.unshift(ret_attr);
ret_ty = LLVMType { cast: false, ty: Type::void() };
}
return FnType {
arg_tys: arg_tys,
ret_ty: ret_ty,
attrs: attrs,
sret: sret
};
pub fn compute_abi_info(_ccx: &mut CrateContext,
atys: &[Type],
rty: Type,
ret_def: bool) -> FnType {
let mut arg_tys = ~[];
let mut attrs = ~[];
for &aty in atys.iter() {
let (ty, attr) = classify_arg_ty(aty);
arg_tys.push(ty);
attrs.push(attr);
}
}
pub fn abi_info() -> @ABIInfo {
return @ARM_ABIInfo as @ABIInfo;
let (ret_ty, ret_attr) = if ret_def {
classify_ret_ty(rty)
} else {
(LLVMType { cast: false, ty: Type::void() }, None)
};
let mut ret_ty = ret_ty;
let sret = ret_attr.is_some();
if sret {
arg_tys.unshift(ret_ty);
attrs.unshift(ret_attr);
ret_ty = LLVMType { cast: false, ty: Type::void() };
}
return FnType {
arg_tys: arg_tys,
ret_ty: ret_ty,
attrs: attrs,
sret: sret
};
}

View file

@ -14,6 +14,7 @@ use std::num;
use std::vec;
use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
use lib::llvm::{Attribute, StructRetAttribute};
use middle::trans::context::CrateContext;
use middle::trans::context::task_llcx;
use middle::trans::cabi::*;
@ -170,47 +171,39 @@ fn struct_ty(ty: Type,
return Type::struct_(fields, false);
}
enum MIPS_ABIInfo { MIPS_ABIInfo }
pub fn compute_abi_info(_ccx: &mut CrateContext,
atys: &[Type],
rty: Type,
ret_def: bool) -> FnType {
let (ret_ty, ret_attr) = if ret_def {
classify_ret_ty(rty)
} else {
(LLVMType { cast: false, ty: Type::void() }, None)
};
impl ABIInfo for MIPS_ABIInfo {
fn compute_info(&self,
atys: &[Type],
rty: Type,
ret_def: bool) -> FnType {
let (ret_ty, ret_attr) = if ret_def {
classify_ret_ty(rty)
} else {
(LLVMType { cast: false, ty: Type::void() }, None)
};
let mut ret_ty = ret_ty;
let mut ret_ty = ret_ty;
let sret = ret_attr.is_some();
let mut arg_tys = ~[];
let mut attrs = ~[];
let mut offset = if sret { 4 } else { 0 };
let sret = ret_attr.is_some();
let mut arg_tys = ~[];
let mut attrs = ~[];
let mut offset = if sret { 4 } else { 0 };
for aty in atys.iter() {
let (ty, attr) = classify_arg_ty(*aty, &mut offset);
arg_tys.push(ty);
attrs.push(attr);
};
for aty in atys.iter() {
let (ty, attr) = classify_arg_ty(*aty, &mut offset);
arg_tys.push(ty);
attrs.push(attr);
};
if sret {
arg_tys = vec::append(~[ret_ty], arg_tys);
attrs = vec::append(~[ret_attr], attrs);
ret_ty = LLVMType { cast: false, ty: Type::void() };
}
return FnType {
arg_tys: arg_tys,
ret_ty: ret_ty,
attrs: attrs,
sret: sret
};
if sret {
arg_tys = vec::append(~[ret_ty], arg_tys);
attrs = vec::append(~[ret_attr], attrs);
ret_ty = LLVMType { cast: false, ty: Type::void() };
}
}
pub fn abi_info() -> @ABIInfo {
return @MIPS_ABIInfo as @ABIInfo;
return FnType {
arg_tys: arg_tys,
ret_ty: ret_ty,
attrs: attrs,
sret: sret
};
}

View file

@ -14,70 +14,87 @@ use lib::llvm::*;
use super::cabi::*;
use super::common::*;
use super::machine::*;
use middle::trans::type_::Type;
struct X86_ABIInfo {
ccx: @mut CrateContext
}
pub fn compute_abi_info(ccx: &mut CrateContext,
atys: &[Type],
rty: Type,
ret_def: bool) -> FnType {
let mut arg_tys = ~[];
let mut attrs = ~[];
impl ABIInfo for X86_ABIInfo {
fn compute_info(&self,
atys: &[Type],
rty: Type,
ret_def: bool) -> FnType {
let mut arg_tys = do atys.map |a| {
LLVMType { cast: false, ty: *a }
let ret_ty;
let sret;
if !ret_def {
ret_ty = LLVMType {
cast: false,
ty: Type::void(),
};
let mut ret_ty = LLVMType {
sret = false;
} else if rty.kind() == Struct {
// Returning a structure. Most often, this will use
// a hidden first argument. On some platforms, though,
// small structs are returned as integers.
//
// Some links:
// http://www.angelcode.com/dev/callconv/callconv.html
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
enum Strategy { RetValue(Type), RetPointer }
let strategy = match ccx.sess.targ_cfg.os {
os_win32 | os_macos => {
match llsize_of_alloc(ccx, rty) {
1 => RetValue(Type::i8()),
2 => RetValue(Type::i16()),
4 => RetValue(Type::i32()),
8 => RetValue(Type::i64()),
_ => RetPointer
}
}
_ => {
RetPointer
}
};
match strategy {
RetValue(t) => {
ret_ty = LLVMType {
cast: true,
ty: t
};
sret = false;
}
RetPointer => {
arg_tys.push(LLVMType {
cast: false,
ty: rty.ptr_to()
});
attrs.push(Some(StructRetAttribute));
ret_ty = LLVMType {
cast: false,
ty: Type::void(),
};
sret = true;
}
}
} else {
ret_ty = LLVMType {
cast: false,
ty: rty
};
let mut attrs = do atys.map |_| {
None
};
// Rules for returning structs taken from
// http://www.angelcode.com/dev/callconv/callconv.html
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
let sret = {
let returning_a_struct = rty.kind() == Struct && ret_def;
let big_struct = match self.ccx.sess.targ_cfg.os {
os_win32 | os_macos => llsize_of_alloc(self.ccx, rty) > 8,
_ => true
};
returning_a_struct && big_struct
};
if sret {
let ret_ptr_ty = LLVMType {
cast: false,
ty: ret_ty.ty.ptr_to()
};
arg_tys = ~[ret_ptr_ty] + arg_tys;
attrs = ~[Some(StructRetAttribute)] + attrs;
ret_ty = LLVMType {
cast: false,
ty: Type::void(),
};
} else if !ret_def {
ret_ty = LLVMType {
cast: false,
ty: Type::void()
};
}
return FnType {
arg_tys: arg_tys,
ret_ty: ret_ty,
attrs: attrs,
sret: sret
};
sret = false;
}
}
pub fn abi_info(ccx: @mut CrateContext) -> @ABIInfo {
return @X86_ABIInfo {
ccx: ccx
} as @ABIInfo;
for &a in atys.iter() {
arg_tys.push(LLVMType { cast: false, ty: a });
attrs.push(None);
}
return FnType {
arg_tys: arg_tys,
ret_ty: ret_ty,
attrs: attrs,
sret: sret
};
}

View file

@ -15,6 +15,7 @@ use lib::llvm::{llvm, Integer, Pointer, Float, Double};
use lib::llvm::{Struct, Array, Attribute};
use lib::llvm::{StructRetAttribute, ByValAttribute};
use middle::trans::cabi::*;
use middle::trans::context::CrateContext;
use middle::trans::type_::Type;
@ -331,10 +332,10 @@ fn llreg_ty(cls: &[RegClass]) -> Type {
return Type::struct_(tys, false);
}
fn x86_64_tys(atys: &[Type],
rty: Type,
ret_def: bool) -> FnType {
pub fn compute_abi_info(_ccx: &mut CrateContext,
atys: &[Type],
rty: Type,
ret_def: bool) -> FnType {
fn x86_64_ty(ty: Type,
is_mem_cls: &fn(cls: &[RegClass]) -> bool,
attr: Attribute) -> (LLVMType, Option<Attribute>) {
@ -384,18 +385,3 @@ fn x86_64_tys(atys: &[Type],
sret: sret
};
}
enum X86_64_ABIInfo { X86_64_ABIInfo }
impl ABIInfo for X86_64_ABIInfo {
fn compute_info(&self,
atys: &[Type],
rty: Type,
ret_def: bool) -> FnType {
return x86_64_tys(atys, rty, ret_def);
}
}
pub fn abi_info() -> @ABIInfo {
return @X86_64_ABIInfo as @ABIInfo;
}

View file

@ -37,6 +37,7 @@ use middle::trans::inline;
use middle::trans::meth;
use middle::trans::monomorphize;
use middle::trans::type_of;
use middle::trans::foreign;
use middle::ty;
use middle::subst::Subst;
use middle::typeck;
@ -46,6 +47,7 @@ use util::ppaux::Repr;
use middle::trans::type_::Type;
use syntax::ast;
use syntax::abi::AbiSet;
use syntax::ast_map;
use syntax::oldvisit;
@ -240,20 +242,20 @@ pub fn trans_fn_ref_with_vtables(
type_params: &[ty::t], // values for fn's ty params
vtables: Option<typeck::vtable_res>) // vtables for the call
-> FnData {
//!
//
// Translates a reference to a fn/method item, monomorphizing and
// inlining as it goes.
//
// # Parameters
//
// - `bcx`: the current block where the reference to the fn occurs
// - `def_id`: def id of the fn or method item being referenced
// - `ref_id`: node id of the reference to the fn/method, if applicable.
// This parameter may be zero; but, if so, the resulting value may not
// have the right type, so it must be cast before being used.
// - `type_params`: values for each of the fn/method's type parameters
// - `vtables`: values for each bound on each of the type parameters
/*!
* Translates a reference to a fn/method item, monomorphizing and
* inlining as it goes.
*
* # Parameters
*
* - `bcx`: the current block where the reference to the fn occurs
* - `def_id`: def id of the fn or method item being referenced
* - `ref_id`: node id of the reference to the fn/method, if applicable.
* This parameter may be zero; but, if so, the resulting value may not
* have the right type, so it must be cast before being used.
* - `type_params`: values for each of the fn/method's type parameters
* - `vtables`: values for each bound on each of the type parameters
*/
let _icx = push_ctxt("trans_fn_ref_with_vtables");
let ccx = bcx.ccx();
@ -386,7 +388,7 @@ pub fn trans_fn_ref_with_vtables(
}
// Find the actual function pointer.
let val = {
let mut val = {
if def_id.crate == ast::LOCAL_CRATE {
// Internal reference.
get_item_val(ccx, def_id.node)
@ -396,6 +398,35 @@ pub fn trans_fn_ref_with_vtables(
}
};
// This is subtle and surprising, but sometimes we have to bitcast
// the resulting fn pointer. The reason has to do with external
// functions. If you have two crates that both bind the same C
// library, they may not use precisely the same types: for
// example, they will probably each declare their own structs,
// which are distinct types from LLVM's point of view (nominal
// types).
//
// Now, if those two crates are linked into an application, and
// they contain inlined code, you can wind up with a situation
// where both of those functions wind up being loaded into this
// application simultaneously. In that case, the same function
// (from LLVM's point of view) requires two types. But of course
// LLVM won't allow one function to have two types.
//
// What we currently do, therefore, is declare the function with
// one of the two types (whichever happens to come first) and then
// bitcast as needed when the function is referenced to make sure
// it has the type we expect.
//
// This can occur on either a crate-local or crate-external
// reference. It also occurs when testing libcore and in some
// other weird situations. Annoying.
let llty = type_of::type_of_fn_from_ty(ccx, fn_tpt.ty);
let llptrty = llty.ptr_to();
if val_ty(val) != llptrty {
val = BitCast(bcx, val, llptrty);
}
return FnData {llfn: val};
}
@ -543,16 +574,26 @@ pub fn body_contains_ret(body: &ast::Block) -> bool {
*cx
}
// See [Note-arg-mode]
pub fn trans_call_inner(in_cx: @mut Block,
call_info: Option<NodeInfo>,
fn_expr_ty: ty::t,
callee_ty: ty::t,
ret_ty: ty::t,
get_callee: &fn(@mut Block) -> Callee,
args: CallArgs,
dest: Option<expr::Dest>,
autoref_arg: AutorefArg)
-> Result {
/*!
* This behemoth of a function translates function calls.
* Unfortunately, in order to generate more efficient LLVM
* output at -O0, it has quite a complex signature (refactoring
* this into two functions seems like a good idea).
*
* In particular, for lang items, it is invoked with a dest of
* None, and
*/
do base::with_scope_result(in_cx, call_info, "call") |cx| {
let callee = get_callee(cx);
let mut bcx = callee.bcx;
@ -580,98 +621,125 @@ pub fn trans_call_inner(in_cx: @mut Block,
}
};
let llretslot = trans_ret_slot(bcx, fn_expr_ty, dest);
let abi = match ty::get(callee_ty).sty {
ty::ty_bare_fn(ref f) => f.abis,
_ => AbiSet::Rust()
};
let is_rust_fn =
abi.is_rust() ||
abi.is_intrinsic();
let mut llargs = ~[];
if !ty::type_is_immediate(bcx.tcx(), ret_ty) {
llargs.push(llretslot);
}
llargs.push(llenv);
bcx = trans_args(bcx, args, fn_expr_ty, autoref_arg, &mut llargs);
// Now that the arguments have finished evaluating, we need to revoke
// the cleanup for the self argument
match callee.data {
Method(d) => {
for &v in d.temp_cleanup.iter() {
revoke_clean(bcx, v);
}
// Generate a location to store the result. If the user does
// not care about the result, just make a stack slot.
let opt_llretslot = match dest {
None => {
assert!(!type_of::return_uses_outptr(in_cx.tcx(), ret_ty));
None
}
_ => {}
}
// Uncomment this to debug calls.
/*
printfln!("calling: %s", bcx.val_to_str(llfn));
for llarg in llargs.iter() {
printfln!("arg: %s", bcx.val_to_str(*llarg));
}
io::println("---");
*/
// If the block is terminated, then one or more of the args
// has type _|_. Since that means it diverges, the code for
// the call itself is unreachable.
let (llresult, new_bcx) = base::invoke(bcx, llfn, llargs);
bcx = new_bcx;
match dest {
None => { assert!(ty::type_is_immediate(bcx.tcx(), ret_ty)) }
Some(expr::SaveIn(dst)) => Some(dst),
Some(expr::Ignore) => {
// drop the value if it is not being saved.
if ty::type_needs_drop(bcx.tcx(), ret_ty) {
if ty::type_is_immediate(bcx.tcx(), ret_ty) {
let llscratchptr = alloc_ty(bcx, ret_ty, "__ret");
Store(bcx, llresult, llscratchptr);
bcx = glue::drop_ty(bcx, llscratchptr, ret_ty);
} else {
bcx = glue::drop_ty(bcx, llretslot, ret_ty);
if !ty::type_is_voidish(ret_ty) {
Some(alloc_ty(bcx, ret_ty, "__llret"))
} else {
unsafe {
Some(llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()))
}
}
}
Some(expr::SaveIn(lldest)) => {
// If this is an immediate, store into the result location.
// (If this was not an immediate, the result will already be
// directly written into the output slot.)
if ty::type_is_immediate(bcx.tcx(), ret_ty) {
Store(bcx, llresult, lldest);
}
};
let mut llresult = unsafe {
llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref())
};
// The code below invokes the function, using either the Rust
// conventions (if it is a rust fn) or the native conventions
// (otherwise). The important part is that, when all is sad
// and done, either the return value of the function will have been
// written in opt_llretslot (if it is Some) or `llresult` will be
// set appropriately (otherwise).
if is_rust_fn {
let mut llargs = ~[];
// Push the out-pointer if we use an out-pointer for this
// return type, otherwise push "undef".
if type_of::return_uses_outptr(in_cx.tcx(), ret_ty) {
llargs.push(opt_llretslot.unwrap());
}
// Push the environment.
llargs.push(llenv);
// Push the arguments.
bcx = trans_args(bcx, args, callee_ty,
autoref_arg, &mut llargs);
// Now that the arguments have finished evaluating, we
// need to revoke the cleanup for the self argument
match callee.data {
Method(d) => {
for &v in d.temp_cleanup.iter() {
revoke_clean(bcx, v);
}
}
_ => {}
}
// Invoke the actual rust fn and update bcx/llresult.
let (llret, b) = base::invoke(bcx, llfn, llargs);
bcx = b;
llresult = llret;
// If the Rust convention for this type is return via
// the return value, copy it into llretslot.
match opt_llretslot {
Some(llretslot) => {
if !type_of::return_uses_outptr(bcx.tcx(), ret_ty) &&
!ty::type_is_voidish(ret_ty)
{
Store(bcx, llret, llretslot);
}
}
None => {}
}
} else {
// Lang items are the only case where dest is None, and
// they are always Rust fns.
assert!(dest.is_some());
let mut llargs = ~[];
bcx = trans_args(bcx, args, callee_ty,
autoref_arg, &mut llargs);
bcx = foreign::trans_native_call(bcx, callee_ty,
llfn, opt_llretslot.unwrap(), llargs);
}
// If the caller doesn't care about the result of this fn call,
// drop the temporary slot we made.
match dest {
None => {
assert!(!type_of::return_uses_outptr(bcx.tcx(), ret_ty));
}
Some(expr::Ignore) => {
// drop the value if it is not being saved.
bcx = glue::drop_ty(bcx, opt_llretslot.unwrap(), ret_ty);
}
Some(expr::SaveIn(_)) => { }
}
if ty::type_is_bot(ret_ty) {
Unreachable(bcx);
}
rslt(bcx, llresult)
}
}
pub enum CallArgs<'self> {
ArgExprs(&'self [@ast::expr]),
ArgVals(&'self [ValueRef])
}
pub fn trans_ret_slot(bcx: @mut Block, fn_ty: ty::t, dest: Option<expr::Dest>)
-> ValueRef {
let retty = ty::ty_fn_ret(fn_ty);
match dest {
Some(expr::SaveIn(dst)) => dst,
_ => {
if ty::type_is_immediate(bcx.tcx(), retty) {
unsafe {
llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref())
}
} else {
alloc_ty(bcx, retty, "__trans_ret_slot")
}
}
}
}
pub fn trans_args(cx: @mut Block,
args: CallArgs,
fn_ty: ty::t,
@ -795,7 +863,7 @@ pub fn trans_arg_expr(bcx: @mut Block,
if formal_arg_ty != arg_datum.ty {
// this could happen due to e.g. subtyping
let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, &formal_arg_ty);
let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
debug!("casting actual type (%s) to match formal (%s)",
bcx.val_to_str(val), bcx.llty_str(llformal_arg_ty));
val = PointerCast(bcx, val, llformal_arg_ty);

View file

@ -121,7 +121,7 @@ pub fn BuilderRef_res(B: BuilderRef) -> BuilderRef_res {
}
}
pub type ExternMap = HashMap<@str, ValueRef>;
pub type ExternMap = HashMap<~str, ValueRef>;
// Types used for llself.
pub struct ValSelfData {
@ -197,10 +197,10 @@ pub struct FunctionContext {
// outputting the resume instruction.
personality: Option<ValueRef>,
// True if this function has an immediate return value, false otherwise.
// If this is false, the llretptr will alias the first argument of the
// function.
has_immediate_return_value: bool,
// True if the caller expects this fn to use the out pointer to
// return. Either way, your code should write into llretptr, but if
// this value is false, llretptr will be a local alloca.
caller_expects_out_pointer: bool,
// Maps arguments to allocas created for them in llallocas.
llargs: @mut HashMap<ast::NodeId, ValueRef>,
@ -232,20 +232,20 @@ pub struct FunctionContext {
impl FunctionContext {
pub fn arg_pos(&self, arg: uint) -> uint {
if self.has_immediate_return_value {
arg + 1u
} else {
if self.caller_expects_out_pointer {
arg + 2u
} else {
arg + 1u
}
}
pub fn out_arg_pos(&self) -> uint {
assert!(!self.has_immediate_return_value);
assert!(self.caller_expects_out_pointer);
0u
}
pub fn env_arg_pos(&self) -> uint {
if !self.has_immediate_return_value {
if self.caller_expects_out_pointer {
1u
} else {
0u

View file

@ -190,12 +190,12 @@ pub fn scratch_datum(bcx: @mut Block, ty: ty::t, name: &str, zero: bool) -> Datu
pub fn appropriate_mode(tcx: ty::ctxt, ty: ty::t) -> DatumMode {
/*!
*
* Indicates the "appropriate" mode for this value,
* which is either by ref or by value, depending
* on whether type is immediate or not. */
* Indicates the "appropriate" mode for this value,
* which is either by ref or by value, depending
* on whether type is immediate or not.
*/
if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
if ty::type_is_voidish(ty) {
ByValue
} else if ty::type_is_immediate(tcx, ty) {
ByValue
@ -271,7 +271,7 @@ impl Datum {
let _icx = push_ctxt("copy_to");
if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
if ty::type_is_voidish(self.ty) {
return bcx;
}
@ -343,7 +343,7 @@ impl Datum {
debug!("move_to(self=%s, action=%?, dst=%s)",
self.to_str(bcx.ccx()), action, bcx.val_to_str(dst));
if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
if ty::type_is_voidish(self.ty) {
return bcx;
}
@ -432,7 +432,7 @@ impl Datum {
*
* Yields the value itself. */
if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
if ty::type_is_voidish(self.ty) {
C_nil()
} else {
match self.mode {
@ -469,7 +469,7 @@ impl Datum {
match self.mode {
ByRef(_) => self.val,
ByValue => {
if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
if ty::type_is_voidish(self.ty) {
C_null(type_of::type_of(bcx.ccx(), self.ty).ptr_to())
} else {
let slot = alloc_ty(bcx, self.ty, "");

View file

@ -290,7 +290,7 @@ pub fn trans_to_datum(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
assert_eq!(datum.appropriate_mode(tcx), ByValue);
Store(bcx, datum.to_appropriate_llval(bcx), llfn);
let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]);
Store(bcx, base::null_env_ptr(bcx), llenv);
Store(bcx, base::null_env_ptr(bcx.ccx()), llenv);
DatumBlock {bcx: bcx, datum: scratch}
}
@ -416,7 +416,7 @@ pub fn trans_into(bcx: @mut Block, expr: @ast::expr, dest: Dest) -> @mut Block {
debuginfo::update_source_pos(bcx.fcx, expr.id, expr.span);
let dest = {
if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
if ty::type_is_voidish(ty) {
Ignore
} else {
dest
@ -507,7 +507,7 @@ fn trans_to_datum_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
ty::RvalueDpsExpr => {
let ty = expr_ty(bcx, expr);
if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
if ty::type_is_voidish(ty) {
bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
return nil(bcx, ty);
} else {

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,503 @@
// 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.
use back::{abi};
use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg};
use lib::llvm::{ValueRef, Pointer};
use lib;
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::callee::*;
use middle::trans::common::*;
use middle::trans::datum::*;
use middle::trans::type_of::*;
use middle::trans::type_of;
use middle::trans::expr::Ignore;
use middle::trans::machine;
use middle::trans::glue;
use middle::ty::FnSig;
use middle::ty;
use syntax::ast;
use syntax::ast_map;
use syntax::attr;
use syntax::opt_vec;
use util::ppaux::{ty_to_str};
use middle::trans::machine::llsize_of;
use middle::trans::type_::Type;
pub fn trans_intrinsic(ccx: @mut CrateContext,
decl: ValueRef,
item: &ast::foreign_item,
path: ast_map::path,
substs: @param_substs,
attributes: &[ast::Attribute],
ref_id: Option<ast::NodeId>) {
debug!("trans_intrinsic(item.ident=%s)", ccx.sess.str_of(item.ident));
fn simple_llvm_intrinsic(bcx: @mut Block, name: &'static str, num_args: uint) {
assert!(num_args <= 4);
let mut args = [0 as ValueRef, ..4];
let first_real_arg = bcx.fcx.arg_pos(0u);
for i in range(0u, num_args) {
args[i] = get_param(bcx.fcx.llfn, first_real_arg + i);
}
let llfn = bcx.ccx().intrinsics.get_copy(&name);
Ret(bcx, Call(bcx, llfn, args.slice(0, num_args)));
}
fn with_overflow_instrinsic(bcx: @mut Block, name: &'static str) {
let first_real_arg = bcx.fcx.arg_pos(0u);
let a = get_param(bcx.fcx.llfn, first_real_arg);
let b = get_param(bcx.fcx.llfn, first_real_arg + 1);
let llfn = bcx.ccx().intrinsics.get_copy(&name);
// convert `i1` to a `bool`, and write to the out parameter
let val = Call(bcx, llfn, [a, b]);
let result = ExtractValue(bcx, val, 0);
let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool());
let retptr = get_param(bcx.fcx.llfn, bcx.fcx.out_arg_pos());
let ret = Load(bcx, retptr);
let ret = InsertValue(bcx, ret, result, 0);
let ret = InsertValue(bcx, ret, overflow, 1);
Store(bcx, ret, retptr);
RetVoid(bcx)
}
fn memcpy_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
let ccx = bcx.ccx();
let lltp_ty = type_of::type_of(ccx, tp_ty);
let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
let size = match sizebits {
32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
_ => ccx.sess.fatal("Invalid value for sizebits")
};
let decl = bcx.fcx.llfn;
let first_real_arg = bcx.fcx.arg_pos(0u);
let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p());
let count = get_param(decl, first_real_arg + 2);
let volatile = C_i1(false);
let llfn = bcx.ccx().intrinsics.get_copy(&name);
Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile]);
RetVoid(bcx);
}
fn memset_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
let ccx = bcx.ccx();
let lltp_ty = type_of::type_of(ccx, tp_ty);
let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
let size = match sizebits {
32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
_ => ccx.sess.fatal("Invalid value for sizebits")
};
let decl = bcx.fcx.llfn;
let first_real_arg = bcx.fcx.arg_pos(0u);
let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p());
let val = get_param(decl, first_real_arg + 1);
let count = get_param(decl, first_real_arg + 2);
let volatile = C_i1(false);
let llfn = bcx.ccx().intrinsics.get_copy(&name);
Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile]);
RetVoid(bcx);
}
fn count_zeros_intrinsic(bcx: @mut Block, name: &'static str) {
let x = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(0u));
let y = C_i1(false);
let llfn = bcx.ccx().intrinsics.get_copy(&name);
Ret(bcx, Call(bcx, llfn, [x, y]));
}
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
let fcx = new_fn_ctxt_w_id(ccx,
path,
decl,
item.id,
output_type,
true,
Some(substs),
None,
Some(item.span));
set_always_inline(fcx.llfn);
// Set the fixed stack segment flag if necessary.
if attr::contains_name(attributes, "fixed_stack_segment") {
set_fixed_stack_segment(fcx.llfn);
}
let mut bcx = fcx.entry_bcx.unwrap();
let first_real_arg = fcx.arg_pos(0u);
let nm = ccx.sess.str_of(item.ident);
let name = nm.as_slice();
// This requires that atomic intrinsics follow a specific naming pattern:
// "atomic_<operation>[_<ordering>], and no ordering means SeqCst
if name.starts_with("atomic_") {
let split : ~[&str] = name.split_iter('_').collect();
assert!(split.len() >= 2, "Atomic intrinsic not correct format");
let order = if split.len() == 2 {
lib::llvm::SequentiallyConsistent
} else {
match split[2] {
"relaxed" => lib::llvm::Monotonic,
"acq" => lib::llvm::Acquire,
"rel" => lib::llvm::Release,
"acqrel" => lib::llvm::AcquireRelease,
_ => ccx.sess.fatal("Unknown ordering in atomic intrinsic")
}
};
match split[1] {
"cxchg" => {
let old = AtomicCmpXchg(bcx, get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
get_param(decl, first_real_arg + 2u),
order);
Ret(bcx, old);
}
"load" => {
let old = AtomicLoad(bcx, get_param(decl, first_real_arg),
order);
Ret(bcx, old);
}
"store" => {
AtomicStore(bcx, get_param(decl, first_real_arg + 1u),
get_param(decl, first_real_arg),
order);
RetVoid(bcx);
}
"fence" => {
AtomicFence(bcx, order);
RetVoid(bcx);
}
op => {
// These are all AtomicRMW ops
let atom_op = match op {
"xchg" => lib::llvm::Xchg,
"xadd" => lib::llvm::Add,
"xsub" => lib::llvm::Sub,
"and" => lib::llvm::And,
"nand" => lib::llvm::Nand,
"or" => lib::llvm::Or,
"xor" => lib::llvm::Xor,
"max" => lib::llvm::Max,
"min" => lib::llvm::Min,
"umax" => lib::llvm::UMax,
"umin" => lib::llvm::UMin,
_ => ccx.sess.fatal("Unknown atomic operation")
};
let old = AtomicRMW(bcx, atom_op, get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
order);
Ret(bcx, old);
}
}
fcx.cleanup();
return;
}
match name {
"size_of" => {
let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty);
Ret(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty)));
}
"move_val" => {
// Create a datum reflecting the value being moved.
// Use `appropriate_mode` so that the datum is by ref
// if the value is non-immediate. Note that, with
// intrinsics, there are no argument cleanups to
// concern ourselves with.
let tp_ty = substs.tys[0];
let mode = appropriate_mode(ccx.tcx, tp_ty);
let src = Datum {val: get_param(decl, first_real_arg + 1u),
ty: tp_ty, mode: mode};
bcx = src.move_to(bcx, DROP_EXISTING,
get_param(decl, first_real_arg));
RetVoid(bcx);
}
"move_val_init" => {
// See comments for `"move_val"`.
let tp_ty = substs.tys[0];
let mode = appropriate_mode(ccx.tcx, tp_ty);
let src = Datum {val: get_param(decl, first_real_arg + 1u),
ty: tp_ty, mode: mode};
bcx = src.move_to(bcx, INIT, get_param(decl, first_real_arg));
RetVoid(bcx);
}
"min_align_of" => {
let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty);
Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty)));
}
"pref_align_of"=> {
let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty);
Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)));
}
"get_tydesc" => {
let tp_ty = substs.tys[0];
let static_ti = get_tydesc(ccx, tp_ty);
glue::lazily_emit_all_tydesc_glue(ccx, static_ti);
// FIXME (#3730): ideally this shouldn't need a cast,
// but there's a circularity between translating rust types to llvm
// types and having a tydesc type available. So I can't directly access
// the llvm type of intrinsic::TyDesc struct.
let userland_tydesc_ty = type_of::type_of(ccx, output_type);
let td = PointerCast(bcx, static_ti.tydesc, userland_tydesc_ty);
Ret(bcx, td);
}
"init" => {
let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty);
match bcx.fcx.llretptr {
Some(ptr) => { Store(bcx, C_null(lltp_ty), ptr); RetVoid(bcx); }
None if ty::type_is_nil(tp_ty) => RetVoid(bcx),
None => Ret(bcx, C_null(lltp_ty)),
}
}
"uninit" => {
// Do nothing, this is effectively a no-op
let retty = substs.tys[0];
if ty::type_is_immediate(ccx.tcx, retty) && !ty::type_is_nil(retty) {
unsafe {
Ret(bcx, lib::llvm::llvm::LLVMGetUndef(type_of(ccx, retty).to_ref()));
}
} else {
RetVoid(bcx)
}
}
"forget" => {
RetVoid(bcx);
}
"transmute" => {
let (in_type, out_type) = (substs.tys[0], substs.tys[1]);
let llintype = type_of::type_of(ccx, in_type);
let llouttype = type_of::type_of(ccx, out_type);
let in_type_size = machine::llbitsize_of_real(ccx, llintype);
let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
if in_type_size != out_type_size {
let sp = match ccx.tcx.items.get_copy(&ref_id.unwrap()) {
ast_map::node_expr(e) => e.span,
_ => fail!("transmute has non-expr arg"),
};
let pluralize = |n| if 1u == n { "" } else { "s" };
ccx.sess.span_fatal(sp,
fmt!("transmute called on types with \
different sizes: %s (%u bit%s) to \
%s (%u bit%s)",
ty_to_str(ccx.tcx, in_type),
in_type_size,
pluralize(in_type_size),
ty_to_str(ccx.tcx, out_type),
out_type_size,
pluralize(out_type_size)));
}
if !ty::type_is_voidish(out_type) {
let llsrcval = get_param(decl, first_real_arg);
if ty::type_is_immediate(ccx.tcx, in_type) {
match fcx.llretptr {
Some(llretptr) => {
Store(bcx, llsrcval, PointerCast(bcx, llretptr, llintype.ptr_to()));
RetVoid(bcx);
}
None => match (llintype.kind(), llouttype.kind()) {
(Pointer, other) | (other, Pointer) if other != Pointer => {
let tmp = Alloca(bcx, llouttype, "");
Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
Ret(bcx, Load(bcx, tmp));
}
_ => Ret(bcx, BitCast(bcx, llsrcval, llouttype))
}
}
} else if ty::type_is_immediate(ccx.tcx, out_type) {
let llsrcptr = PointerCast(bcx, llsrcval, llouttype.ptr_to());
Ret(bcx, Load(bcx, llsrcptr));
} else {
// NB: Do not use a Load and Store here. This causes massive
// code bloat when `transmute` is used on large structural
// types.
let lldestptr = fcx.llretptr.unwrap();
let lldestptr = PointerCast(bcx, lldestptr, Type::i8p());
let llsrcptr = PointerCast(bcx, llsrcval, Type::i8p());
let llsize = llsize_of(ccx, llintype);
call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1);
RetVoid(bcx);
};
} else {
RetVoid(bcx);
}
}
"needs_drop" => {
let tp_ty = substs.tys[0];
Ret(bcx, C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)));
}
"contains_managed" => {
let tp_ty = substs.tys[0];
Ret(bcx, C_bool(ty::type_contents(ccx.tcx, tp_ty).contains_managed()));
}
"visit_tydesc" => {
let td = get_param(decl, first_real_arg);
let visitor = get_param(decl, first_real_arg + 1u);
let td = PointerCast(bcx, td, ccx.tydesc_type.ptr_to());
glue::call_tydesc_glue_full(bcx, visitor, td,
abi::tydesc_field_visit_glue, None);
RetVoid(bcx);
}
"frame_address" => {
let frameaddress = ccx.intrinsics.get_copy(& &"llvm.frameaddress");
let frameaddress_val = Call(bcx, frameaddress, [C_i32(0i32)]);
let star_u8 = ty::mk_imm_ptr(
bcx.tcx(),
ty::mk_mach_uint(ast::ty_u8));
let fty = ty::mk_closure(bcx.tcx(), ty::ClosureTy {
purity: ast::impure_fn,
sigil: ast::BorrowedSigil,
onceness: ast::Many,
region: ty::re_bound(ty::br_anon(0)),
bounds: ty::EmptyBuiltinBounds(),
sig: FnSig {
bound_lifetime_names: opt_vec::Empty,
inputs: ~[ star_u8 ],
output: ty::mk_nil()
}
});
let datum = Datum {val: get_param(decl, first_real_arg),
mode: ByRef(ZeroMem), ty: fty};
let arg_vals = ~[frameaddress_val];
bcx = trans_call_inner(
bcx, None, fty, ty::mk_nil(),
|bcx| Callee {bcx: bcx, data: Closure(datum)},
ArgVals(arg_vals), Some(Ignore), DontAutorefArg).bcx;
RetVoid(bcx);
}
"morestack_addr" => {
// XXX This is a hack to grab the address of this particular
// native function. There should be a general in-language
// way to do this
let llfty = type_of_rust_fn(bcx.ccx(), [], ty::mk_nil());
let morestack_addr = decl_cdecl_fn(
bcx.ccx().llmod, "__morestack", llfty);
let morestack_addr = PointerCast(bcx, morestack_addr, Type::nil().ptr_to());
Ret(bcx, morestack_addr);
}
"offset" => {
let ptr = get_param(decl, first_real_arg);
let offset = get_param(decl, first_real_arg + 1);
Ret(bcx, GEP(bcx, ptr, [offset]));
}
"offset_inbounds" => {
let ptr = get_param(decl, first_real_arg);
let offset = get_param(decl, first_real_arg + 1);
Ret(bcx, InBoundsGEP(bcx, ptr, [offset]));
}
"memcpy32" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i32", substs.tys[0], 32),
"memcpy64" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i64", substs.tys[0], 64),
"memmove32" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i32", substs.tys[0], 32),
"memmove64" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i64", substs.tys[0], 64),
"memset32" => memset_intrinsic(bcx, "llvm.memset.p0i8.i32", substs.tys[0], 32),
"memset64" => memset_intrinsic(bcx, "llvm.memset.p0i8.i64", substs.tys[0], 64),
"sqrtf32" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f32", 1),
"sqrtf64" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f64", 1),
"powif32" => simple_llvm_intrinsic(bcx, "llvm.powi.f32", 2),
"powif64" => simple_llvm_intrinsic(bcx, "llvm.powi.f64", 2),
"sinf32" => simple_llvm_intrinsic(bcx, "llvm.sin.f32", 1),
"sinf64" => simple_llvm_intrinsic(bcx, "llvm.sin.f64", 1),
"cosf32" => simple_llvm_intrinsic(bcx, "llvm.cos.f32", 1),
"cosf64" => simple_llvm_intrinsic(bcx, "llvm.cos.f64", 1),
"powf32" => simple_llvm_intrinsic(bcx, "llvm.pow.f32", 2),
"powf64" => simple_llvm_intrinsic(bcx, "llvm.pow.f64", 2),
"expf32" => simple_llvm_intrinsic(bcx, "llvm.exp.f32", 1),
"expf64" => simple_llvm_intrinsic(bcx, "llvm.exp.f64", 1),
"exp2f32" => simple_llvm_intrinsic(bcx, "llvm.exp2.f32", 1),
"exp2f64" => simple_llvm_intrinsic(bcx, "llvm.exp2.f64", 1),
"logf32" => simple_llvm_intrinsic(bcx, "llvm.log.f32", 1),
"logf64" => simple_llvm_intrinsic(bcx, "llvm.log.f64", 1),
"log10f32" => simple_llvm_intrinsic(bcx, "llvm.log10.f32", 1),
"log10f64" => simple_llvm_intrinsic(bcx, "llvm.log10.f64", 1),
"log2f32" => simple_llvm_intrinsic(bcx, "llvm.log2.f32", 1),
"log2f64" => simple_llvm_intrinsic(bcx, "llvm.log2.f64", 1),
"fmaf32" => simple_llvm_intrinsic(bcx, "llvm.fma.f32", 3),
"fmaf64" => simple_llvm_intrinsic(bcx, "llvm.fma.f64", 3),
"fabsf32" => simple_llvm_intrinsic(bcx, "llvm.fabs.f32", 1),
"fabsf64" => simple_llvm_intrinsic(bcx, "llvm.fabs.f64", 1),
"floorf32" => simple_llvm_intrinsic(bcx, "llvm.floor.f32", 1),
"floorf64" => simple_llvm_intrinsic(bcx, "llvm.floor.f64", 1),
"ceilf32" => simple_llvm_intrinsic(bcx, "llvm.ceil.f32", 1),
"ceilf64" => simple_llvm_intrinsic(bcx, "llvm.ceil.f64", 1),
"truncf32" => simple_llvm_intrinsic(bcx, "llvm.trunc.f32", 1),
"truncf64" => simple_llvm_intrinsic(bcx, "llvm.trunc.f64", 1),
"ctpop8" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i8", 1),
"ctpop16" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i16", 1),
"ctpop32" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i32", 1),
"ctpop64" => simple_llvm_intrinsic(bcx, "llvm.ctpop.i64", 1),
"ctlz8" => count_zeros_intrinsic(bcx, "llvm.ctlz.i8"),
"ctlz16" => count_zeros_intrinsic(bcx, "llvm.ctlz.i16"),
"ctlz32" => count_zeros_intrinsic(bcx, "llvm.ctlz.i32"),
"ctlz64" => count_zeros_intrinsic(bcx, "llvm.ctlz.i64"),
"cttz8" => count_zeros_intrinsic(bcx, "llvm.cttz.i8"),
"cttz16" => count_zeros_intrinsic(bcx, "llvm.cttz.i16"),
"cttz32" => count_zeros_intrinsic(bcx, "llvm.cttz.i32"),
"cttz64" => count_zeros_intrinsic(bcx, "llvm.cttz.i64"),
"bswap16" => simple_llvm_intrinsic(bcx, "llvm.bswap.i16", 1),
"bswap32" => simple_llvm_intrinsic(bcx, "llvm.bswap.i32", 1),
"bswap64" => simple_llvm_intrinsic(bcx, "llvm.bswap.i64", 1),
"i8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i8"),
"i16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i16"),
"i32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i32"),
"i64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i64"),
"u8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i8"),
"u16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i16"),
"u32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i32"),
"u64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i64"),
"i8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i8"),
"i16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i16"),
"i32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i32"),
"i64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i64"),
"u8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i8"),
"u16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i16"),
"u32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i32"),
"u64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i64"),
"i8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i8"),
"i16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i16"),
"i32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i32"),
"i64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i64"),
"u8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i8"),
"u16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i16"),
"u32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i32"),
"u64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i64"),
_ => {
// Could we make this an enum rather than a string? does it get
// checked earlier?
ccx.sess.span_bug(item.span, "unknown intrinsic");
}
}
fcx.cleanup();
}

View file

@ -35,6 +35,7 @@ pub mod cabi_x86_64;
pub mod cabi_arm;
pub mod cabi_mips;
pub mod foreign;
pub mod intrinsic;
pub mod reflect;
pub mod debuginfo;
pub mod type_use;

View file

@ -19,12 +19,12 @@ use middle::trans::base::{get_item_val, no_self};
use middle::trans::base;
use middle::trans::common::*;
use middle::trans::datum;
use middle::trans::foreign;
use middle::trans::machine;
use middle::trans::meth;
use middle::trans::type_of::type_of_fn_from_ty;
use middle::trans::type_of;
use middle::trans::type_use;
use middle::trans::intrinsic;
use middle::ty;
use middle::ty::{FnSig};
use middle::typeck;
@ -239,8 +239,8 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
}
ast_map::node_foreign_item(i, _, _, _) => {
let d = mk_lldecl();
foreign::trans_intrinsic(ccx, d, i, pt, psubsts, i.attrs,
ref_id);
intrinsic::trans_intrinsic(ccx, d, i, pt, psubsts, i.attrs,
ref_id);
d
}
ast_map::node_variant(ref v, enum_item, _) => {

View file

@ -284,7 +284,7 @@ impl Reflector {
sub_path,
"get_disr");
let llfty = type_of_fn(ccx, [opaqueptrty], ty::mk_int());
let llfty = type_of_rust_fn(ccx, [opaqueptrty], ty::mk_int());
let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty);
let fcx = new_fn_ctxt(ccx,
~[],

View file

@ -11,6 +11,7 @@
use middle::trans::adt;
use middle::trans::common::*;
use middle::trans::foreign;
use middle::ty;
use util::ppaux;
@ -19,12 +20,16 @@ use middle::trans::type_::Type;
use syntax::ast;
use syntax::opt_vec;
pub fn arg_is_indirect(ccx: &CrateContext, arg_ty: &ty::t) -> bool {
!ty::type_is_immediate(ccx.tcx, *arg_ty)
pub fn arg_is_indirect(ccx: &CrateContext, arg_ty: ty::t) -> bool {
!ty::type_is_immediate(ccx.tcx, arg_ty)
}
pub fn type_of_explicit_arg(ccx: &mut CrateContext, arg_ty: &ty::t) -> Type {
let llty = type_of(ccx, *arg_ty);
pub fn return_uses_outptr(tcx: ty::ctxt, ty: ty::t) -> bool {
!ty::type_is_immediate(tcx, ty)
}
pub fn type_of_explicit_arg(ccx: &mut CrateContext, arg_ty: ty::t) -> Type {
let llty = type_of(ccx, arg_ty);
if arg_is_indirect(ccx, arg_ty) {
llty.ptr_to()
} else {
@ -34,17 +39,19 @@ pub fn type_of_explicit_arg(ccx: &mut CrateContext, arg_ty: &ty::t) -> Type {
pub fn type_of_explicit_args(ccx: &mut CrateContext,
inputs: &[ty::t]) -> ~[Type] {
inputs.map(|arg_ty| type_of_explicit_arg(ccx, arg_ty))
inputs.map(|&arg_ty| type_of_explicit_arg(ccx, arg_ty))
}
pub fn type_of_fn(cx: &mut CrateContext, inputs: &[ty::t], output: ty::t) -> Type {
pub fn type_of_rust_fn(cx: &mut CrateContext,
inputs: &[ty::t],
output: ty::t) -> Type {
let mut atys: ~[Type] = ~[];
// Arg 0: Output pointer.
// (if the output type is non-immediate)
let output_is_immediate = ty::type_is_immediate(cx.tcx, output);
let use_out_pointer = return_uses_outptr(cx.tcx, output);
let lloutputtype = type_of(cx, output);
if !output_is_immediate {
if use_out_pointer {
atys.push(lloutputtype.ptr_to());
}
@ -55,7 +62,7 @@ pub fn type_of_fn(cx: &mut CrateContext, inputs: &[ty::t], output: ty::t) -> Typ
atys.push_all(type_of_explicit_args(cx, inputs));
// Use the output as the actual return value if it's immediate.
if output_is_immediate && !ty::type_is_nil(output) {
if !use_out_pointer && !ty::type_is_voidish(output) {
Type::func(atys, &lloutputtype)
} else {
Type::func(atys, &Type::void())
@ -64,13 +71,21 @@ pub fn type_of_fn(cx: &mut CrateContext, inputs: &[ty::t], output: ty::t) -> Typ
// Given a function type and a count of ty params, construct an llvm type
pub fn type_of_fn_from_ty(cx: &mut CrateContext, fty: ty::t) -> Type {
match ty::get(fty).sty {
ty::ty_closure(ref f) => type_of_fn(cx, f.sig.inputs, f.sig.output),
ty::ty_bare_fn(ref f) => type_of_fn(cx, f.sig.inputs, f.sig.output),
return match ty::get(fty).sty {
ty::ty_closure(ref f) => {
type_of_rust_fn(cx, f.sig.inputs, f.sig.output)
}
ty::ty_bare_fn(ref f) => {
if f.abis.is_rust() || f.abis.is_intrinsic() {
type_of_rust_fn(cx, f.sig.inputs, f.sig.output)
} else {
foreign::lltype_for_foreign_fn(cx, fty)
}
}
_ => {
cx.sess.bug("type_of_fn_from_ty given non-closure, non-bare-fn")
}
}
};
}
// A "sizing type" is an LLVM type, the size and alignment of which are
@ -250,7 +265,9 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type {
Type::array(&type_of(cx, mt.ty), n as u64)
}
ty::ty_bare_fn(_) => type_of_fn_from_ty(cx, t).ptr_to(),
ty::ty_bare_fn(_) => {
type_of_fn_from_ty(cx, t).ptr_to()
}
ty::ty_closure(_) => {
let ty = type_of_fn_from_ty(cx, t);
Type::func_pair(cx, &ty)

View file

@ -1545,6 +1545,11 @@ pub fn subst(cx: ctxt,
// Type utilities
pub fn type_is_voidish(ty: t) -> bool {
//! "nil" and "bot" are void types in that they represent 0 bits of information
type_is_nil(ty) || type_is_bot(ty)
}
pub fn type_is_nil(ty: t) -> bool { get(ty).sty == ty_nil }
pub fn type_is_bot(ty: t) -> bool {

View file

@ -17,6 +17,11 @@
#[license = "MIT/ASL2"];
#[crate_type = "lib"];
// Rustc tasks always run on a fixed_stack_segment, so code in this
// module can call C functions (in particular, LLVM functions) with
// impunity.
#[allow(cstack)];
extern mod extra;
extern mod syntax;
@ -68,6 +73,7 @@ pub mod middle {
pub mod reachable;
pub mod graph;
pub mod cfg;
pub mod stack_check;
}
pub mod front {

View file

@ -862,3 +862,15 @@ impl UserString for ty::t {
ty_to_str(tcx, *self)
}
}
impl Repr for AbiSet {
fn repr(&self, _tcx: ctxt) -> ~str {
self.to_str()
}
}
impl UserString for AbiSet {
fn user_string(&self, _tcx: ctxt) -> ~str {
self.to_str()
}
}

View file

@ -498,6 +498,8 @@ pub fn run_line(repl: &mut Repl, input: @io::Reader, out: @io::Writer, line: ~st
}
pub fn main() {
#[fixed_stack_segment]; #[inline(never)];
let args = os::args();
let input = io::stdin();
let out = io::stdout();

View file

@ -382,6 +382,8 @@ pub fn find_and_install_dependencies(ctxt: &Ctx,
#[cfg(windows)]
pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
#[fixed_stack_segment]; #[inline(never)];
/* FIXME (#1768): Investigate how to do this on win32
Node wraps symlinks by having a .bat,
but that won't work with minGW. */
@ -394,6 +396,8 @@ pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
pub fn link_exe(src: &Path, dest: &Path) -> bool {
#[fixed_stack_segment]; #[inline(never)];
use std::c_str::ToCStr;
use std::libc;

View file

@ -96,6 +96,7 @@ impl CString {
///
/// Fails if the CString is null.
pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
#[fixed_stack_segment]; #[inline(never)];
if self.buf.is_null() { fail!("CString is null!"); }
unsafe {
let len = libc::strlen(self.buf) as uint;
@ -114,6 +115,7 @@ impl CString {
impl Drop for CString {
fn drop(&self) {
#[fixed_stack_segment]; #[inline(never)];
if self.owns_buffer_ {
unsafe {
libc::free(self.buf as *libc::c_void)
@ -172,6 +174,7 @@ impl<'self> ToCStr for &'self str {
impl<'self> ToCStr for &'self [u8] {
fn to_c_str(&self) -> CString {
#[fixed_stack_segment]; #[inline(never)];
let mut cs = unsafe { self.to_c_str_unchecked() };
do cs.with_mut_ref |buf| {
for i in range(0, self.len()) {
@ -190,6 +193,7 @@ impl<'self> ToCStr for &'self [u8] {
}
unsafe fn to_c_str_unchecked(&self) -> CString {
#[fixed_stack_segment]; #[inline(never)];
do self.as_imm_buf |self_buf, self_len| {
let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
if buf.is_null() {
@ -260,12 +264,16 @@ mod tests {
#[test]
fn test_unwrap() {
#[fixed_stack_segment]; #[inline(never)];
let c_str = "hello".to_c_str();
unsafe { libc::free(c_str.unwrap() as *libc::c_void) }
}
#[test]
fn test_with_ref() {
#[fixed_stack_segment]; #[inline(never)];
let c_str = "hello".to_c_str();
let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
assert!(!c_str.is_null());

View file

@ -928,6 +928,8 @@ fn convert_whence(whence: SeekStyle) -> i32 {
impl Reader for *libc::FILE {
fn read(&self, bytes: &mut [u8], len: uint) -> uint {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do bytes.as_mut_buf |buf_p, buf_len| {
assert!(buf_len >= len);
@ -950,16 +952,22 @@ impl Reader for *libc::FILE {
}
}
fn read_byte(&self) -> int {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::fgetc(*self) as int
}
}
fn eof(&self) -> bool {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
return libc::feof(*self) != 0 as c_int;
}
}
fn seek(&self, offset: int, whence: SeekStyle) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
assert!(libc::fseek(*self,
offset as c_long,
@ -967,6 +975,8 @@ impl Reader for *libc::FILE {
}
}
fn tell(&self) -> uint {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
return libc::ftell(*self) as uint;
}
@ -1005,6 +1015,8 @@ impl FILERes {
impl Drop for FILERes {
fn drop(&self) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::fclose(self.f);
}
@ -1035,12 +1047,16 @@ pub fn FILE_reader(f: *libc::FILE, cleanup: bool) -> @Reader {
* ~~~
*/
pub fn stdin() -> @Reader {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
@rustrt::rust_get_stdin() as @Reader
}
}
pub fn file_reader(path: &Path) -> Result<@Reader, ~str> {
#[fixed_stack_segment]; #[inline(never)];
let f = do path.with_c_str |pathbuf| {
do "rb".with_c_str |modebuf| {
unsafe { libc::fopen(pathbuf, modebuf as *libc::c_char) }
@ -1162,6 +1178,8 @@ impl<W:Writer,C> Writer for Wrapper<W, C> {
impl Writer for *libc::FILE {
fn write(&self, v: &[u8]) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do v.as_imm_buf |vbuf, len| {
let nout = libc::fwrite(vbuf as *c_void,
@ -1177,6 +1195,8 @@ impl Writer for *libc::FILE {
}
}
fn seek(&self, offset: int, whence: SeekStyle) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
assert!(libc::fseek(*self,
offset as c_long,
@ -1184,16 +1204,22 @@ impl Writer for *libc::FILE {
}
}
fn tell(&self) -> uint {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::ftell(*self) as uint
}
}
fn flush(&self) -> int {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::fflush(*self) as int
}
}
fn get_type(&self) -> WriterType {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let fd = libc::fileno(*self);
if libc::isatty(fd) == 0 { File }
@ -1212,6 +1238,8 @@ pub fn FILE_writer(f: *libc::FILE, cleanup: bool) -> @Writer {
impl Writer for fd_t {
fn write(&self, v: &[u8]) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let mut count = 0u;
do v.as_imm_buf |vbuf, len| {
@ -1238,6 +1266,8 @@ impl Writer for fd_t {
}
fn flush(&self) -> int { 0 }
fn get_type(&self) -> WriterType {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
if libc::isatty(*self) == 0 { File } else { Screen }
}
@ -1256,6 +1286,8 @@ impl FdRes {
impl Drop for FdRes {
fn drop(&self) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::close(self.fd);
}
@ -1273,6 +1305,8 @@ pub fn fd_writer(fd: fd_t, cleanup: bool) -> @Writer {
pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
-> Result<@Writer, ~str> {
#[fixed_stack_segment]; #[inline(never)];
#[cfg(windows)]
fn wb() -> c_int {
(O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int
@ -1573,6 +1607,8 @@ pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> {
// FIXME: fileflags // #2004
pub fn buffered_file_writer(path: &Path) -> Result<@Writer, ~str> {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let f = do path.with_c_str |pathbuf| {
do "w".with_c_str |modebuf| {
@ -1803,12 +1839,13 @@ pub mod fsync {
blk: &fn(v: Res<*libc::FILE>)) {
blk(Res::new(Arg {
val: file.f, opt_level: opt_level,
fsync_fn: |file, l| {
unsafe {
os::fsync_fd(libc::fileno(*file), l) as int
}
}
fsync_fn: |file, l| fsync_fd(fileno(*file), l)
}));
fn fileno(stream: *libc::FILE) -> libc::c_int {
#[fixed_stack_segment]; #[inline(never)];
unsafe { libc::fileno(stream) }
}
}
// fsync fd after executing blk
@ -1816,10 +1853,16 @@ pub mod fsync {
blk: &fn(v: Res<fd_t>)) {
blk(Res::new(Arg {
val: fd.fd, opt_level: opt_level,
fsync_fn: |fd, l| os::fsync_fd(*fd, l) as int
fsync_fn: |fd, l| fsync_fd(*fd, l)
}));
}
fn fsync_fd(fd: libc::c_int, level: Level) -> int {
#[fixed_stack_segment]; #[inline(never)];
os::fsync_fd(fd, level) as int
}
// Type of objects that may want to fsync
pub trait FSyncable { fn fsync(&self, l: Level) -> int; }

View file

@ -2762,9 +2762,11 @@ pub mod funcs {
// doesn't link it correctly on i686, so we're going
// through a C function that mysteriously does work.
pub unsafe fn opendir(dirname: *c_char) -> *DIR {
#[fixed_stack_segment]; #[inline(never)];
rust_opendir(dirname)
}
pub unsafe fn readdir(dirp: *DIR) -> *dirent_t {
#[fixed_stack_segment]; #[inline(never)];
rust_readdir(dirp)
}

View file

@ -41,7 +41,7 @@ macro_rules! delegate(
use unstable::intrinsics;
$(
#[inline]
#[inline] #[fixed_stack_segment] #[inline(never)]
pub fn $name($( $arg : $arg_ty ),*) -> $rv {
unsafe {
$bound_name($( $arg ),*)

View file

@ -43,7 +43,7 @@ macro_rules! delegate(
use unstable::intrinsics;
$(
#[inline]
#[inline] #[fixed_stack_segment] #[inline(never)]
pub fn $name($( $arg : $arg_ty ),*) -> $rv {
unsafe {
$bound_name($( $arg ),*)

View file

@ -51,6 +51,7 @@ pub use os::consts::*;
/// Delegates to the libc close() function, returning the same return value.
pub fn close(fd: c_int) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::close(fd)
}
@ -70,6 +71,7 @@ pub static TMPBUF_SZ : uint = 1000u;
static BUF_BYTES : uint = 2048u;
pub fn getcwd() -> Path {
#[fixed_stack_segment]; #[inline(never)];
let mut buf = [0 as libc::c_char, ..BUF_BYTES];
do buf.as_mut_buf |buf, len| {
unsafe {
@ -109,6 +111,8 @@ pub mod win32 {
pub fn fill_utf16_buf_and_decode(f: &fn(*mut u16, DWORD) -> DWORD)
-> Option<~str> {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let mut n = TMPBUF_SZ as DWORD;
let mut res = None;
@ -145,6 +149,18 @@ pub mod win32 {
}
}
#[cfg(stage0)]
mod macro_hack {
#[macro_escape];
macro_rules! externfn(
(fn $name:ident ()) => (
extern {
fn $name();
}
)
)
}
/*
Accessing environment variables is not generally threadsafe.
Serialize access through a global lock.
@ -161,12 +177,8 @@ fn with_env_lock<T>(f: &fn() -> T) -> T {
};
}
extern {
#[fast_ffi]
fn rust_take_env_lock();
#[fast_ffi]
fn rust_drop_env_lock();
}
externfn!(fn rust_take_env_lock());
externfn!(fn rust_drop_env_lock());
}
/// Returns a vector of (variable, value) pairs for all the environment
@ -175,6 +187,8 @@ pub fn env() -> ~[(~str,~str)] {
unsafe {
#[cfg(windows)]
unsafe fn get_env_pairs() -> ~[~str] {
#[fixed_stack_segment]; #[inline(never)];
use libc::funcs::extra::kernel32::{
GetEnvironmentStringsA,
FreeEnvironmentStringsA
@ -198,6 +212,8 @@ pub fn env() -> ~[(~str,~str)] {
}
#[cfg(unix)]
unsafe fn get_env_pairs() -> ~[~str] {
#[fixed_stack_segment]; #[inline(never)];
extern {
fn rust_env_pairs() -> **libc::c_char;
}
@ -237,6 +253,7 @@ pub fn env() -> ~[(~str,~str)] {
/// Fetches the environment variable `n` from the current process, returning
/// None if the variable isn't set.
pub fn getenv(n: &str) -> Option<~str> {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
let s = do n.with_c_str |buf| {
@ -255,6 +272,8 @@ pub fn getenv(n: &str) -> Option<~str> {
/// Fetches the environment variable `n` from the current process, returning
/// None if the variable isn't set.
pub fn getenv(n: &str) -> Option<~str> {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
@ -272,6 +291,7 @@ pub fn getenv(n: &str) -> Option<~str> {
/// Sets the environment variable `n` to the value `v` for the currently running
/// process
pub fn setenv(n: &str, v: &str) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
do n.with_c_str |nbuf| {
@ -288,6 +308,8 @@ pub fn setenv(n: &str, v: &str) {
/// Sets the environment variable `n` to the value `v` for the currently running
/// process
pub fn setenv(n: &str, v: &str) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
use os::win32::as_utf16_p;
@ -304,6 +326,7 @@ pub fn setenv(n: &str, v: &str) {
pub fn unsetenv(n: &str) {
#[cfg(unix)]
fn _unsetenv(n: &str) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
do n.with_c_str |nbuf| {
@ -314,6 +337,7 @@ pub fn unsetenv(n: &str) {
}
#[cfg(windows)]
fn _unsetenv(n: &str) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
use os::win32::as_utf16_p;
@ -328,6 +352,7 @@ pub fn unsetenv(n: &str) {
}
pub fn fdopen(fd: c_int) -> *FILE {
#[fixed_stack_segment]; #[inline(never)];
do "r".with_c_str |modebuf| {
unsafe {
libc::fdopen(fd, modebuf)
@ -340,6 +365,7 @@ pub fn fdopen(fd: c_int) -> *FILE {
#[cfg(windows)]
pub fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::extra::msvcrt::*;
return commit(fd);
@ -349,6 +375,7 @@ pub fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int {
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::posix01::unistd::*;
match level {
@ -361,6 +388,8 @@ pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
#[cfg(target_os = "macos")]
pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::consts::os::extra::*;
use libc::funcs::posix88::fcntl::*;
@ -381,6 +410,8 @@ pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
#[cfg(target_os = "freebsd")]
pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::posix01::unistd::*;
return fsync(fd);
@ -394,6 +425,7 @@ pub struct Pipe {
#[cfg(unix)]
pub fn pipe() -> Pipe {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let mut fds = Pipe {input: 0 as c_int,
out: 0 as c_int };
@ -406,6 +438,7 @@ pub fn pipe() -> Pipe {
#[cfg(windows)]
pub fn pipe() -> Pipe {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
// Windows pipes work subtly differently than unix pipes, and their
// inheritance has to be handled in a different way that I do not
@ -424,6 +457,7 @@ pub fn pipe() -> Pipe {
}
fn dup2(src: c_int, dst: c_int) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::dup2(src, dst)
}
@ -440,6 +474,7 @@ pub fn self_exe_path() -> Option<Path> {
#[cfg(target_os = "freebsd")]
fn load_self() -> Option<~str> {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::bsd44::*;
use libc::consts::os::extra::*;
@ -458,6 +493,7 @@ pub fn self_exe_path() -> Option<Path> {
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn load_self() -> Option<~str> {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::posix01::unistd::readlink;
@ -479,6 +515,7 @@ pub fn self_exe_path() -> Option<Path> {
#[cfg(target_os = "macos")]
fn load_self() -> Option<~str> {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do fill_charp_buf() |buf, sz| {
let mut sz = sz as u32;
@ -490,6 +527,7 @@ pub fn self_exe_path() -> Option<Path> {
#[cfg(windows)]
fn load_self() -> Option<~str> {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::fill_utf16_buf_and_decode;
do fill_utf16_buf_and_decode() |buf, sz| {
@ -592,6 +630,7 @@ pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool {
/// Indicates whether a path represents a directory
pub fn path_is_dir(p: &Path) -> bool {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do p.with_c_str |buf| {
rustrt::rust_path_is_dir(buf) != 0 as c_int
@ -601,6 +640,7 @@ pub fn path_is_dir(p: &Path) -> bool {
/// Indicates whether a path exists
pub fn path_exists(p: &Path) -> bool {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do p.with_c_str |buf| {
rustrt::rust_path_exists(buf) != 0 as c_int
@ -633,6 +673,7 @@ pub fn make_dir(p: &Path, mode: c_int) -> bool {
#[cfg(windows)]
fn mkdir(p: &Path, _mode: c_int) -> bool {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
// FIXME: turn mode into something useful? #2623
@ -645,6 +686,7 @@ pub fn make_dir(p: &Path, mode: c_int) -> bool {
#[cfg(unix)]
fn mkdir(p: &Path, mode: c_int) -> bool {
#[fixed_stack_segment]; #[inline(never)];
do p.with_c_str |buf| {
unsafe {
libc::mkdir(buf, mode as libc::mode_t) == (0 as c_int)
@ -689,6 +731,7 @@ pub fn list_dir(p: &Path) -> ~[~str] {
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
unsafe fn get_list(p: &Path) -> ~[~str] {
#[fixed_stack_segment]; #[inline(never)];
use libc::{dirent_t};
use libc::{opendir, readdir, closedir};
extern {
@ -721,6 +764,7 @@ pub fn list_dir(p: &Path) -> ~[~str] {
}
#[cfg(windows)]
unsafe fn get_list(p: &Path) -> ~[~str] {
#[fixed_stack_segment]; #[inline(never)];
use libc::consts::os::extra::INVALID_HANDLE_VALUE;
use libc::{wcslen, free};
use libc::funcs::extra::kernel32::{
@ -809,6 +853,7 @@ pub fn remove_dir(p: &Path) -> bool {
#[cfg(windows)]
fn rmdir(p: &Path) -> bool {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(p.to_str()) |buf| {
@ -819,6 +864,7 @@ pub fn remove_dir(p: &Path) -> bool {
#[cfg(unix)]
fn rmdir(p: &Path) -> bool {
#[fixed_stack_segment]; #[inline(never)];
do p.with_c_str |buf| {
unsafe {
libc::rmdir(buf) == (0 as c_int)
@ -834,6 +880,7 @@ pub fn change_dir(p: &Path) -> bool {
#[cfg(windows)]
fn chdir(p: &Path) -> bool {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(p.to_str()) |buf| {
@ -844,6 +891,7 @@ pub fn change_dir(p: &Path) -> bool {
#[cfg(unix)]
fn chdir(p: &Path) -> bool {
#[fixed_stack_segment]; #[inline(never)];
do p.with_c_str |buf| {
unsafe {
libc::chdir(buf) == (0 as c_int)
@ -858,6 +906,7 @@ pub fn copy_file(from: &Path, to: &Path) -> bool {
#[cfg(windows)]
fn do_copy_file(from: &Path, to: &Path) -> bool {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(from.to_str()) |fromp| {
@ -871,6 +920,7 @@ pub fn copy_file(from: &Path, to: &Path) -> bool {
#[cfg(unix)]
fn do_copy_file(from: &Path, to: &Path) -> bool {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let istream = do from.with_c_str |fromp| {
do "rb".with_c_str |modebuf| {
@ -933,6 +983,7 @@ pub fn remove_file(p: &Path) -> bool {
#[cfg(windows)]
fn unlink(p: &Path) -> bool {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(p.to_str()) |buf| {
@ -943,6 +994,7 @@ pub fn remove_file(p: &Path) -> bool {
#[cfg(unix)]
fn unlink(p: &Path) -> bool {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do p.with_c_str |buf| {
libc::unlink(buf) == (0 as c_int)
@ -957,6 +1009,7 @@ pub fn errno() -> int {
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
fn errno_location() -> *c_int {
#[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn __error() -> *c_int;
@ -969,6 +1022,7 @@ pub fn errno() -> int {
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn errno_location() -> *c_int {
#[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn __errno_location() -> *c_int;
@ -986,6 +1040,7 @@ pub fn errno() -> int {
#[cfg(windows)]
/// Returns the platform-specific value of errno
pub fn errno() -> uint {
#[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::DWORD;
#[link_name = "kernel32"]
@ -1008,6 +1063,8 @@ pub fn last_os_error() -> ~str {
#[cfg(target_os = "freebsd")]
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
-> c_int {
#[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
@ -1023,6 +1080,7 @@ pub fn last_os_error() -> ~str {
// So we just use __xpg_strerror_r which is always POSIX compliant
#[cfg(target_os = "linux")]
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn __xpg_strerror_r(errnum: c_int,
@ -1050,6 +1108,8 @@ pub fn last_os_error() -> ~str {
#[cfg(windows)]
fn strerror() -> ~str {
#[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::DWORD;
use libc::types::os::arch::extra::LPSTR;
use libc::types::os::arch::extra::LPVOID;
@ -1129,6 +1189,8 @@ unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] {
*/
#[cfg(target_os = "macos")]
pub fn real_args() -> ~[~str] {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let (argc, argv) = (*_NSGetArgc() as c_int,
*_NSGetArgv() as **c_char);
@ -1150,6 +1212,8 @@ pub fn real_args() -> ~[~str] {
#[cfg(windows)]
pub fn real_args() -> ~[~str] {
#[fixed_stack_segment]; #[inline(never)];
let mut nArgs: c_int = 0;
let lpArgCount: *mut c_int = &mut nArgs;
let lpCmdLine = unsafe { GetCommandLineW() };
@ -1232,6 +1296,8 @@ pub fn set_args(new_args: ~[~str]) {
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
pub fn glob(pattern: &str) -> ~[Path] {
#[fixed_stack_segment]; #[inline(never)];
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn default_glob_t () -> libc::glob_t {
@ -1326,6 +1392,8 @@ fn round_up(from: uint, to: uint) -> uint {
#[cfg(unix)]
pub fn page_size() -> uint {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::sysconf(libc::_SC_PAGESIZE) as uint
}
@ -1333,6 +1401,8 @@ pub fn page_size() -> uint {
#[cfg(windows)]
pub fn page_size() -> uint {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let mut info = libc::SYSTEM_INFO::new();
libc::GetSystemInfo(&mut info);
@ -1404,6 +1474,8 @@ impl to_str::ToStr for MapError {
#[cfg(unix)]
impl MemoryMap {
pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError> {
#[fixed_stack_segment]; #[inline(never)];
use libc::off_t;
let mut addr: *c_void = ptr::null();
@ -1460,6 +1532,8 @@ impl MemoryMap {
#[cfg(unix)]
impl Drop for MemoryMap {
fn drop(&self) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
match libc::munmap(self.data as *c_void, self.len) {
0 => (),
@ -1476,6 +1550,8 @@ impl Drop for MemoryMap {
#[cfg(windows)]
impl MemoryMap {
pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError> {
#[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
let mut lpAddress: LPVOID = ptr::mut_null();
@ -1569,6 +1645,8 @@ impl MemoryMap {
#[cfg(windows)]
impl Drop for MemoryMap {
fn drop(&self) {
#[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::{LPCVOID, HANDLE};
unsafe {
@ -1921,6 +1999,8 @@ mod tests {
#[test]
fn copy_file_ok() {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let tempdir = getcwd(); // would like to use $TMPDIR,
// doesn't seem to work on Linux
@ -1991,17 +2071,23 @@ mod tests {
#[test]
fn memory_map_file() {
#[fixed_stack_segment]; #[inline(never)];
use result::{Ok, Err};
use os::*;
use libc::*;
#[cfg(unix)]
#[fixed_stack_segment]
#[inline(never)]
fn lseek_(fd: c_int, size: uint) {
unsafe {
assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
}
}
#[cfg(windows)]
#[fixed_stack_segment]
#[inline(never)]
fn lseek_(fd: c_int, size: uint) {
unsafe {
assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);

View file

@ -381,6 +381,7 @@ mod stat {
#[cfg(target_os = "win32")]
impl WindowsPath {
pub fn stat(&self) -> Option<libc::stat> {
#[fixed_stack_segment]; #[inline(never)];
do self.with_c_str |buf| {
let mut st = stat::arch::default_stat();
match unsafe { libc::stat(buf, &mut st) } {
@ -415,6 +416,7 @@ impl WindowsPath {
#[cfg(not(target_os = "win32"))]
impl PosixPath {
pub fn stat(&self) -> Option<libc::stat> {
#[fixed_stack_segment]; #[inline(never)];
do self.with_c_str |buf| {
let mut st = stat::arch::default_stat();
match unsafe { libc::stat(buf as *libc::c_char, &mut st) } {
@ -493,6 +495,7 @@ impl PosixPath {
#[cfg(unix)]
impl PosixPath {
pub fn lstat(&self) -> Option<libc::stat> {
#[fixed_stack_segment]; #[inline(never)];
do self.with_c_str |buf| {
let mut st = stat::arch::default_stat();
match unsafe { libc::lstat(buf, &mut st) } {
@ -1101,6 +1104,8 @@ pub mod windows {
}
pub fn extract_drive_prefix(s: &str) -> Option<(~str,~str)> {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
if (s.len() > 1 &&
libc::isalpha(s[0] as libc::c_int) != 0 &&

View file

@ -877,6 +877,8 @@ impl Rng for XorShiftRng {
impl XorShiftRng {
/// Create an xor shift random number generator with a random seed.
pub fn new() -> XorShiftRng {
#[fixed_stack_segment]; #[inline(never)];
// generate seeds the same way as seed(), except we have a spceific size
let mut s = [0u8, ..16];
loop {
@ -910,6 +912,8 @@ impl XorShiftRng {
/// Create a new random seed.
pub fn seed() -> ~[u8] {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let n = rustrt::rand_seed_size() as uint;
let mut s = vec::from_elem(n, 0_u8);
@ -1142,6 +1146,8 @@ mod test {
#[test]
fn compare_isaac_implementation() {
#[fixed_stack_segment]; #[inline(never)];
// This is to verify that the implementation of the ISAAC rng is
// correct (i.e. matches the output of the upstream implementation,
// which is in the runtime)

View file

@ -118,12 +118,22 @@ mod imp {
args
}
extern {
fn rust_take_global_args_lock();
fn rust_drop_global_args_lock();
fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>;
#[cfg(stage0)]
mod macro_hack {
#[macro_escape];
macro_rules! externfn(
(fn $name:ident () $(-> $ret_ty:ty),*) => (
extern {
fn $name() $(-> $ret_ty),*;
}
)
)
}
externfn!(fn rust_take_global_args_lock())
externfn!(fn rust_drop_global_args_lock())
externfn!(fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>)
#[cfg(test)]
mod tests {
use option::{Some, None};

View file

@ -136,6 +136,7 @@ impl DebugPrints for io::fd_t {
}
unsafe fn write_cstr(&self, p: *c_char) {
#[fixed_stack_segment]; #[inline(never)];
use libc::strlen;
use vec;

View file

@ -35,8 +35,9 @@ fn align_to(size: uint, align: uint) -> uint {
}
/// A wrapper around libc::malloc, aborting on out-of-memory
#[inline]
pub unsafe fn malloc_raw(size: uint) -> *c_void {
#[fixed_stack_segment]; #[inline(never)];
let p = malloc(size as size_t);
if p.is_null() {
// we need a non-allocating way to print an error here
@ -46,8 +47,9 @@ pub unsafe fn malloc_raw(size: uint) -> *c_void {
}
/// A wrapper around libc::realloc, aborting on out-of-memory
#[inline]
pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void {
#[fixed_stack_segment]; #[inline(never)];
let p = realloc(ptr, size as size_t);
if p.is_null() {
// we need a non-allocating way to print an error here
@ -97,8 +99,9 @@ pub unsafe fn exchange_free_(ptr: *c_char) {
exchange_free(ptr)
}
#[inline]
pub unsafe fn exchange_free(ptr: *c_char) {
#[fixed_stack_segment]; #[inline(never)];
free(ptr as *c_void);
}

View file

@ -37,6 +37,7 @@ pub struct LocalHeap {
}
impl LocalHeap {
#[fixed_stack_segment] #[inline(never)]
pub fn new() -> LocalHeap {
unsafe {
// Don't need synchronization for the single-threaded local heap
@ -55,18 +56,21 @@ impl LocalHeap {
}
}
#[fixed_stack_segment] #[inline(never)]
pub fn alloc(&mut self, td: *TypeDesc, size: uint) -> *OpaqueBox {
unsafe {
return rust_boxed_region_malloc(self.boxed_region, td, size as size_t);
}
}
#[fixed_stack_segment] #[inline(never)]
pub fn realloc(&mut self, ptr: *OpaqueBox, size: uint) -> *OpaqueBox {
unsafe {
return rust_boxed_region_realloc(self.boxed_region, ptr, size as size_t);
}
}
#[fixed_stack_segment] #[inline(never)]
pub fn free(&mut self, box: *OpaqueBox) {
unsafe {
return rust_boxed_region_free(self.boxed_region, box);
@ -75,6 +79,7 @@ impl LocalHeap {
}
impl Drop for LocalHeap {
#[fixed_stack_segment] #[inline(never)]
fn drop(&self) {
unsafe {
rust_delete_boxed_region(self.boxed_region);

View file

@ -24,6 +24,8 @@ use unstable::finally::Finally;
use tls = rt::thread_local_storage;
/// Initialize the TLS key. Other ops will fail if this isn't executed first.
#[fixed_stack_segment]
#[inline(never)]
pub fn init_tls_key() {
unsafe {
rust_initialize_rt_tls_key();
@ -124,6 +126,8 @@ fn tls_key() -> tls::Key {
}
}
#[fixed_stack_segment]
#[inline(never)]
fn maybe_tls_key() -> Option<tls::Key> {
unsafe {
let key: *mut c_void = rust_get_rt_tls_key();
@ -149,8 +153,6 @@ fn maybe_tls_key() -> Option<tls::Key> {
}
extern {
#[fast_ffi]
fn rust_get_rt_tls_key() -> *mut c_void;
}
}

View file

@ -57,6 +57,7 @@ impl Logger for StdErrLogger {
/// Configure logging by traversing the crate map and setting the
/// per-module global logging flags based on the logging spec
#[fixed_stack_segment] #[inline(never)]
pub fn init(crate_map: *u8) {
use c_str::ToCStr;
use os;
@ -78,8 +79,13 @@ pub fn init(crate_map: *u8) {
}
}
#[fixed_stack_segment] #[inline(never)]
pub fn console_on() { unsafe { rust_log_console_on() } }
#[fixed_stack_segment] #[inline(never)]
pub fn console_off() { unsafe { rust_log_console_off() } }
#[fixed_stack_segment] #[inline(never)]
fn should_log_console() -> bool { unsafe { rust_should_log_console() != 0 } }
extern {

View file

@ -200,6 +200,18 @@ pub fn start_on_main_thread(argc: int, argv: **u8, crate_map: *u8, main: ~fn())
return exit_code;
}
#[cfg(stage0)]
mod macro_hack {
#[macro_escape];
macro_rules! externfn(
(fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
extern {
fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
}
)
)
}
/// One-time runtime initialization.
///
/// Initializes global state, including frobbing
@ -215,9 +227,7 @@ pub fn init(argc: int, argv: **u8, crate_map: *u8) {
rust_update_gc_metadata(crate_map);
}
extern {
fn rust_update_gc_metadata(crate_map: *u8);
}
externfn!(fn rust_update_gc_metadata(crate_map: *u8));
}
/// One-time runtime cleanup.

View file

@ -21,6 +21,8 @@ pub struct StackSegment {
impl StackSegment {
pub fn new(size: uint) -> StackSegment {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
// Crate a block of uninitialized values
let mut stack = vec::with_capacity(size);
@ -50,6 +52,8 @@ impl StackSegment {
impl Drop for StackSegment {
fn drop(&self) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
// XXX: Using the FFI to call a C macro. Slow
rust_valgrind_stack_deregister(self.valgrind_id);

View file

@ -441,6 +441,8 @@ impl Unwinder {
}
pub fn begin_unwind(&mut self) -> ! {
#[fixed_stack_segment]; #[inline(never)];
self.unwinding = true;
unsafe {
rust_begin_unwind(UNWIND_TOKEN);

View file

@ -98,6 +98,8 @@ mod darwin_fd_limit {
static RLIMIT_NOFILE: libc::c_int = 8;
pub unsafe fn raise_fd_limit() {
#[fixed_stack_segment]; #[inline(never)];
// The strategy here is to fetch the current resource limits, read the kern.maxfilesperproc
// sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
use ptr::{to_unsafe_ptr, to_mut_unsafe_ptr, mut_null};
@ -305,6 +307,7 @@ pub fn cleanup_task(mut task: ~Task) {
}
/// Get a port number, starting at 9600, for use in tests
#[fixed_stack_segment] #[inline(never)]
pub fn next_test_port() -> u16 {
unsafe {
return rust_dbg_next_port(base_port() as libc::uintptr_t) as u16;

View file

@ -23,6 +23,8 @@ pub struct Thread {
impl Thread {
pub fn start(main: ~fn()) -> Thread {
fn substart(main: &~fn()) -> *raw_thread {
#[fixed_stack_segment]; #[inline(never)];
unsafe { rust_raw_thread_start(main) }
}
let raw = substart(&main);
@ -34,6 +36,8 @@ impl Thread {
}
pub fn join(self) {
#[fixed_stack_segment]; #[inline(never)];
assert!(!self.joined);
let mut this = self;
unsafe { rust_raw_thread_join(this.raw_thread); }
@ -43,6 +47,8 @@ impl Thread {
impl Drop for Thread {
fn drop(&self) {
#[fixed_stack_segment]; #[inline(never)];
assert!(self.joined);
unsafe { rust_raw_thread_delete(self.raw_thread) }
}

View file

@ -20,16 +20,22 @@ use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
pub type Key = pthread_key_t;
#[cfg(unix)]
#[fixed_stack_segment]
#[inline(never)]
pub unsafe fn create(key: &mut Key) {
assert_eq!(0, pthread_key_create(key, null()));
}
#[cfg(unix)]
#[fixed_stack_segment]
#[inline(never)]
pub unsafe fn set(key: Key, value: *mut c_void) {
assert_eq!(0, pthread_setspecific(key, value));
}
#[cfg(unix)]
#[fixed_stack_segment]
#[inline(never)]
pub unsafe fn get(key: Key) -> *mut c_void {
pthread_getspecific(key)
}
@ -58,6 +64,8 @@ extern {
pub type Key = DWORD;
#[cfg(windows)]
#[fixed_stack_segment]
#[inline(never)]
pub unsafe fn create(key: &mut Key) {
static TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF;
*key = TlsAlloc();
@ -65,11 +73,15 @@ pub unsafe fn create(key: &mut Key) {
}
#[cfg(windows)]
#[fixed_stack_segment]
#[inline(never)]
pub unsafe fn set(key: Key, value: *mut c_void) {
assert!(0 != TlsSetValue(key, value))
}
#[cfg(windows)]
#[fixed_stack_segment]
#[inline(never)]
pub unsafe fn get(key: Key) -> *mut c_void {
TlsGetValue(key)
}

View file

@ -17,6 +17,8 @@ use str::StrSlice;
/// Get the number of cores available
pub fn num_cpus() -> uint {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
return rust_get_num_cpus();
}
@ -94,11 +96,16 @@ memory and partly incapable of presentation to others.",
rterrln!("%s", "");
rterrln!("fatal runtime error: %s", msg);
unsafe { libc::abort(); }
abort();
fn abort() -> ! {
#[fixed_stack_segment]; #[inline(never)];
unsafe { libc::abort() }
}
}
pub fn set_exit_status(code: int) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
return rust_set_exit_status_newrt(code as libc::uintptr_t);
}
@ -109,7 +116,7 @@ pub fn set_exit_status(code: int) {
}
pub fn get_exit_status() -> int {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
return rust_get_exit_status_newrt() as int;
}

View file

@ -310,6 +310,8 @@ pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
/// Transmute an owned vector to a Buf
pub fn vec_to_uv_buf(v: ~[u8]) -> Buf {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let data = malloc(v.len() as size_t) as *u8;
assert!(data.is_not_null());
@ -323,6 +325,8 @@ pub fn vec_to_uv_buf(v: ~[u8]) -> Buf {
/// Transmute a Buf that was once a ~[u8] back to ~[u8]
pub fn vec_from_uv_buf(buf: Buf) -> Option<~[u8]> {
#[fixed_stack_segment]; #[inline(never)];
if !(buf.len == 0 && buf.base.is_null()) {
let v = unsafe { vec::from_buf(buf.base, buf.len as uint) };
unsafe { free(buf.base as *c_void) };

View file

@ -45,6 +45,7 @@ enum SocketNameKind {
fn socket_name<T, U: Watcher + NativeHandle<*T>>(sk: SocketNameKind,
handle: U) -> Result<SocketAddr, IoError> {
#[fixed_stack_segment]; #[inline(never)];
let getsockname = match sk {
TcpPeer => uvll::rust_uv_tcp_getpeername,
@ -406,6 +407,8 @@ impl RtioTcpListener for UvTcpListener {
}
fn accept_simultaneously(&mut self) -> Result<(), IoError> {
#[fixed_stack_segment]; #[inline(never)];
let r = unsafe {
uvll::rust_uv_tcp_simultaneous_accepts(self.watcher.native_handle(), 1 as c_int)
};
@ -417,6 +420,8 @@ impl RtioTcpListener for UvTcpListener {
}
fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> {
#[fixed_stack_segment]; #[inline(never)];
let r = unsafe {
uvll::rust_uv_tcp_simultaneous_accepts(self.watcher.native_handle(), 0 as c_int)
};
@ -524,6 +529,8 @@ impl RtioTcpStream for UvTcpStream {
}
fn control_congestion(&mut self) -> Result<(), IoError> {
#[fixed_stack_segment]; #[inline(never)];
let r = unsafe {
uvll::rust_uv_tcp_nodelay(self.native_handle(), 0 as c_int)
};
@ -535,6 +542,8 @@ impl RtioTcpStream for UvTcpStream {
}
fn nodelay(&mut self) -> Result<(), IoError> {
#[fixed_stack_segment]; #[inline(never)];
let r = unsafe {
uvll::rust_uv_tcp_nodelay(self.native_handle(), 1 as c_int)
};
@ -546,6 +555,8 @@ impl RtioTcpStream for UvTcpStream {
}
fn keepalive(&mut self, delay_in_seconds: uint) -> Result<(), IoError> {
#[fixed_stack_segment]; #[inline(never)];
let r = unsafe {
uvll::rust_uv_tcp_keepalive(self.native_handle(), 1 as c_int,
delay_in_seconds as c_uint)
@ -558,6 +569,8 @@ impl RtioTcpStream for UvTcpStream {
}
fn letdie(&mut self) -> Result<(), IoError> {
#[fixed_stack_segment]; #[inline(never)];
let r = unsafe {
uvll::rust_uv_tcp_keepalive(self.native_handle(), 0 as c_int, 0 as c_uint)
};

View file

@ -124,6 +124,8 @@ pub enum uv_membership {
}
pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void {
#[fixed_stack_segment]; #[inline(never)];
assert!(handle != UV_UNKNOWN_HANDLE && handle != UV_HANDLE_TYPE_MAX);
let size = rust_uv_handle_size(handle as uint);
let p = malloc(size);
@ -132,10 +134,14 @@ pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void {
}
pub unsafe fn free_handle(v: *c_void) {
#[fixed_stack_segment]; #[inline(never)];
free(v)
}
pub unsafe fn malloc_req(req: uv_req_type) -> *c_void {
#[fixed_stack_segment]; #[inline(never)];
assert!(req != UV_UNKNOWN_REQ && req != UV_REQ_TYPE_MAX);
let size = rust_uv_req_size(req as uint);
let p = malloc(size);
@ -144,17 +150,22 @@ pub unsafe fn malloc_req(req: uv_req_type) -> *c_void {
}
pub unsafe fn free_req(v: *c_void) {
#[fixed_stack_segment]; #[inline(never)];
free(v)
}
#[test]
fn handle_sanity_check() {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
assert_eq!(UV_HANDLE_TYPE_MAX as uint, rust_uv_handle_type_max());
}
}
#[test]
#[fixed_stack_segment]
#[inline(never)]
fn request_sanity_check() {
unsafe {
assert_eq!(UV_REQ_TYPE_MAX as uint, rust_uv_req_type_max());
@ -162,59 +173,87 @@ fn request_sanity_check() {
}
pub unsafe fn loop_new() -> *c_void {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_loop_new();
}
pub unsafe fn loop_delete(loop_handle: *c_void) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_loop_delete(loop_handle);
}
pub unsafe fn run(loop_handle: *c_void) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_run(loop_handle);
}
pub unsafe fn close<T>(handle: *T, cb: *u8) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_close(handle as *c_void, cb);
}
pub unsafe fn walk(loop_handle: *c_void, cb: *u8, arg: *c_void) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_walk(loop_handle, cb, arg);
}
pub unsafe fn idle_new() -> *uv_idle_t {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_idle_new()
}
pub unsafe fn idle_delete(handle: *uv_idle_t) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_idle_delete(handle)
}
pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_idle_init(loop_handle, handle)
}
pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_idle_start(handle, cb)
}
pub unsafe fn idle_stop(handle: *uv_idle_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_idle_stop(handle)
}
pub unsafe fn udp_init(loop_handle: *uv_loop_t, handle: *uv_udp_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_udp_init(loop_handle, handle);
}
pub unsafe fn udp_bind(server: *uv_udp_t, addr: *sockaddr_in, flags: c_uint) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_udp_bind(server, addr, flags);
}
pub unsafe fn udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_udp_bind6(server, addr, flags);
}
pub unsafe fn udp_send<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
addr: *sockaddr_in, cb: uv_udp_send_cb) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_udp_send(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb);
@ -222,6 +261,8 @@ pub unsafe fn udp_send<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
pub unsafe fn udp_send6<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
addr: *sockaddr_in6, cb: uv_udp_send_cb) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_udp_send6(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb);
@ -229,124 +270,184 @@ pub unsafe fn udp_send6<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: uv_alloc_cb,
on_recv: uv_udp_recv_cb) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_udp_recv_start(server, on_alloc, on_recv);
}
pub unsafe fn udp_recv_stop(server: *uv_udp_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_udp_recv_stop(server);
}
pub unsafe fn get_udp_handle_from_send_req(send_req: *uv_udp_send_t) -> *uv_udp_t {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_get_udp_handle_from_send_req(send_req);
}
pub unsafe fn udp_get_sockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_udp_getsockname(handle, name);
}
pub unsafe fn udp_set_membership(handle: *uv_udp_t, multicast_addr: *c_char,
interface_addr: *c_char, membership: uv_membership) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_udp_set_membership(handle, multicast_addr, interface_addr, membership as c_int);
}
pub unsafe fn udp_set_multicast_loop(handle: *uv_udp_t, on: c_int) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_udp_set_multicast_loop(handle, on);
}
pub unsafe fn udp_set_multicast_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_udp_set_multicast_ttl(handle, ttl);
}
pub unsafe fn udp_set_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_udp_set_ttl(handle, ttl);
}
pub unsafe fn udp_set_broadcast(handle: *uv_udp_t, on: c_int) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_udp_set_broadcast(handle, on);
}
pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_tcp_init(loop_handle, handle);
}
pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
addr_ptr: *sockaddr_in, after_connect_cb: *u8) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
}
pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
addr_ptr: *sockaddr_in6, after_connect_cb: *u8) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
}
pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_tcp_bind(tcp_server_ptr, addr_ptr);
}
pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in6) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_tcp_bind6(tcp_server_ptr, addr_ptr);
}
pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_storage) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_tcp_getpeername(tcp_handle_ptr, name);
}
pub unsafe fn tcp_getsockname(handle: *uv_tcp_t, name: *sockaddr_storage) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_tcp_getsockname(handle, name);
}
pub unsafe fn tcp_nodelay(handle: *uv_tcp_t, enable: c_int) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_tcp_nodelay(handle, enable);
}
pub unsafe fn tcp_keepalive(handle: *uv_tcp_t, enable: c_int, delay: c_uint) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_tcp_keepalive(handle, enable, delay);
}
pub unsafe fn tcp_simultaneous_accepts(handle: *uv_tcp_t, enable: c_int) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_tcp_simultaneous_accepts(handle, enable);
}
pub unsafe fn listen<T>(stream: *T, backlog: c_int, cb: *u8) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_listen(stream as *c_void, backlog, cb);
}
pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_accept(server as *c_void, client as *c_void);
}
pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb);
}
pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: uv_alloc_cb, on_read: *u8) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_read_start(stream as *c_void, on_alloc, on_read);
}
pub unsafe fn read_stop(stream: *uv_stream_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_read_stop(stream as *c_void);
}
pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_last_error(loop_handle);
}
pub unsafe fn strerror(err: *uv_err_t) -> *c_char {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_strerror(err);
}
pub unsafe fn err_name(err: *uv_err_t) -> *c_char {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_err_name(err);
}
pub unsafe fn async_init(loop_handle: *c_void, async_handle: *uv_async_t, cb: *u8) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_async_init(loop_handle, async_handle, cb);
}
pub unsafe fn async_send(async_handle: *uv_async_t) {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_async_send(async_handle);
}
pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t {
#[fixed_stack_segment]; #[inline(never)];
let out_buf = uv_buf_t { base: ptr::null(), len: 0 as size_t };
let out_buf_ptr = ptr::to_unsafe_ptr(&out_buf);
rust_uv_buf_init(out_buf_ptr, input, len as size_t);
@ -354,99 +455,149 @@ pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t {
}
pub unsafe fn timer_init(loop_ptr: *c_void, timer_ptr: *uv_timer_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_timer_init(loop_ptr, timer_ptr);
}
pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: u64,
repeat: u64) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_timer_start(timer_ptr, cb, timeout, repeat);
}
pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_timer_stop(timer_ptr);
}
pub unsafe fn is_ip4_addr(addr: *sockaddr) -> bool {
#[fixed_stack_segment]; #[inline(never)];
match rust_uv_is_ipv4_sockaddr(addr) { 0 => false, _ => true }
}
pub unsafe fn is_ip6_addr(addr: *sockaddr) -> bool {
#[fixed_stack_segment]; #[inline(never)];
match rust_uv_is_ipv6_sockaddr(addr) { 0 => false, _ => true }
}
pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in {
#[fixed_stack_segment]; #[inline(never)];
do ip.with_c_str |ip_buf| {
rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int)
}
}
pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 {
#[fixed_stack_segment]; #[inline(never)];
do ip.with_c_str |ip_buf| {
rust_uv_ip6_addrp(ip_buf as *u8, port as libc::c_int)
}
}
pub unsafe fn malloc_sockaddr_storage() -> *sockaddr_storage {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_malloc_sockaddr_storage()
}
pub unsafe fn free_sockaddr_storage(ss: *sockaddr_storage) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_free_sockaddr_storage(ss);
}
pub unsafe fn free_ip4_addr(addr: *sockaddr_in) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_free_ip4_addr(addr);
}
pub unsafe fn free_ip6_addr(addr: *sockaddr_in6) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_free_ip6_addr(addr);
}
pub unsafe fn ip4_name(addr: *sockaddr_in, dst: *u8, size: size_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_ip4_name(addr, dst, size);
}
pub unsafe fn ip6_name(addr: *sockaddr_in6, dst: *u8, size: size_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_ip6_name(addr, dst, size);
}
pub unsafe fn ip4_port(addr: *sockaddr_in) -> c_uint {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_ip4_port(addr);
}
pub unsafe fn ip6_port(addr: *sockaddr_in6) -> c_uint {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_ip6_port(addr);
}
// data access helpers
pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_get_loop_for_uv_handle(handle as *c_void);
}
pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t) -> *uv_stream_t {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_get_stream_handle_from_connect_req(connect);
}
pub unsafe fn get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_get_stream_handle_from_write_req(write_req);
}
pub unsafe fn get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_get_data_for_uv_loop(loop_ptr)
}
pub unsafe fn set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_set_data_for_uv_loop(loop_ptr, data);
}
pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *c_void {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_get_data_for_uv_handle(handle as *c_void);
}
pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, data: *U) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_set_data_for_uv_handle(handle as *c_void, data as *c_void);
}
pub unsafe fn get_data_for_req<T>(req: *T) -> *c_void {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_get_data_for_req(req as *c_void);
}
pub unsafe fn set_data_for_req<T, U>(req: *T, data: *U) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_set_data_for_req(req as *c_void, data as *c_void);
}
pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_get_base_from_buf(buf);
}
pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_get_len_from_buf(buf);
}
pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str {

View file

@ -147,8 +147,11 @@ impl Process {
* * options - Options to configure the environment of the process,
* the working directory and the standard IO streams.
*/
pub fn new(prog: &str, args: &[~str], options: ProcessOptions)
pub fn new(prog: &str, args: &[~str],
options: ProcessOptions)
-> Process {
#[fixed_stack_segment]; #[inline(never)];
let (in_pipe, in_fd) = match options.in_fd {
None => {
let pipe = os::pipe();
@ -287,6 +290,7 @@ impl Process {
* method does nothing.
*/
pub fn close_input(&mut self) {
#[fixed_stack_segment]; #[inline(never)];
match self.input {
Some(-1) | None => (),
Some(fd) => {
@ -299,10 +303,12 @@ impl Process {
}
fn close_outputs(&mut self) {
#[fixed_stack_segment]; #[inline(never)];
fclose_and_null(&mut self.output);
fclose_and_null(&mut self.error);
fn fclose_and_null(f_opt: &mut Option<*libc::FILE>) {
#[allow(cstack)]; // fixed_stack_segment declared on enclosing fn
match *f_opt {
Some(f) if !f.is_null() => {
unsafe {
@ -387,6 +393,7 @@ impl Process {
#[cfg(windows)]
fn killpid(pid: pid_t, _force: bool) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::funcs::extra::kernel32::TerminateProcess(
cast::transmute(pid), 1);
@ -395,6 +402,8 @@ impl Process {
#[cfg(unix)]
fn killpid(pid: pid_t, force: bool) {
#[fixed_stack_segment]; #[inline(never)];
let signal = if force {
libc::consts::os::posix88::SIGKILL
} else {
@ -447,6 +456,7 @@ fn spawn_process_os(prog: &str, args: &[~str],
env: Option<~[(~str, ~str)]>,
dir: Option<&Path>,
in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
#[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
use libc::consts::os::extra::{
@ -630,6 +640,7 @@ fn spawn_process_os(prog: &str, args: &[~str],
env: Option<~[(~str, ~str)]>,
dir: Option<&Path>,
in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
#[fixed_stack_segment]; #[inline(never)];
use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
use libc::funcs::bsd44::getdtablesize;
@ -782,6 +793,7 @@ fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T {
#[cfg(windows)]
fn free_handle(handle: *()) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
}
@ -848,6 +860,7 @@ fn waitpid(pid: pid_t) -> int {
#[cfg(windows)]
fn waitpid_os(pid: pid_t) -> int {
#[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::DWORD;
use libc::consts::os::extra::{
@ -892,6 +905,7 @@ fn waitpid(pid: pid_t) -> int {
#[cfg(unix)]
fn waitpid_os(pid: pid_t) -> int {
#[fixed_stack_segment]; #[inline(never)];
use libc::funcs::posix01::wait::*;
@ -1069,6 +1083,8 @@ mod tests {
}
fn readclose(fd: c_int) -> ~str {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let file = os::fdopen(fd);
let reader = io::FILE_reader(file, false);
@ -1351,6 +1367,7 @@ mod tests {
}
fn running_on_valgrind() -> bool {
#[fixed_stack_segment]; #[inline(never)];
unsafe { rust_running_on_valgrind() != 0 }
}

View file

@ -220,3 +220,4 @@ mod std {
pub use fmt;
pub use to_bytes;
}

View file

@ -2908,6 +2908,7 @@ mod tests {
#[test]
fn test_map() {
#[fixed_stack_segment]; #[inline(never)];
assert_eq!(~"", "".map_chars(|c| unsafe {libc::toupper(c as c_char)} as char));
assert_eq!(~"YMCA", "ymca".map_chars(|c| unsafe {libc::toupper(c as c_char)} as char));
}

View file

@ -147,7 +147,7 @@ pub unsafe fn local_pop<T: 'static>(handle: Handle,
// above.
let data = match util::replace(entry, None) {
Some((_, data, _)) => data,
None => libc::abort(),
None => abort(),
};
// Move `data` into transmute to get out the memory that it
@ -252,7 +252,7 @@ unsafe fn local_get_with<T: 'static, U>(handle: Handle,
}
}
}
_ => libc::abort()
_ => abort()
}
// n.b. 'data' and 'loans' are both invalid pointers at the point
@ -262,7 +262,7 @@ unsafe fn local_get_with<T: 'static, U>(handle: Handle,
if return_loan {
match map[i] {
Some((_, _, ref mut loan)) => { *loan = NoLoan; }
None => { libc::abort(); }
None => { abort(); }
}
}
return ret;
@ -270,6 +270,12 @@ unsafe fn local_get_with<T: 'static, U>(handle: Handle,
}
}
fn abort() -> ! {
#[fixed_stack_segment]; #[inline(never)];
unsafe { libc::abort() }
}
pub unsafe fn local_set<T: 'static>(handle: Handle,
key: local_data::Key<T>,
data: T) {

View file

@ -1045,15 +1045,12 @@ fn test_spawn_sched_childs_on_default_sched() {
mod testrt {
use libc;
#[nolink]
extern {
pub fn rust_dbg_lock_create() -> *libc::c_void;
pub fn rust_dbg_lock_destroy(lock: *libc::c_void);
pub fn rust_dbg_lock_lock(lock: *libc::c_void);
pub fn rust_dbg_lock_unlock(lock: *libc::c_void);
pub fn rust_dbg_lock_wait(lock: *libc::c_void);
pub fn rust_dbg_lock_signal(lock: *libc::c_void);
}
externfn!(fn rust_dbg_lock_create() -> *libc::c_void)
externfn!(fn rust_dbg_lock_destroy(lock: *libc::c_void))
externfn!(fn rust_dbg_lock_lock(lock: *libc::c_void))
externfn!(fn rust_dbg_lock_unlock(lock: *libc::c_void))
externfn!(fn rust_dbg_lock_wait(lock: *libc::c_void))
externfn!(fn rust_dbg_lock_signal(lock: *libc::c_void))
}
#[test]

View file

@ -145,16 +145,21 @@ mod dl {
use result::*;
pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
#[fixed_stack_segment]; #[inline(never)];
do filename.with_c_str |raw_name| {
dlopen(raw_name, Lazy as libc::c_int)
}
}
pub unsafe fn open_internal() -> *libc::c_void {
#[fixed_stack_segment]; #[inline(never)];
dlopen(ptr::null(), Lazy as libc::c_int)
}
pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do atomically {
let _old_error = dlerror();
@ -172,9 +177,13 @@ mod dl {
}
pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
#[fixed_stack_segment]; #[inline(never)];
dlsym(handle, symbol)
}
pub unsafe fn close(handle: *libc::c_void) {
#[fixed_stack_segment]; #[inline(never)];
dlclose(handle); ()
}
@ -204,18 +213,21 @@ mod dl {
use result::*;
pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
#[fixed_stack_segment]; #[inline(never)];
do os::win32::as_utf16_p(filename.to_str()) |raw_name| {
LoadLibraryW(raw_name)
}
}
pub unsafe fn open_internal() -> *libc::c_void {
#[fixed_stack_segment]; #[inline(never)];
let handle = ptr::null();
GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &handle as **libc::c_void);
handle
}
pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
do atomically {
SetLastError(0);
@ -232,9 +244,11 @@ mod dl {
}
}
pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
#[fixed_stack_segment]; #[inline(never)];
GetProcAddress(handle, symbol)
}
pub unsafe fn close(handle: *libc::c_void) {
#[fixed_stack_segment]; #[inline(never)];
FreeLibrary(handle); ()
}

View file

@ -83,6 +83,8 @@ fn test_run_in_bare_thread_exchange() {
/// can lead to deadlock. Calling change_dir_locked recursively will
/// also deadlock.
pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
#[fixed_stack_segment]; #[inline(never)];
use os;
use os::change_dir;
use unstable::sync::atomically;

View file

@ -322,7 +322,6 @@ impl LittleLock {
}
}
#[inline]
pub unsafe fn lock<T>(&self, f: &fn() -> T) -> T {
do atomically {
rust_lock_little_lock(self.l);
@ -410,13 +409,28 @@ impl<T:Send> Exclusive<T> {
}
}
extern {
fn rust_create_little_lock() -> rust_little_lock;
fn rust_destroy_little_lock(lock: rust_little_lock);
fn rust_lock_little_lock(lock: rust_little_lock);
fn rust_unlock_little_lock(lock: rust_little_lock);
#[cfg(stage0)]
mod macro_hack {
#[macro_escape];
macro_rules! externfn(
(fn $name:ident () $(-> $ret_ty:ty),*) => (
extern {
fn $name() $(-> $ret_ty),*;
}
);
(fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
extern {
fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
}
)
)
}
externfn!(fn rust_create_little_lock() -> rust_little_lock)
externfn!(fn rust_destroy_little_lock(lock: rust_little_lock))
externfn!(fn rust_lock_little_lock(lock: rust_little_lock))
externfn!(fn rust_unlock_little_lock(lock: rust_little_lock))
#[cfg(test)]
mod tests {
use cell::Cell;

View file

@ -968,6 +968,85 @@ pub fn std_macros() -> @str {
pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
)
)
// externfn! declares a wrapper for an external function.
// It is intended to be used like:
//
// externfn!(#[nolink]
// #[abi = \"cdecl\"]
// fn memcmp(cx: *u8, ct: *u8, n: u32) -> u32)
//
// Due to limitations in the macro parser, this pattern must be
// implemented with 4 distinct patterns (with attrs / without
// attrs CROSS with args / without ARGS).
//
// Also, this macro grammar allows for any number of return types
// because I couldn't figure out the syntax to specify at most one.
macro_rules! externfn(
(fn $name:ident () $(-> $ret_ty:ty),*) => (
pub unsafe fn $name() $(-> $ret_ty),* {
// Note: to avoid obscure bug in macros, keep these
// attributes *internal* to the fn
#[fixed_stack_segment];
#[inline(never)];
#[allow(missing_doc)];
return $name();
extern {
fn $name() $(-> $ret_ty),*;
}
}
);
(fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
pub unsafe fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),* {
// Note: to avoid obscure bug in macros, keep these
// attributes *internal* to the fn
#[fixed_stack_segment];
#[inline(never)];
#[allow(missing_doc)];
return $name($($arg_name),*);
extern {
fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
}
}
);
($($attrs:attr)* fn $name:ident () $(-> $ret_ty:ty),*) => (
pub unsafe fn $name() $(-> $ret_ty),* {
// Note: to avoid obscure bug in macros, keep these
// attributes *internal* to the fn
#[fixed_stack_segment];
#[inline(never)];
#[allow(missing_doc)];
return $name();
$($attrs)*
extern {
fn $name() $(-> $ret_ty),*;
}
}
);
($($attrs:attr)* fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
pub unsafe fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),* {
// Note: to avoid obscure bug in macros, keep these
// attributes *internal* to the fn
#[fixed_stack_segment];
#[inline(never)];
#[allow(missing_doc)];
return $name($($arg_name),*);
$($attrs)*
extern {
fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
}
}
)
)
}";
}

View file

@ -24,6 +24,7 @@ pub mod rustrt {
}
}
#[fixed_stack_segment] #[inline(never)]
pub fn fact(n: uint) -> uint {
unsafe {
info!("n = %?", n);

View file

@ -10,6 +10,7 @@
// Exercise the unused_unsafe attribute in some positive and negative cases
#[allow(cstack)];
#[deny(unused_unsafe)];
mod foo {
@ -55,6 +56,7 @@ fn good2() {
}
}
}
unsafe fn good3() { foo::bar() }
fn good4() { unsafe { foo::bar() } }

View file

@ -8,15 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//error-pattern:libc::c_int or libc::c_long should be used
#[forbid(ctypes)];
mod xx {
extern {
pub fn strlen(str: *u8) -> uint;
pub fn foo(x: int, y: uint);
pub fn strlen(str: *u8) -> uint; //~ ERROR found rust type `uint`
pub fn foo(x: int, y: uint); //~ ERROR found rust type `int`
//~^ ERROR found rust type `uint`
}
}
fn main() {
// let it fail to verify warning message
fail!()
}

View file

@ -14,6 +14,7 @@ extern mod anonexternmod;
use anonexternmod::*;
#[fixed_stack_segment]
pub fn main() {
unsafe {
rust_get_test_int();

View file

@ -16,6 +16,7 @@ extern {
fn rust_get_test_int() -> libc::intptr_t;
}
#[fixed_stack_segment]
pub fn main() {
unsafe {
let _ = rust_get_test_int();

View file

@ -19,10 +19,12 @@ mod libc {
}
}
#[fixed_stack_segment]
fn atol(s: ~str) -> int {
s.with_c_str(|x| unsafe { libc::atol(x) as int })
}
#[fixed_stack_segment]
fn atoll(s: ~str) -> i64 {
s.with_c_str(|x| unsafe { libc::atoll(x) as i64 })
}

View file

@ -27,6 +27,7 @@ extern fn cb(data: libc::uintptr_t) -> libc::uintptr_t {
}
}
#[fixed_stack_segment]
fn count(n: uint) -> uint {
unsafe {
info!("n = %?", n);

View file

@ -28,6 +28,7 @@ extern fn cb(data: libc::uintptr_t) -> libc::uintptr_t {
}
}
#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
info!("n = %?", n);

View file

@ -32,6 +32,7 @@ extern fn cb(data: libc::uintptr_t) -> libc::uintptr_t {
}
}
#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
info!("n = %?", n);

View file

@ -27,6 +27,7 @@ extern fn cb(data: libc::uintptr_t) -> libc::uintptr_t {
}
}
#[fixed_stack_segment] #[inline(never)]
fn fact(n: uint) -> uint {
unsafe {
info!("n = %?", n);

View file

@ -13,6 +13,7 @@
extern mod externcallback(vers = "0.1");
#[fixed_stack_segment] #[inline(never)]
fn fact(n: uint) -> uint {
unsafe {
info!("n = %?", n);

View file

@ -20,6 +20,7 @@ extern {
pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s;
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let x = TwoU32s {one: 22, two: 23};

View file

@ -19,6 +19,7 @@ extern {
pub fn rust_dbg_extern_identity_TwoU64s(u: TwoU64s) -> TwoU64s;
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let x = TwoU64s {one: 22, two: 23};

View file

@ -24,6 +24,7 @@ extern {
pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s;
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let x = TwoU64s {one: 22, two: 23};

View file

@ -14,6 +14,7 @@ extern {
pub fn rust_dbg_extern_identity_u8(v: u8) -> u8;
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22_u8, rust_dbg_extern_identity_u8(22_u8));

View file

@ -12,6 +12,7 @@ extern {
pub fn rust_dbg_extern_identity_double(v: f64) -> f64;
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22.0_f64, rust_dbg_extern_identity_double(22.0_f64));

View file

@ -14,6 +14,7 @@ extern {
pub fn rust_dbg_extern_identity_u32(v: u32) -> u32;
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22_u32, rust_dbg_extern_identity_u32(22_u32));

View file

@ -14,6 +14,7 @@ extern {
pub fn rust_dbg_extern_identity_u64(v: u64) -> u64;
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22_u64, rust_dbg_extern_identity_u64(22_u64));

View file

@ -8,9 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// xfail-win32 #5745
// xfail-macos Broken on mac i686
struct TwoU16s {
one: u16, two: u16
}
@ -19,6 +16,7 @@ extern {
pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s;
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU16s();

View file

@ -16,6 +16,7 @@ extern {
pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s;
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU32s();

View file

@ -16,6 +16,7 @@ extern {
pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s;
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU64s();

View file

@ -8,9 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// xfail-win32 #5745
// xfail-macos Broken on mac i686
struct TwoU8s {
one: u8, two: u8
}
@ -19,6 +16,7 @@ extern {
pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s;
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU8s();

View file

@ -32,6 +32,7 @@ extern fn cb(data: libc::uintptr_t) -> libc::uintptr_t {
}
}
#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
rustrt::rust_dbg_call(cb, n)

View file

@ -28,6 +28,7 @@ extern fn cb(data: libc::uintptr_t) -> libc::uintptr_t {
}
}
#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
task::deschedule();

View file

@ -2,9 +2,7 @@ use std::cast;
use std::libc;
use std::unstable::run_in_bare_thread;
extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t) -> libc::uintptr_t;
}
externfn!(fn rust_dbg_call(cb: *u8, data: libc::uintptr_t) -> libc::uintptr_t)
pub fn main() {
unsafe {

View file

@ -31,6 +31,7 @@ mod rustrt2 {
}
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
rustrt1::rust_get_test_int();

View file

@ -21,6 +21,7 @@ mod libc {
}
}
#[fixed_stack_segment] #[inline(never)]
fn strlen(str: ~str) -> uint {
// C string is terminated with a zero
do str.with_c_str |buf| {

View file

@ -18,6 +18,7 @@ mod rustrt {
}
}
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
rustrt::rust_get_test_int();

View file

@ -17,6 +17,7 @@
extern mod foreign_lib;
#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let _foo = foreign_lib::rustrt::rust_get_test_int();

View file

@ -19,6 +19,7 @@ fn to_c_int(v: &mut int) -> &mut c_int {
}
}
#[fixed_stack_segment] #[inline(never)]
fn lgamma(n: c_double, value: &mut int) -> c_double {
unsafe {
return m::lgamma(n, to_c_int(value));

View file

@ -4,6 +4,7 @@ use std::libc;
pub struct Fd(c_int);
impl Drop for Fd {
#[fixed_stack_segment] #[inline(never)]
fn drop(&self) {
unsafe {
libc::close(**self);

View file

@ -6,6 +6,7 @@ mod a {
}
}
#[fixed_stack_segment] #[inline(never)]
fn main() {
unsafe {
a::free(transmute(0));

View file

@ -27,6 +27,7 @@ struct Ccx {
x: int
}
#[fixed_stack_segment] #[inline(never)]
fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> {
unsafe {
cast::transmute(libc::malloc(sys::size_of::<Bcx<'blk>>()
@ -38,6 +39,7 @@ fn h<'a>(bcx : &'a Bcx<'a>) -> &'a Bcx<'a> {
return alloc(bcx.fcx.arena);
}
#[fixed_stack_segment] #[inline(never)]
fn g(fcx : &Fcx) {
let bcx = Bcx { fcx: fcx };
let bcx2 = h(&bcx);

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// xfail-test - FIXME(#8538) some kind of problem linking induced by extern "C" fns that I do not understand
// xfail-fast - windows doesn't like this
// Smallest hello world with no runtime

Some files were not shown because too many files have changed in this diff Show more