Skip to content

Commit d563bcd

Browse files
committed
---
yaml --- r: 4715 b: refs/heads/master c: 053b8bf h: refs/heads/master i: 4713: 3e0b41a 4711: 5faf180 v: v3
1 parent b087174 commit d563bcd

File tree

7 files changed

+222
-20
lines changed

7 files changed

+222
-20
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: 76aab80e3988caf71b7d6299e5a7ebb06cf2bbbb
2+
refs/heads/master: 053b8bff5a81a0cb6c347f8c371fa5b66f48dbda

trunk/src/comp/middle/trans.rs

Lines changed: 136 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6345,28 +6345,153 @@ fn decl_fn_and_pair_full(ccx: &@crate_ctxt, sp: &span, path: &[str],
63456345
}
63466346
_ { ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!"); }
63476347
}
6348-
let is_main: bool = is_main_name(path) && !ccx.sess.get_opts().library;
6349-
// Declare the function itself.
63506348

6351-
let s: str =
6352-
if is_main {
6353-
"_rust_main"
6354-
} else { mangle_internal_name_by_path(ccx, path) };
6349+
let s: str = mangle_internal_name_by_path(ccx, path);
63556350
let llfn: ValueRef = decl_internal_fastcall_fn(ccx.llmod, s, llfty);
63566351
// Declare the global constant pair that points to it.
63576352

