Comments, cleanup, whitespace, refactoring.

This commit is contained in:
Lindsey Kuper 2011-08-10 13:10:38 -07:00
parent b23360ec8e
commit 007af36bb3

View file

@ -23,26 +23,26 @@ import trans::*;
export trans_anon_obj;
export trans_obj;
// trans_obj: creates an LLVM function that is the object constructor for the
// trans_obj: create an LLVM function that is the object constructor for the
// object being translated.
fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,
ctor_id: ast::node_id, ty_params: &[ast::ty_param]) {
// To make a function, we have to create a function context and, inside
// that, a number of block contexts for which code is generated.
let ccx = cx.ccx;
let llctor_decl;
alt ccx.item_ids.find(ctor_id) {
some(x) { llctor_decl = x; }
_ { cx.ccx.sess.span_fatal(sp, "unbound llctor_decl in trans_obj"); }
}
// Much like trans_fn, we must create an LLVM function, but since we're
// starting with an ast::_obj rather than an ast::_fn, we have some setup
// work to do.
// The fields of our object will become the arguments to the function
// we're creating.
let fn_args: [ast::arg] = ~[];
for f: ast::obj_field in ob.fields {
fn_args +=
@ -93,10 +93,6 @@ fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,
// 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.
// FIXME: What about inner_obj? Do we have to think about it here?
// (Pertains to issues #538/#539/#540/#543.)
let llbox_ty: TypeRef = T_ptr(T_empty_struct());
if std::ivec::len[ast::ty_param](ty_params) == 0u &&
@ -122,7 +118,8 @@ fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,
// Tuple type for typarams: [typaram, ...]
let typarams_ty: ty::t = ty::mk_imm_tup(ccx.tcx, tps);
// Tuple type for body: [tydesc_ty, [typaram, ...], [field, ...]]
// Tuple type for body:
// [tydesc_ty, [typaram, ...], [field, ...]]
let body_ty: ty::t =
ty::mk_imm_tup(ccx.tcx, ~[tydesc_ty, typarams_ty, fields_ty]);
@ -215,12 +212,10 @@ fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,
fn trans_anon_obj(bcx: @block_ctxt, sp: &span, anon_obj: &ast::anon_obj,
id: ast::node_id) -> result {
let ccx = bcx_ccx(bcx);
// Fields.
// FIXME (part of issue #538): Where do we fill in the field *values* from
// the outer object?
// Fields. FIXME (part of issue #538): Where do we fill in the field
// *values* from the outer object?
let additional_fields: [ast::anon_obj_field] = ~[];
let additional_field_vals: [result] = ~[];
let additional_field_tys: [ty::t] = ~[];
@ -254,32 +249,31 @@ fn trans_anon_obj(bcx: @block_ctxt, sp: &span, anon_obj: &ast::anon_obj,
let vtbl;
alt anon_obj.inner_obj {
none. {
// We need a dummy inner_obj_ty for setting up the object body
// later.
// We need a dummy inner_obj_ty for setting up the object body later.
inner_obj_ty = ty::mk_type(ccx.tcx);
// If there's no inner_obj -- that is, if we're just adding new
// fields rather than extending an existing object -- then we just
// pass the outer object to create_vtbl(). Our vtable won't need
// If there's no inner_obj -- that is, if we're creating a new object
// from nothing rather than extending an existing object -- then we
// just pass the outer object to create_vtbl(). Our vtable won't need
// to have any forwarding slots.
vtbl =
create_vtbl(bcx.fcx.lcx, sp, outer_obj_ty, wrapper_obj, ~[], none,
additional_field_tys);
}
some(e) {
// TODO: What makes more sense to get the type of an expr --
// calling ty::expr_ty(ccx.tcx, e) on it or calling
// TODO: What makes more sense to get the type of an expr -- calling
// ty::expr_ty(ccx.tcx, e) on it or calling
// ty::node_id_to_type(ccx.tcx, id) on its id?
inner_obj_ty = ty::expr_ty(ccx.tcx, e);
//inner_obj_ty = ty::node_id_to_type(ccx.tcx, e.id);
// If there's a inner_obj, we pass its type along to create_vtbl().
// Part of what create_vtbl() will do is take the set difference
// of methods defined on the original and methods being added.
// For every method defined on the original that does *not* have
// one with a matching name and type being added, we'll need to
// create a forwarding slot. And, of course, we need to create a
// normal vtable entry for every method being added.
// Part of what create_vtbl() will do is take the set difference of
// methods defined on the original and methods being added. For every
// method defined on the original that does *not* have one with a
// matching name and type being added, we'll need to create a
// forwarding slot. And, of course, we need to create a normal vtable
// entry for every method being added.
vtbl =
create_vtbl(bcx.fcx.lcx, sp, outer_obj_ty, wrapper_obj, ~[],
some(inner_obj_ty), additional_field_tys);
@ -294,8 +288,6 @@ fn trans_anon_obj(bcx: @block_ctxt, sp: &span, anon_obj: &ast::anon_obj,
add_clean_temp(bcx, pair, t);
// 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'.
let pair_vtbl =
bcx.build.GEP(pair, ~[C_int(0), C_int(abi::obj_field_vtbl)]);
let pair_box =
@ -414,8 +406,8 @@ fn trans_anon_obj(bcx: @block_ctxt, sp: &span, anon_obj: &ast::anon_obj,
// Used only inside create_vtbl and create_backwarding_vtbl to distinguish
// different kinds of slots we'll have to create.
tag vtbl_mthd {
// Normal methods are complete AST nodes, but for forwarding methods,
// the only information we'll have about them is their type.
// Normal methods are complete AST nodes, but for forwarding methods, the
// only information we'll have about them is their type.
normal_mthd(@ast::method);
fwding_mthd(@ty::method);
}
@ -443,8 +435,8 @@ fn vtbl_mthd_lteq(a: &vtbl_mthd, b: &vtbl_mthd) -> bool {
}
}
// Used by create_vtbl to filter a list of methods to remove the ones that we
// don't need forwarding slots for.
// filtering_fn: Used by create_vtbl to filter a list of methods to remove the
// ones that we don't need forwarding slots for.
fn filtering_fn(cx: @local_ctxt, m: &vtbl_mthd,
addtl_meths: [@ast::method]) ->
option::t[vtbl_mthd] {
@ -468,8 +460,8 @@ fn filtering_fn(cx: @local_ctxt, m: &vtbl_mthd,
}
}
// Create a vtable for an object being translated. Returns a pointer into
// read-only memory.
// create_vtbl: Create a vtable for a regular object or for an outer anonymous
// object, and return a pointer to it.
fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
ob: &ast::_obj, ty_params: &[ast::ty_param],
inner_obj_ty: option::t[ty::t],
@ -479,6 +471,9 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
alt inner_obj_ty {
none. {
// We're creating a vtable for a regular object, or for an anonymous
// object that doesn't extend an existing one.
// Sort and process all the methods.
let meths =
std::sort::ivector::merge_sort[@ast::method]
@ -490,24 +485,18 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
}
}
some(inner_obj_ty) {
// If this vtable is being created for an extended object, then the
// vtable needs to contain 'forwarding slots' for methods that were on
// the original object and are not being overridden by the extended
// one. So, to find the set of methods that we need forwarding slots
// for, we need to take the set difference of inner_obj_methods
// (methods on the original object) and ob.methods (methods being
// added, whether entirely new or overriding).
// We're creating a vtable for an anonymous object that extends an
// existing one.
// inner_obj_ty is the type of the inner object being forwarded to,
// and "ob" is the wrapper object. We need to take apart
// inner_obj_ty, which is the type of the object being forwarded to
// (it had better have an object type with methods!) and put those
// original methods onto the list of methods we need forwarding
// methods for.
// The vtable needs to contain 'forwarding slots' for any methods that
// were on the inner object and are not being overridden by the outer
// one. To find the set of methods that we need forwarding slots for,
// we take the set difference of { methods on the original object }
// and { methods being added, whether entirely new or overriding }.
let meths: [vtbl_mthd] = ~[];
// Gather up methods on the original object in 'meths'.
// Gather up methods on the inner object.
alt ty::struct(cx.ccx.tcx, inner_obj_ty) {
ty::ty_obj(inner_obj_methods) {
for m: ty::method in inner_obj_methods {
@ -520,8 +509,8 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
}
}
// Now, filter out any methods that we don't need forwarding slots
// for, because they're being overridden.
// Filter out any methods that we don't need forwarding slots for
// because they're being overridden.
let f = bind filtering_fn(cx, _, ob.methods);
meths = std::ivec::filter_map[vtbl_mthd, vtbl_mthd](f, meths);
@ -534,6 +523,8 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
std::sort::ivector::merge_sort[vtbl_mthd]
(bind vtbl_mthd_lteq(_, _), meths);
// To create forwarding methods, we'll need a "backwarding" vtbl. See
// create_backwarding_vtbl and process_bkwding_method for details.
let backwarding_vtbl: ValueRef =
create_backwarding_vtbl(cx, sp, inner_obj_ty, outer_obj_ty);
@ -554,17 +545,12 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
}
}
let vtbl = C_struct(llmethods);
let vtbl_name = mangle_internal_name_by_path(cx.ccx, cx.path + ~["vtbl"]);
let gvar =
llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl), str::buf(vtbl_name));
llvm::LLVMSetInitializer(gvar, vtbl);
llvm::LLVMSetGlobalConstant(gvar, True);
llvm::LLVMSetLinkage(gvar,
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
ret gvar;
ret finish_vtbl(cx, llmethods, "vtbl");
}
// create_backwarding_vtbl: Create a vtable for the inner object of an
// anonymous object, so that any self-calls made from the inner object's
// methods get redirected appropriately.
fn create_backwarding_vtbl(cx: @local_ctxt, sp: &span, inner_obj_ty: ty::t,
outer_obj_ty: ty::t) -> ValueRef {
@ -591,28 +577,30 @@ fn create_backwarding_vtbl(cx: @local_ctxt, sp: &span, inner_obj_ty: ty::t,
// Methods should have already been sorted, so no need to do so again.
for m: ty::method in meths {
// We pass outer_obj_ty to process_fwding_mthd() because it's
// the one being forwarded to.
// We pass outer_obj_ty to process_fwding_mthd() because it's the one
// being forwarded to.
llmethods += ~[process_bkwding_mthd(
cx, sp, @m, ~[], outer_obj_ty, ~[])];
}
ret finish_vtbl(cx, llmethods, "backwarding_vtbl");
}
// finish_vtbl: Given a vector of vtable entries, create the table in
// read-only memory and return a pointer to it.
fn finish_vtbl(cx: @local_ctxt, llmethods: [ValueRef], name: str)
-> ValueRef {
let vtbl = C_struct(llmethods);
let vtbl_name =
mangle_internal_name_by_path(cx.ccx,
cx.path + ~["backwarding_vtbl"]);
let vtbl_name = mangle_internal_name_by_path(cx.ccx, cx.path + ~[name]);
let gvar =
llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl), str::buf(vtbl_name));
llvm::LLVMSetInitializer(gvar, vtbl);
llvm::LLVMSetGlobalConstant(gvar, True);
llvm::LLVMSetLinkage(gvar,
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
ret gvar;
}
// process_bkwding_mthd: Create the backwarding function that appears in a
// backwarding vtable slot.
//
@ -653,9 +641,9 @@ fn process_bkwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
let bcx = new_top_block_ctxt(fcx);
let lltop = bcx.llbb;
// The self-object will arrive in the backwarding function via the llenv
// argument, but we need to jump past the first item in the self-stack to
// get to the one we really want.
// The self-object will arrive in the backwarding function via the
// llenv argument, but we need to jump past the first item in the
// self-stack to get to the one we really want.
// Cast to self-stack's type.
let llenv = bcx.build.PointerCast(
@ -717,8 +705,8 @@ fn process_bkwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
bcx.build.PointerCast(llouter_mthd, T_ptr(T_ptr(llouter_mthd_ty)));
llouter_mthd = bcx.build.Load(llouter_mthd);
// Set up the three implicit arguments to the outer method we'll need
// to call.
// Set up the three implicit arguments to the outer method we'll need to
// call.
let self_arg = llself_obj_ptr;
let llouter_mthd_args: [ValueRef] = ~[llretptr, fcx.lltaskptr, self_arg];
@ -831,8 +819,7 @@ fn process_fwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
// Placeholder for non-existent typarams, since anon objs don't have them.
let typarams_ty: ty::t = ty::mk_imm_tup(cx.ccx.tcx, ~[]);
// Tuple type for body:
// [tydesc, [typaram, ...], [field, ...], inner_obj]
// Tuple type for body: [tydesc, [typaram, ...], [field, ...], inner_obj]
let body_ty: ty::t =
ty::mk_imm_tup(cx.ccx.tcx,
@ -951,9 +938,9 @@ fn process_normal_mthd(cx: @local_ctxt, m: @ast::method, self_ty: ty::t,
let s: str = mangle_internal_name_by_path(mcx.ccx, mcx.path);
let llfn: ValueRef = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty);
// Every method on an object gets its node_id inserted into the
// crate-wide item_ids map, together with the ValueRef that points to
// where that method's definition will be in the executable.
// Every method on an object gets its node_id inserted into the crate-wide
// item_ids map, together with the ValueRef that points to where that
// method's definition will be in the executable.
cx.ccx.item_ids.insert(m.node.id, llfn);
cx.ccx.item_symbols.insert(m.node.id, s);
trans_fn(mcx, m.span, m.node.meth, llfn, some(self_ty), ty_params,
@ -999,3 +986,13 @@ fn populate_self_stack(bcx: @block_ctxt,
ret self_stack;
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//