Simplify the _rust_main/rust_start interface

rust_start will always call _rust_main with the command line args, and it is
_rust_main's responsibility to free the args ivec heap. _rust_main will be
generated slightly differently depending on whether main takes an ivec or not:
if so then it's just passed through to main, otherwise it frees the ivec
directly.
This commit is contained in:
Brian Anderson 2011-08-17 20:31:55 -07:00
parent c2d8a4df35
commit 0a8bffceb3
3 changed files with 28 additions and 35 deletions

View file

@ -6378,6 +6378,8 @@ fn decl_fn_and_pair_full(ccx: &@crate_ctxt, sp: &span, path: &[str],
}
}
// Create a _rust_main(args: [str]) function which will be called from the
// runtime rust_start function
fn create_main_wrapper(ccx: &@crate_ctxt, sp: &span,
main_llfn: ValueRef, main_node_type: ty::t) {
@ -6392,14 +6394,13 @@ fn create_main_wrapper(ccx: &@crate_ctxt, sp: &span,
};
let llfn = create_main(ccx, sp, main_llfn, main_takes_ivec);
create_main_type_indicator(ccx, main_takes_ivec);
ccx.main_fn = some(llfn);
fn create_main(ccx: &@crate_ctxt,
sp: &span,
main_llfn: ValueRef,
takes_ivec: bool) -> ValueRef {
let ivecarg = {
let ivecarg_ty: ty::arg = {
mode: ty::mo_val,
ty: ty::mk_ivec(ccx.tcx, {
ty: ty::mk_str(ccx.tcx),
@ -6408,13 +6409,15 @@ fn create_main_wrapper(ccx: &@crate_ctxt, sp: &span,
};
let llfty = type_of_fn(ccx, sp,
ast::proto_fn,
~[ivecarg],
~[ivecarg_ty],
ty::mk_nil(ccx.tcx),
0u);
let llfdecl = decl_fastcall_fn(ccx.llmod, "_rust_main", llfty);
let fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, llfdecl);
let bcx = new_top_block_ctxt(fcx);
let lltop = bcx.llbb;
if takes_ivec {
let lloutputarg = llvm::LLVMGetParam(llfdecl, 0u);
@ -6430,6 +6433,15 @@ fn create_main_wrapper(ccx: &@crate_ctxt, sp: &span,
let lloutputarg = llvm::LLVMGetParam(llfdecl, 0u);
let lltaskarg = llvm::LLVMGetParam(llfdecl, 1u);
let llenvarg = llvm::LLVMGetParam(llfdecl, 2u);
let llargvarg = llvm::LLVMGetParam(llfdecl, 3u);
// If the crate's main function doesn't take the args vector then
// we're responsible for freeing it
let llivecptr = alloca(bcx, val_ty(llargvarg));
bcx.build.Store(llargvarg, llivecptr);
bcx = maybe_free_ivec_heap_part(bcx, llivecptr,
ty::mk_str(ccx.tcx)).bcx;
let args = ~[lloutputarg,
lltaskarg,
llenvarg];
@ -6437,21 +6449,10 @@ fn create_main_wrapper(ccx: &@crate_ctxt, sp: &span,
}
build_return(bcx);
let lltop = bcx.llbb;
finish_fn(fcx, lltop);
ret llfdecl;
}
// FIXME: Remove after main takes only ivec
// Sets a global value hinting to the runtime whether main takes
// a vec or an ivec
fn create_main_type_indicator(ccx: &@crate_ctxt, takes_ivec: bool) {
let i = llvm::LLVMAddGlobal(ccx.llmod, T_int(),
str::buf("_rust_main_is_ivec"));
llvm::LLVMSetInitializer(i, C_int(takes_ivec as int));
llvm::LLVMSetGlobalConstant(i, True);
}
}

View file

@ -14,10 +14,7 @@
@_rust_crate_map_toplevel = external global %0
; FIXME: Remove after main takes only ivec
@_rust_main_is_ivec = external global i32
declare i32 @rust_start(i32, i32, i32, i32, i32)
declare i32 @rust_start(i32, i32, i32, i32)
declare external fastcc void @_rust_main(i1* nocapture, %task*, %2* nocapture, %ivec)
@ -29,8 +26,6 @@ define void @_rust_main_wrap(i1* nocapture, %task *, %2* nocapture, %ivec *)
}
define i32 @"MAIN"(i32, i32) {
%is_ivec = load i32 *@_rust_main_is_ivec
%3 = tail call i32 @rust_start(i32 ptrtoint (void (i1*, %task*, %2*, %ivec*)* @_rust_main_wrap to i32), i32 %0, i32 %1, i32 ptrtoint (%0* @_rust_crate_map_toplevel to i32), i32 %is_ivec)
%3 = tail call i32 @rust_start(i32 ptrtoint (void (i1*, %task*, %2*, %ivec*)* @_rust_main_wrap to i32), i32 %0, i32 %1, i32 ptrtoint (%0* @_rust_crate_map_toplevel to i32))
ret i32 %3
}

View file

@ -14,8 +14,7 @@ command_line_args : public kernel_owned<command_line_args>
command_line_args(rust_task *task,
int sys_argc,
char **sys_argv,
bool main_is_ivec)
char **sys_argv)
: kernel(task->kernel),
task(task),
argc(sys_argc),
@ -67,15 +66,13 @@ command_line_args : public kernel_owned<command_line_args>
args_ivec->fill = 0;
size_t ivec_exterior_sz = sizeof(rust_str *) * argc;
args_ivec->alloc = ivec_exterior_sz;
if (main_is_ivec) {
// NB: This is freed by some ivec machinery, probably the drop
// glue in main, so we don't free it ourselves
args_ivec->payload.ptr = (rust_ivec_heap *)
kernel->malloc(ivec_exterior_sz + sizeof(size_t),
"command line arg exterior");
args_ivec->payload.ptr->fill = ivec_exterior_sz;
memcpy(&args_ivec->payload.ptr->data, strs, ivec_exterior_sz);
}
// NB: This is freed by some ivec machinery, probably the drop
// glue in main, so we don't free it ourselves
args_ivec->payload.ptr = (rust_ivec_heap *)
kernel->malloc(ivec_exterior_sz + sizeof(size_t),
"command line arg exterior");
args_ivec->payload.ptr->fill = ivec_exterior_sz;
memcpy(&args_ivec->payload.ptr->data, strs, ivec_exterior_sz);
}
~command_line_args() {
@ -107,7 +104,7 @@ int check_claims = 0;
extern "C" CDECL int
rust_start(uintptr_t main_fn, int argc, char **argv,
void* crate_map, int main_takes_ivec) {
void* crate_map) {
rust_env *env = load_env();
@ -122,7 +119,7 @@ rust_start(uintptr_t main_fn, int argc, char **argv,
rust_scheduler *sched = root_task->sched;
command_line_args *args
= new (kernel, "main command line args")
command_line_args(root_task, argc, argv, main_takes_ivec);
command_line_args(root_task, argc, argv);
DLOG(sched, dom, "startup: %d args in 0x%" PRIxPTR,
args->argc, (uintptr_t)args->args);
@ -154,7 +151,7 @@ rust_start(uintptr_t main_fn, int argc, char **argv,
extern "C" CDECL int
rust_start_ivec(uintptr_t main_fn, int argc, char **argv,
void* crate_map, int main_takes_ivec) {
return rust_start(main_fn, argc, argv, crate_map, main_takes_ivec);
return rust_start(main_fn, argc, argv, crate_map);
}