63586353
let ps: str = mangle_exported_name(ccx, path, node_type);
63596354
register_fn_pair(ccx, ps, llfty, llfn, node_id);
6355+
6356+
let is_main: bool = is_main_name(path) && !ccx.sess.get_opts().library;
63606357
if is_main {
6361-
if ccx.main_fn != none[ValueRef] {
6362-
ccx.sess.span_fatal(sp, "multiple 'main' functions");
6358+
create_main_wrapper(ccx, sp, llfn, node_type);
6359+
}
6360+
}
6361+
6362+
fn create_main_wrapper(ccx: &@crate_ctxt, sp: &span,
6363+
main_llfn: ValueRef, main_node_type: ty::t) {
6364+
6365+
if ccx.main_fn != none[ValueRef] {
6366+
ccx.sess.span_fatal(sp, "multiple 'main' functions");
6367+
}
6368+
6369+
tag main_mode {
6370+
mm_nil;
6371+
mm_vec;
6372+
mm_ivec;
6373+
};
6374+
6375+
let main_mode = alt ty::struct(ccx.tcx, main_node_type) {
6376+
ty::ty_fn(_, args, _ ,_ ,_) {
6377+
if std::ivec::len(args) == 0u {
6378+
mm_nil
6379+
} else {
6380+
alt ty::struct(ccx.tcx, args.(0).ty) {
6381+
ty::ty_ivec(_) { mm_ivec }
6382+
ty::ty_vec(_) { mm_vec }
6383+
}
63636384
}
6364-
llvm::LLVMSetLinkage(llfn,
6365-
lib::llvm::LLVMExternalLinkage as llvm::Linkage);
6366-
ccx.main_fn = some(llfn);
6385+
}
6386+
};
6387+
6388+
// Have to create two different main functions depending on whether
6389+
// main was declared to take vec or ivec
6390+
let llfn_vec = create_main_wrapper_vec(ccx, sp, main_llfn, main_mode);
6391+
let llfn_ivec = create_main_wrapper_ivec(ccx, sp, main_llfn, main_mode);
6392+
let takes_ivec = main_mode == mm_ivec;
6393+
// Create a global to tell main.ll which main we want to use
6394+
create_main_type_indicator(ccx, takes_ivec);
6395+
ccx.main_fn = takes_ivec ? some(llfn_ivec) : some(llfn_vec);
6396+
6397+
fn create_main_wrapper_vec(ccx: &@crate_ctxt,
6398+
sp: &span,
6399+
main_llfn: ValueRef,
6400+
main_mode: main_mode) -> ValueRef {
6401+
6402+
let vecarg = {
6403+
mode: ty::mo_val,
6404+
ty: ty::mk_vec(ccx.tcx, {
6405+
ty: ty::mk_str(ccx.tcx),
6406+
mut: ast::imm
6407+
})
6408+
};
6409+
let llfty = type_of_fn(ccx, sp,
6410+
ast::proto_fn,
6411+
~[vecarg],
6412+
ty::mk_nil(ccx.tcx),
6413+
0u);
6414+
let llfdecl = decl_fastcall_fn(ccx.llmod, "_rust_main", llfty);
6415+
6416+
let fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, llfdecl);
6417+
let bcx = new_top_block_ctxt(fcx);
6418+
6419+
if main_mode != mm_ivec {
6420+
let lloutputarg = llvm::LLVMGetParam(llfdecl, 0u);
6421+
let lltaskarg = llvm::LLVMGetParam(llfdecl, 1u);
6422+
let llenvarg = llvm::LLVMGetParam(llfdecl, 2u);
6423+
let llargvarg = llvm::LLVMGetParam(llfdecl, 3u);
6424+
let args = alt main_mode {
6425+
mm_nil. { ~[lloutputarg,
6426+
lltaskarg,
6427+
llenvarg] }
6428+
mm_vec. { ~[lloutputarg,
6429+
lltaskarg,
6430+
llenvarg,
6431+
llargvarg] }
6432+
};
6433+
bcx.build.FastCall(main_llfn, args);
6434+
}
6435+
bcx.build.RetVoid();
6436+
6437+
let lltop = bcx.llbb;
6438+
finish_fn(fcx, lltop);
6439+
6440+
ret llfdecl;
6441+
}
6442+
6443+
fn create_main_wrapper_ivec(ccx: &@crate_ctxt,
6444+
sp: &span,
6445+
main_llfn: ValueRef,
6446+
main_mode: main_mode) -> ValueRef {
6447+
let ivecarg = {
6448+
mode: ty::mo_val,
6449+
ty: ty::mk_ivec(ccx.tcx, {
6450+
ty: ty::mk_str(ccx.tcx),
6451+
mut: ast::imm
6452+
})
6453+
};
6454+
let llfty = type_of_fn(ccx, sp,
6455+
ast::proto_fn,
6456+
~[ivecarg],
6457+
ty::mk_nil(ccx.tcx),
6458+
0u);
6459+
let llfdecl = decl_fastcall_fn(ccx.llmod, "_rust_main_ivec", llfty);
6460+
6461+
let fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, llfdecl);
6462+
let bcx = new_top_block_ctxt(fcx);
6463+
6464+
if main_mode == mm_ivec {
6465+
let lloutputarg = llvm::LLVMGetParam(llfdecl, 0u);
6466+
let lltaskarg = llvm::LLVMGetParam(llfdecl, 1u);
6467+
let llenvarg = llvm::LLVMGetParam(llfdecl, 2u);
6468+
let llargvarg = llvm::LLVMGetParam(llfdecl, 3u);
6469+
let args = ~[lloutputarg,
6470+
lltaskarg,
6471+
llenvarg,
6472+
llargvarg];
6473+
bcx.build.FastCall(main_llfn, args);
6474+
}
6475+
bcx.build.RetVoid();
6476+
6477+
let lltop = bcx.llbb;
6478+
finish_fn(fcx, lltop);
6479+
6480+
ret llfdecl;
6481+
}
6482+
6483+
// FIXME: Remove after main takes only ivec
6484+
// Sets a global value hinting to the runtime whether main takes
6485+
// a vec or an ivec
6486+
fn create_main_type_indicator(ccx: &@crate_ctxt, takes_ivec: bool) {
6487+
let i = llvm::LLVMAddGlobal(ccx.llmod, T_int(),
6488+
str::buf("_rust_main_is_ivec"));
6489+
llvm::LLVMSetInitializer(i, C_int(takes_ivec as int));
6490+
llvm::LLVMSetGlobalConstant(i, True);
63676491
}
63686492
}
63696493

6494+
63706495
// Create a closure: a pair containing (1) a ValueRef, pointing to where the
63716496
// fn's definition is in the executable we're creating, and (2) a pointer to
63726497
// space for the function's environment.

