Comments and cleanup.

This commit is contained in:
Lindsey Kuper 2011-06-28 18:54:05 -07:00
parent 684c0dc494
commit 57e5cde3a2

View File

@ -166,7 +166,6 @@ type local_ctxt =
// Types used for llself.
type val_self_pair = rec(ValueRef v, ty::t t);
type ty_self_pair = tup(TypeRef, ty::t);
@ -719,22 +718,22 @@ fn type_of_fn_full(&@crate_ctxt cx, &span sp, ast::proto proto,
&option::t[TypeRef] obj_self, &vec[ty::arg] inputs,
&ty::t output, uint ty_param_count) -> TypeRef {
let vec[TypeRef] atys = [];
// Arg 0: Output pointer.
// Arg 0: Output pointer.
if (ty::type_has_dynamic_size(cx.tcx, output)) {
atys += [T_typaram_ptr(cx.tn)];
} else { atys += [T_ptr(type_of_inner(cx, sp, output))]; }
// Arg 1: task pointer.
atys += [T_taskptr(cx.tn)];
// Arg 2: Env (closure-bindings / self-obj)
// Arg 2: Env (closure-bindings / self-obj)
alt (obj_self) {
case (some(?t)) { assert (t as int != 0); atys += [t]; }
case (_) { atys += [T_opaque_closure_ptr(cx.tn)]; }
}
// Args >3: ty params, if not acquired via capture...
// Args >3: ty params, if not acquired via capture...
if (obj_self == none[TypeRef]) {
auto i = 0u;
while (i < ty_param_count) {
@ -746,7 +745,6 @@ fn type_of_fn_full(&@crate_ctxt cx, &span sp, ast::proto proto,
// If it's an iter, the 'output' type of the iter is actually the
// *input* type of the function we're given as our iter-block
// argument.
atys +=
[T_fn_pair(cx.tn,
type_of_fn_full(cx, sp, ast::proto_fn, none[TypeRef],
@ -754,8 +752,8 @@ fn type_of_fn_full(&@crate_ctxt cx, &span sp, ast::proto proto,
ty=output)], ty::mk_nil(cx.tcx),
0u))];
}
// ... then explicit args.
// ... then explicit args.
atys += type_of_explicit_args(cx, sp, inputs);
ret T_fn(atys, llvm::LLVMVoidType());
}
@ -5102,37 +5100,79 @@ fn trans_bind_thunk(&@local_ctxt cx, &span sp, &ty::t incoming_fty,
&ty::t outgoing_fty, &vec[option::t[@ast::expr]] args,
&ty::t closure_ty, &vec[ty::t] bound_tys,
uint ty_param_count) -> ValueRef {
// Construct a thunk-call with signature incoming_fty, and that copies
// args forward into a call to outgoing_fty:
// Here we're not necessarily constructing a thunk in the sense of
// "function with no arguments". The result of compiling 'bind f(foo,
// bar, baz)' would be a thunk that, when called, applies f to those
// arguments and returns the result. But we're stretching the meaning of
// the word "thunk" here to also mean the result of compiling, say, 'bind
// f(foo, _, baz)', or any other bind expression that binds f and leaves
// some (or all) of the arguments unbound.
// Here, 'incoming_fty' is the type of the entire bind expression, while
// 'outgoing_fty' is the type of the function that is having some of its
// arguments bound. If f is a function that takes three arguments of type
// int and returns int, and we're translating, say, 'bind f(3, _, 5)',
// then outgoing_fty is the type of f, which is (int, int, int) -> int,
// and incoming_fty is the type of 'bind f(3, _, 5)', which is int -> int.
// Once translated, the entire bind expression will be the call f(foo,
// bar, baz) wrapped in a (so-called) thunk that takes 'bar' as its
// argument and that has bindings of 'foo' to 3 and 'baz' to 5 and a
// pointer to 'f' all saved in its environment. So, our job is to
// construct and return that thunk.
// Give the thunk a name, type, and value.
let str s =
mangle_internal_name_by_path_and_seq(cx.ccx, cx.path, "thunk");
let TypeRef llthunk_ty =
get_pair_fn_ty(type_of(cx.ccx, sp, incoming_fty));
let ValueRef llthunk =
decl_internal_fastcall_fn(cx.ccx.llmod, s, llthunk_ty);
// Create a new function context and block context for the thunk, and hold
// onto a pointer to the first block in the function for later use.
auto fcx = new_fn_ctxt(cx, sp, llthunk);
auto bcx = new_top_block_ctxt(fcx);
auto lltop = bcx.llbb;
auto llclosure_ptr_ty =
type_of(cx.ccx, sp, ty::mk_imm_box(cx.ccx.tcx, closure_ty));
auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
// "target", in this context, means the function that's having some of its
// arguments bound and that will be called inside the thunk we're
// creating. (In our running example, target is the function f.) Pick
// out the pointer to the target function from the environment.
auto lltarget =
GEP_tup_like(bcx, closure_ty, llclosure,
[0, abi::box_rc_field_body, abi::closure_elt_target]);
bcx = lltarget.bcx;
// And then, pick out the target function's own environment. That's what
// we'll use as the environment the thunk gets.
auto lltargetclosure =
bcx.build.GEP(lltarget.val, [C_int(0), C_int(abi::fn_field_box)]);
lltargetclosure = bcx.build.Load(lltargetclosure);
// Get f's return type, which will also be the return type of the entire
// bind expression.
auto outgoing_ret_ty = ty::ty_fn_ret(cx.ccx.tcx, outgoing_fty);
// Get the types of the arguments to f.
auto outgoing_args = ty::ty_fn_args(cx.ccx.tcx, outgoing_fty);
// The 'llretptr' that will arrive in the thunk we're creating also needs
// to be the correct size. Cast it to the size of f's return type, if
// necessary.
auto llretptr = fcx.llretptr;
if (ty::type_has_dynamic_size(cx.ccx.tcx, outgoing_ret_ty)) {
llretptr = bcx.build.PointerCast(llretptr, T_typaram_ptr(cx.ccx.tn));
}
let vec[ValueRef] llargs = [llretptr, fcx.lltaskptr, lltargetclosure];
// Copy in the type parameters.
// Set up the three implicit arguments to the thunk.
let vec[ValueRef] llargs = [llretptr, fcx.lltaskptr, lltargetclosure];
// Copy in the type parameters.
let uint i = 0u;
while (i < ty_param_count) {
auto lltyparam_ptr =
@ -5145,6 +5185,7 @@ fn trans_bind_thunk(&@local_ctxt cx, &span sp, &ty::t incoming_fty,
fcx.lltydescs += [td];
i += 1u;
}
let uint a = 3u; // retptr, task ptr, env come first
let int b = 0;
@ -5199,9 +5240,9 @@ fn trans_bind_thunk(&@local_ctxt cx, &span sp, &ty::t incoming_fty,
auto lltargetfn =
bcx.build.GEP(lltarget.val, [C_int(0), C_int(abi::fn_field_code)]);
// Cast the outgoing function to the appropriate type (see the comments in
// trans_bind below for why this is necessary).
auto lltargetty =
type_of_fn(bcx.fcx.lcx.ccx, sp,
ty::ty_fn_proto(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
@ -5227,8 +5268,8 @@ fn trans_bind(&@block_ctxt cx, &@ast::expr f,
case (some(?e)) { vec::push[@ast::expr](bound, e); }
}
}
// Figure out which tydescs we need to pass, if any.
// Figure out which tydescs we need to pass, if any.
let ty::t outgoing_fty;
let vec[ValueRef] lltydescs;
alt (f_res.generic) {
@ -5244,15 +5285,15 @@ fn trans_bind(&@block_ctxt cx, &@ast::expr f,
}
auto ty_param_count = vec::len[ValueRef](lltydescs);
if (vec::len[@ast::expr](bound) == 0u && ty_param_count == 0u) {
// Trivial 'binding': just return the static pair-ptr.
// Trivial 'binding': just return the static pair-ptr.
ret f_res.res;
} else {
auto bcx = f_res.res.bcx;
auto pair_t = node_type(cx.fcx.lcx.ccx, cx.sp, id);
auto pair_v = alloca(bcx, pair_t);
// Translate the bound expressions.
// Translate the bound expressions.
let vec[ty::t] bound_tys = [];
let vec[ValueRef] bound_vals = [];
auto i = 0u;
@ -5264,33 +5305,54 @@ fn trans_bind(&@block_ctxt cx, &@ast::expr f,
ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
i += 1u;
}
// Synthesize a closure type.
// First, synthesize a tuple type containing the types of all the
// bound expressions.
// bindings_ty = [bound_ty1, bound_ty2, ...]
let ty::t bindings_ty =
ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, bound_tys);
// NB: keep this in sync with T_closure_ptr; we're making
// a ty::t structure that has the same "shape" as the LLVM type
// it constructs.
// Make a vector that contains ty_param_count copies of tydesc_ty.
// (We'll need room for that many tydescs in the closure.)
let ty::t tydesc_ty = ty::mk_type(cx.fcx.lcx.ccx.tcx);
let vec[ty::t] captured_tys =
vec::init_elt[ty::t](tydesc_ty, ty_param_count);
// Get all the types we've got (some of which we synthesized
// ourselves) into a vector. The whole things ends up looking
// like:
// closure_tys = [tydesc_ty, outgoing_fty, [bound_ty1, bound_ty2,
// ...], [tydesc_ty, tydesc_ty, ...]]
let vec[ty::t] closure_tys =
[tydesc_ty, outgoing_fty, bindings_ty,
ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, captured_tys)];
// Finally, synthesize a type for that whole vector.
let ty::t closure_ty =
ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, closure_tys);
// Allocate a box that can hold something closure-sized, including
// space for a refcount.
auto r = trans_malloc_boxed(bcx, closure_ty);
auto box = r.val;
bcx = r.bcx;
// Grab onto the refcount and body parts of the box we allocated.
auto rc =
bcx.build.GEP(box,
[C_int(0), C_int(abi::box_rc_field_refcnt)]);
auto closure =
bcx.build.GEP(box, [C_int(0), C_int(abi::box_rc_field_body)]);
bcx.build.Store(C_int(1), rc);
// Store bindings tydesc.
// Store bindings tydesc.
auto bound_tydesc =
bcx.build.GEP(closure,
[C_int(0), C_int(abi::closure_elt_tydesc)]);
@ -5300,13 +5362,13 @@ fn trans_bind(&@block_ctxt cx, &@ast::expr f,
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
bcx = bindings_tydesc.bcx;
bcx.build.Store(bindings_tydesc.val, bound_tydesc);
// Determine the LLVM type for the outgoing function type. This
// may be different from the type returned by trans_malloc_boxed()
// since we have more information than that function does;
// specifically, we know how many type descriptors the outgoing
// function has, which type_of() doesn't, as only we know which
// item the function refers to.
auto llfnty =
type_of_fn(bcx.fcx.lcx.ccx, cx.sp,
ty::ty_fn_proto(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
@ -5314,8 +5376,8 @@ fn trans_bind(&@block_ctxt cx, &@ast::expr f,
ty::ty_fn_ret(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
ty_param_count);
auto llclosurety = T_ptr(T_fn_pair(bcx.fcx.lcx.ccx.tn, llfnty));
// Store thunk-target.
// Store thunk-target.
auto bound_target =
bcx.build.GEP(closure,
[C_int(0), C_int(abi::closure_elt_target)]);
@ -5334,9 +5396,9 @@ fn trans_bind(&@block_ctxt cx, &@ast::expr f,
bcx = copy_val(bcx, INIT, bound, v, bound_tys.(i)).bcx;
i += 1u;
}
// If necessary, copy tydescs describing type parameters into the
// appropriate slot in the closure.
alt (f_res.generic) {
case (none) {/* nothing to do */ }
case (some(?ginfo)) {
@ -5356,17 +5418,19 @@ fn trans_bind(&@block_ctxt cx, &@ast::expr f,
outgoing_fty = ginfo.item_type;
}
}
// Make thunk and store thunk-ptr in outer pair's code slot.
// Make thunk and store thunk-ptr in outer pair's code slot.
auto pair_code =
bcx.build.GEP(pair_v, [C_int(0), C_int(abi::fn_field_code)]);
// The type of the entire bind expression.
let ty::t pair_ty = node_id_type(cx.fcx.lcx.ccx, id);
let ValueRef llthunk =
trans_bind_thunk(cx.fcx.lcx, cx.sp, pair_ty, outgoing_fty,
args, closure_ty, bound_tys, ty_param_count);
bcx.build.Store(llthunk, pair_code);
// Store box ptr in outer pair's box slot.
// Store box ptr in outer pair's box slot.
auto tn = bcx.fcx.lcx.ccx.tn;
auto pair_box =
bcx.build.GEP(pair_v, [C_int(0), C_int(abi::fn_field_box)]);
@ -5533,12 +5597,10 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
alt (f_res.llobj) {
case (some(_)) {
// It's a vtbl entry.
faddr = f_res.res.bcx.build.Load(faddr);
}
case (none) {
// It's a closure.
auto bcx = f_res.res.bcx;
auto pair = faddr;
faddr =
@ -5553,7 +5615,6 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
alt (f_res.method_ty) {
case (some(?meth)) {
// self-call
fn_ty = meth;
}
case (_) { fn_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f); }
@ -7452,8 +7513,8 @@ fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ValueRef llfndecl,
option::t[ty_self_pair] ty_self, &vec[ast::ty_param] ty_params,
ast::node_id id) {
set_uwtable(llfndecl);
// Set up arguments to the function.
// Set up arguments to the function.
auto fcx = new_fn_ctxt(cx, sp, llfndecl);
create_llargs_for_fn_args(fcx, f.proto, ty_self,
ty::ret_ty_of_fn(cx.ccx.tcx, id),
@ -7465,18 +7526,18 @@ fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ValueRef llfndecl,
}
auto arg_tys = arg_tys_of_fn(fcx.lcx.ccx, id);
copy_args_to_allocas(fcx, f.decl.inputs, arg_tys);
// Create the first basic block in the function and keep a handle on it to
// pass to finish_fn later.
auto bcx = new_top_block_ctxt(fcx);
add_cleanups_for_args(bcx, f.decl.inputs, arg_tys);
auto lltop = bcx.llbb;
auto block_ty = node_id_type(cx.ccx, f.body.node.id);
// This call to trans_block is the place where we bridge between
// translation calls that don't have a return value (trans_crate,
// trans_mod, trans_item, trans_obj, et cetera) and those that do
// (trans_block, trans_expr, et cetera).
auto rslt =
if (!ty::type_is_nil(cx.ccx.tcx, block_ty) &&
!ty::type_is_bot(cx.ccx.tcx, block_ty)) {
@ -7564,7 +7625,6 @@ fn trans_dtor(@local_ctxt cx, TypeRef llself_ty, ty::t self_ty,
ret llfn;
}
// trans_obj: creates an LLVM function that is the object constructor for the
// object being translated.
fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::node_id ctor_id,
@ -7587,45 +7647,46 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::node_id ctor_id,
[rec(mode=ast::alias(false), ty=f.ty, ident=f.ident, id=f.id)];
}
auto fcx = new_fn_ctxt(cx, sp, llctor_decl);
// Both regular arguments and type parameters are handled here.
// Both regular arguments and type parameters are handled here.
create_llargs_for_fn_args(fcx, ast::proto_fn, none[ty_self_pair],
ty::ret_ty_of_fn(ccx.tcx, ctor_id),
fn_args, ty_params);
let vec[ty::arg] arg_tys = arg_tys_of_fn(ccx, ctor_id);
copy_args_to_allocas(fcx, fn_args, arg_tys);
// Create the first block context in the function and keep a handle on it
// to pass to finish_fn later.
auto bcx = new_top_block_ctxt(fcx);
auto lltop = bcx.llbb;
// Pick up the type of this object by looking at our own output type, that
// is, the output type of the object constructor we're building.
auto self_ty = ty::ret_ty_of_fn(ccx.tcx, ctor_id);
auto llself_ty = type_of(ccx, sp, self_ty);
// Set up the two-word pair that we're going to return from the object
// constructor we're building. The two elements of this pair will be a
// vtable pointer and a body pointer. (llretptr already points to the
// place where this two-word pair should go; it was pre-allocated by the
// caller of the function.)
auto pair = bcx.fcx.llretptr;
// Grab onto the first and second elements of the pair.
// abi::obj_field_vtbl and abi::obj_field_box simply specify words 0 and 1
// of 'pair'.
auto pair_vtbl =
bcx.build.GEP(pair, [C_int(0), C_int(abi::obj_field_vtbl)]);
auto pair_box =
bcx.build.GEP(pair, [C_int(0), C_int(abi::obj_field_box)]);
// Make a vtable for this object: a static array of pointers to functions.
// It will be located in the read-only memory of the executable we're
// creating and will contain ValueRefs for all of this object's methods.
// create_vtbl returns a pointer to the vtable, which we store.
auto vtbl = create_vtbl(cx, llself_ty, self_ty, ob, ty_params, none);
bcx.build.Store(vtbl, pair_vtbl);
// Next we have to take care of the other half of the pair we're
// returning: a boxed (reference-counted) tuple containing a tydesc,
// typarams, and fields.
@ -7634,10 +7695,10 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::node_id ctor_id,
// (Pertains to issues #538/#539/#540/#543.)
let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn);
// FIXME: we should probably also allocate a box for empty objs that have
// a dtor, since otherwise they are never dropped, and the dtor never
// runs.
if (vec::len[ast::ty_param](ty_params) == 0u &&
vec::len[ty::arg](arg_tys) == 0u) {
// If the object we're translating has no fields or type parameters,