trunk/src/comp/middle/typeck.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2715,13 +2715,21 @@ fn check_item(ccx: @crate_ctxt, it: &@ast::item) {
27152715

27162716
fn arg_is_argv_ty(tcx: &ty::ctxt, a: &ty::arg) -> bool {
27172717
alt ty::struct(tcx, a.ty) {
2718+
// FIXME: Remove after main takes only ivec
27182719
ty::ty_vec(mt) {
27192720
if mt.mut != ast::imm { ret false; }
27202721
alt ty::struct(tcx, mt.ty) {
27212722
ty::ty_str. { ret true; }
27222723
_ { ret false; }
27232724
}
27242725
}
2726+
ty::ty_ivec(mt) {
2727+
if mt.mut != ast::imm { ret false; }
2728+
alt ty::struct(tcx, mt.ty) {
2729+
ty::ty_str. { ret true; }
2730+
_ { ret false; }
2731+
}
2732+
}
27252733
_ { ret false; }
27262734
}
27272735
}

trunk/src/rt/main.ll.in

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,48 @@
66
%5 = type { i32, i32, i32, i32, [0 x %6*] }
77
%6 = type { i32, i32, i32, i32, [0 x i8] }
88

9+
%tydesc = type { %tydesc**, i32, i32, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*, i8*, i8)* }
10+
11+
%task = type { i32, i32, i32, i32, i32, i32, i32, i32 }
12+
13+
%ivec = type { i32, i32, [4 x { i32, i32, i32, i32, [0 x i8] }*] }
914

1015
@_rust_crate_map_toplevel = external global %0
1116

12-
declare fastcc void @_rust_main(i1* nocapture, %task*, %2* nocapture, %5*);
13-
declare i32 @rust_start(i32, i32, i32, i32)
17+
; FIXME: Remove after main takes only ivec
18+
@_rust_main_is_ivec = external global i32
1419

15-
%tydesc = type { %tydesc**, i32, i32, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*, i8*, i8)* }
20+
declare i32 @rust_start(i32, i32, i32, i32)
1621

17-
%task = type { i32, i32, i32, i32, i32, i32, i32, i32 }
22+
declare external fastcc void @_rust_main(i1* nocapture, %task*, %2* nocapture, %5*);
1823

1924
define void @_rust_main_wrap(i1* nocapture, %task *, %2* nocapture, %5 *)
2025
{
2126
tail call fastcc void @_rust_main(i1* %0, %task *%1, %2* nocapture %2, %5 *%3)
2227
ret void
2328
}
2429

30+
declare i32 @rust_start_ivec(i32, i32, i32, i32, i32)
31+
32+
declare external fastcc void @_rust_main_ivec(i1* nocapture, %task*, %2* nocapture, %ivec)
33+
34+
define void @_rust_main_wrap_ivec(i1* nocapture, %task *, %2* nocapture, %ivec *)
35+
{
36+
%ivec = load %ivec *%3
37+
tail call fastcc void @_rust_main_ivec(i1* %0, %task *%1, %2* nocapture %2, %ivec %ivec)
38+
ret void
39+
}
40+
2541
define i32 @"MAIN"(i32, i32) {
42+
%is_ivec = load i32 *@_rust_main_is_ivec
43+
%is_ivec1 = trunc i32 %is_ivec to i1
44+
br i1 %is_ivec1, label %ivec, label %evec
45+
46+
evec:
2647
%3 = tail call i32 @rust_start(i32 ptrtoint (void (i1*, %task*, %2*, %5*)* @_rust_main_wrap to i32), i32 %0, i32 %1, i32 ptrtoint (%0* @_rust_crate_map_toplevel to i32))
2748
ret i32 %3
49+
50+
ivec:
51+
%4 = tail call i32 @rust_start_ivec(i32 ptrtoint (void (i1*, %task*, %2*, %ivec*)* @_rust_main_wrap_ivec to i32), i32 %0, i32 %1, i32 ptrtoint (%0* @_rust_crate_map_toplevel to i32), i32 %is_ivec)
52+
ret i32 %4
2853
}

trunk/src/rt/rust.cpp

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ command_line_args : public kernel_owned<command_line_args>
1010

1111
// vec[str] passed to rust_task::start.
1212
rust_vec *args;
13+
rust_ivec *args_ivec;
1314

1415
command_line_args(rust_task *task,
1516
int sys_argc,
16-
char **sys_argv)
17+
char **sys_argv,
18+
bool main_is_ivec)
1719
: kernel(task->kernel),
1820
task(task),
1921
argc(sys_argc),
@@ -49,15 +51,39 @@ command_line_args : public kernel_owned<command_line_args>
4951
mem = kernel->malloc(str_alloc, "command line arg");
5052
strs[i] = new (mem) rust_str(str_alloc, str_fill,
5153
(uint8_t const *)argv[i]);
54+
strs[i]->ref_count++;
5255
}
5356
args->fill = vec_fill;
5457
// If the caller has a declared args array, they may drop; but
5558
// we don't know if they have such an array. So we pin the args
5659
// array here to ensure it survives to program-shutdown.
5760
args->ref();
61+
62+
if (main_is_ivec) {
63+
size_t ivec_interior_sz =
64+
sizeof(size_t) * 2 + sizeof(rust_str *) * 4;
65+
args_ivec = (rust_ivec *)
66+
kernel->malloc(ivec_interior_sz,
67+
"command line arg interior");
68+
args_ivec->fill = 0;
69+
size_t ivec_exterior_sz = sizeof(rust_str *) * argc;
70+
args_ivec->alloc = ivec_exterior_sz;
71+
// NB: This is freed by some ivec machinery, probably the drop
72+
// glue in main, so we don't free it ourselves
73+
args_ivec->payload.ptr = (rust_ivec_heap *)
74+
kernel->malloc(ivec_exterior_sz + sizeof(size_t),
75+
"command line arg exterior");
76+
args_ivec->payload.ptr->fill = ivec_exterior_sz;
77+
memcpy(&args_ivec->payload.ptr->data, strs, ivec_exterior_sz);
78+
} else {
79+
args_ivec = NULL;
80+
}
5881
}
5982

6083
~command_line_args() {
84+
if (args_ivec) {
85+
kernel->free(args_ivec);
86+
}
6187
if (args) {
6288
// Drop the args we've had pinned here.
6389
rust_str **strs = (rust_str**) &args->data[0];
@@ -84,7 +110,8 @@ command_line_args : public kernel_owned<command_line_args>
84110
int check_claims = 0;
85111

86112
extern "C" CDECL int
87-
rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
113+
rust_start_ivec(uintptr_t main_fn, int argc, char **argv,
114+
void* crate_map, int main_is_ivec) {
88115

89116
rust_env *env = load_env();
90117

@@ -99,15 +126,21 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
99126
rust_scheduler *sched = root_task->sched;
100127
command_line_args *args
101128
= new (kernel, "main command line args")
102-
command_line_args(root_task, argc, argv);
129+
command_line_args(root_task, argc, argv, main_is_ivec);
103130

104131
DLOG(sched, dom, "startup: %d args in 0x%" PRIxPTR,
105132
args->argc, (uintptr_t)args->args);
106133
for (int i = 0; i < args->argc; i++) {
107134
DLOG(sched, dom, "startup: arg[%d] = '%s'", i, args->argv[i]);
108135
}
109136

110-
root_task->start(main_fn, (uintptr_t)args->args);
137+
if (main_is_ivec) {
138+
DLOG(sched, dom, "main takes ivec");
139+
root_task->start(main_fn, (uintptr_t)args->args_ivec);
140+
} else {
141+
DLOG(sched, dom, "main takes vec");
142+
root_task->start(main_fn, (uintptr_t)args->args);
143+
}
111144
root_task->deref();
112145
root_task = NULL;
113146

@@ -127,6 +160,13 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
127160
return ret;
128161
}
129162

163+
extern "C" CDECL int
164+
rust_start(uintptr_t main_fn, int argc, char **argv,
165+
void* crate_map) {
166+
return rust_start_ivec(main_fn, argc, argv, crate_map, 0);
167+
}
168+
169+
130170
//
131171
// Local Variables:
132172
// mode: C++

trunk/src/rt/rustrt.def.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ rust_process_wait
6262
rust_ptr_eq
6363
rust_run_program
6464
rust_start
65+
rust_start_ivec
6566
rust_getcwd
6667
set_min_stack
6768
sched_threads

trunk/src/test/run-pass/main-ivec.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main(args: [str]) {
2+
for s in args { log s }
3+
}

0 commit comments

Comments
 (0)