Skip to content

Commit 8d8c25b

Browse files
committed
auto merge of #4980 : pcwalton/rust/sizing-type-of, r=pcwalton
...locking-servo `simplify_type` was bogus, as there was no way for it to handle enums properly. It was also slow, because it created many Rust types at runtime. In general creating Rust types during trans is a source of slowness, and I'd like to avoid doing it as much as possible. (It is probably not possible to eliminate it entirely, due to `subst`, but we should get rid of as much of it as we can.) So this patch replaces `simplify_type` with `sizing_type_of`, which creates a size-equivalent LLVM type directly without going through a Rust type first. Because this is causing an ICE in Servo, I'm rubber stamping it.
2 parents 65aa259 + 548c098 commit 8d8c25b

File tree

4 files changed

+139
-87
lines changed

4 files changed

+139
-87
lines changed

src/librustc/middle/trans/base.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3030,6 +3030,7 @@ pub fn trans_crate(sess: session::Session,
30303030
const_values: HashMap(),
30313031
module_data: HashMap(),
30323032
lltypes: ty::new_ty_hash(),
3033+
llsizingtypes: ty::new_ty_hash(),
30333034
names: new_namegen(sess.parse_sess.interner),
30343035
next_addrspace: new_addrspace_gen(),
30353036
symbol_hasher: symbol_hasher,

src/librustc/middle/trans/common.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ pub struct crate_ctxt {
202202
const_values: HashMap<ast::node_id, ValueRef>,
203203
module_data: HashMap<~str, ValueRef>,
204204
lltypes: HashMap<ty::t, TypeRef>,
205+
llsizingtypes: HashMap<ty::t, TypeRef>,
205206
names: namegen,
206207
next_addrspace: addrspace_gen,
207208
symbol_hasher: @hash::State,

src/librustc/middle/trans/machine.rs

Lines changed: 33 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -13,60 +13,8 @@
1313

1414
use middle::trans::common::*;
1515
use middle::trans::type_of;
16-
use middle::ty::field;
1716
use middle::ty;
18-
19-
use syntax::parse::token::special_idents;
20-
21-
// Creates a simpler, size-equivalent type. The resulting type is guaranteed
22-
// to have (a) the same size as the type that was passed in; (b) to be non-
23-
// recursive. This is done by replacing all boxes in a type with boxed unit
24-
// types.
25-
// This should reduce all pointers to some simple pointer type, to
26-
// ensure that we don't recurse endlessly when computing the size of a
27-
// nominal type that has pointers to itself in it.
28-
pub fn simplify_type(tcx: ty::ctxt, typ: ty::t) -> ty::t {
29-
fn nilptr(tcx: ty::ctxt) -> ty::t {
30-
ty::mk_ptr(tcx, ty::mt {ty: ty::mk_nil(tcx), mutbl: ast::m_imm})
31-
}
32-
fn simplifier(tcx: ty::ctxt, typ: ty::t) -> ty::t {
33-
match ty::get(typ).sty {
34-
ty::ty_box(_) | ty::ty_opaque_box | ty::ty_uniq(_) |
35-
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_evec(_, ty::vstore_box) |
36-
ty::ty_estr(ty::vstore_uniq) | ty::ty_estr(ty::vstore_box) |
37-
ty::ty_ptr(_) | ty::ty_rptr(*) => nilptr(tcx),
38-
39-
ty::ty_bare_fn(*) | // FIXME(#4804) Bare fn repr
40-
ty::ty_closure(*) => ty::mk_tup(tcx, ~[nilptr(tcx), nilptr(tcx)]),
41-
42-
ty::ty_evec(_, ty::vstore_slice(_)) |
43-
ty::ty_estr(ty::vstore_slice(_)) => {
44-
ty::mk_tup(tcx, ~[nilptr(tcx), ty::mk_int(tcx)])
45-
}
46-
// Reduce a class type to a record type in which all the fields are
47-
// simplified
48-
ty::ty_struct(did, ref substs) => {
49-
let simpl_fields = (if ty::ty_dtor(tcx, did).is_present() {
50-
// remember the drop flag
51-
~[field {
52-
ident: special_idents::dtor,
53-
mt: ty::mt {ty: ty::mk_u8(tcx), mutbl: ast::m_mutbl}
54-
}] }
55-
else { ~[] }) +
56-
do ty::lookup_struct_fields(tcx, did).map |f| {
57-
let t = ty::lookup_field_type(tcx, did, f.id, substs);
58-
field {
59-
ident: f.ident,
60-
mt: ty::mt {ty: simplify_type(tcx, t), mutbl: ast::m_const
61-
}}
62-
};
63-
ty::mk_rec(tcx, simpl_fields)
64-
}
65-
_ => typ
66-
}
67-
}
68-
ty::fold_ty(tcx, typ, |t| simplifier(tcx, t))
69-
}
17+
use util::ppaux::ty_to_str;
7018

7119
// ______________________________________________________________________
7220
// compute sizeof / alignof
@@ -180,27 +128,40 @@ pub fn llalign_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
180128

181129
// Computes the size of the data part of an enum.
182130
pub fn static_size_of_enum(cx: @crate_ctxt, t: ty::t) -> uint {
183-
if cx.enum_sizes.contains_key(&t) { return cx.enum_sizes.get(&t); }
131+
if cx.enum_sizes.contains_key(&t) {
132+
return cx.enum_sizes.get(&t);
133+
}
134+
135+
debug!("static_size_of_enum %s", ty_to_str(cx.tcx, t));
136+
184137
match ty::get(t).sty {
185-
ty::ty_enum(tid, ref substs) => {
186-
// Compute max(variant sizes).
187-
let mut max_size = 0u;
188-
let variants = ty::enum_variants(cx.tcx, tid);
189-
for vec::each(*variants) |variant| {
190-
let tup_ty = simplify_type(
191-
cx.tcx,
192-
ty::mk_tup(cx.tcx, /*bad*/copy variant.args));
193-
// Perform any type parameter substitutions.
194-
let tup_ty = ty::subst(cx.tcx, substs, tup_ty);
195-
// Here we possibly do a recursive call.
196-
let this_size =
197-
llsize_of_real(cx, type_of::type_of(cx, tup_ty));
198-
if max_size < this_size { max_size = this_size; }
138+
ty::ty_enum(tid, ref substs) => {
139+
// Compute max(variant sizes).
140+
let mut max_size = 0;
141+
let variants = ty::enum_variants(cx.tcx, tid);
142+
for variants.each |variant| {
143+
if variant.args.len() == 0 {
144+
loop;
145+
}
146+
147+
let lltypes = variant.args.map(|&variant_arg| {
148+
let substituted = ty::subst(cx.tcx, substs, variant_arg);
149+
type_of::sizing_type_of(cx, substituted)
150+
});
151+
152+
debug!("static_size_of_enum: variant %s type %s",
153+
cx.tcx.sess.str_of(variant.name),
154+
ty_str(cx.tn, T_struct(lltypes)));
155+
156+
let this_size = llsize_of_real(cx, T_struct(lltypes));
157+
if max_size < this_size {
158+
max_size = this_size;
159+
}
160+
}
161+
cx.enum_sizes.insert(t, max_size);
162+
return max_size;
199163
}
200-
cx.enum_sizes.insert(t, max_size);
201-
return max_size;
202-
}
203-
_ => cx.sess.bug(~"static_size_of_enum called on non-enum")
164+
_ => cx.sess.bug(~"static_size_of_enum called on non-enum")
204165
}
205166
}
206167

src/librustc/middle/trans/type_of.rs

Lines changed: 104 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,95 @@ pub fn type_of_non_gc_box(cx: @crate_ctxt, t: ty::t) -> TypeRef {
8989
}
9090
}
9191

92+
// A "sizing type" is an LLVM type, the size and alignment of which are
93+
// guaranteed to be equivalent to what you would get out of `type_of()`. It's
94+
// useful because:
95+
//
96+
// (1) It may be cheaper to compute the sizing type than the full type if all
97+
// you're interested in is the size and/or alignment;
98+
//
99+
// (2) It won't make any recursive calls to determine the structure of the
100+
// type behind pointers. This can help prevent infinite loops for
101+
// recursive types. For example, `static_size_of_enum()` relies on this
102+
// behavior.
103+
104+
pub fn sizing_type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
105+
if cx.llsizingtypes.contains_key(&t) {
106+
return cx.llsizingtypes.get(&t);
107+
}
108+
109+
let llsizingty = match ty::get(t).sty {
110+
ty::ty_nil | ty::ty_bot => T_nil(),
111+
ty::ty_bool => T_bool(),
112+
ty::ty_int(t) => T_int_ty(cx, t),
113+
ty::ty_uint(t) => T_uint_ty(cx, t),
114+
ty::ty_float(t) => T_float_ty(cx, t),
115+
116+
ty::ty_estr(ty::vstore_uniq) |
117+
ty::ty_estr(ty::vstore_box) |
118+
ty::ty_evec(_, ty::vstore_uniq) |
119+
ty::ty_evec(_, ty::vstore_box) |
120+
ty::ty_box(*) |
121+
ty::ty_opaque_box |
122+
ty::ty_uniq(*) |
123+
ty::ty_ptr(*) |
124+
ty::ty_rptr(*) |
125+
ty::ty_type |
126+
ty::ty_opaque_closure_ptr(*) => T_ptr(T_i8()),
127+
128+
ty::ty_estr(ty::vstore_slice(*)) |
129+
ty::ty_evec(_, ty::vstore_slice(*)) => {
130+
T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())])
131+
}
132+
133+
// FIXME(#4804) Bare fn repr
134+
ty::ty_bare_fn(*) => T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())]),
135+
ty::ty_closure(*) => T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())]),
136+
ty::ty_trait(_, _, vstore) => T_opaque_trait(cx, vstore),
137+
138+
ty::ty_estr(ty::vstore_fixed(size)) => T_array(T_i8(), size),
139+
ty::ty_evec(mt, ty::vstore_fixed(size)) => {
140+
T_array(sizing_type_of(cx, mt.ty), size)
141+
}
142+
143+
ty::ty_unboxed_vec(mt) => T_vec(cx, sizing_type_of(cx, mt.ty)),
144+
145+
ty::ty_tup(ref elems) => {
146+
T_struct(elems.map(|&t| sizing_type_of(cx, t)))
147+
}
148+
149+
ty::ty_rec(ref fields) => {
150+
T_struct(fields.map(|f| sizing_type_of(cx, f.mt.ty)))
151+
}
152+
153+
ty::ty_struct(def_id, ref substs) => {
154+
let fields = ty::lookup_struct_fields(cx.tcx, def_id);
155+
let lltype = T_struct(fields.map(|field| {
156+
let field_type = ty::lookup_field_type(cx.tcx,
157+
def_id,
158+
field.id,
159+
substs);
160+
sizing_type_of(cx, field_type)
161+
}));
162+
if ty::ty_dtor(cx.tcx, def_id).is_present() {
163+
T_struct(~[lltype, T_i8()])
164+
} else {
165+
lltype
166+
}
167+
}
168+
169+
ty::ty_enum(def_id, _) => T_struct(enum_body_types(cx, def_id, t)),
170+
171+
ty::ty_self | ty::ty_infer(*) | ty::ty_param(*) | ty::ty_err(*) => {
172+
cx.tcx.sess.bug(~"fictitious type in sizing_type_of()")
173+
}
174+
};
175+
176+
cx.llsizingtypes.insert(t, llsizingty);
177+
llsizingty
178+
}
179+
180+
// NB: If you update this, be sure to update `sizing_type_of()` as well.
92181
pub fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
93182
debug!("type_of %?: %?", t, ty::get(t));
94183

@@ -236,23 +325,23 @@ pub fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
236325
return llty;
237326
}
238327

239-
pub fn fill_type_of_enum(cx: @crate_ctxt, did: ast::def_id, t: ty::t,
240-
llty: TypeRef) {
328+
pub fn enum_body_types(cx: @crate_ctxt, did: ast::def_id, t: ty::t)
329+
-> ~[TypeRef] {
330+
let univar = ty::enum_is_univariant(cx.tcx, did);
331+
let size = machine::static_size_of_enum(cx, t);
332+
if !univar {
333+
~[T_enum_discrim(cx), T_array(T_i8(), size)]
334+
} else {
335+
~[T_array(T_i8(), size)]
336+
}
337+
}
241338

339+
pub fn fill_type_of_enum(cx: @crate_ctxt,
340+
did: ast::def_id,
341+
t: ty::t,
342+
llty: TypeRef) {
242343
debug!("type_of_enum %?: %?", t, ty::get(t));
243-
244-
let lltys = {
245-
let univar = ty::enum_is_univariant(cx.tcx, did);
246-
let size = machine::static_size_of_enum(cx, t);
247-
if !univar {
248-
~[T_enum_discrim(cx), T_array(T_i8(), size)]
249-
}
250-
else {
251-
~[T_array(T_i8(), size)]
252-
}
253-
};
254-
255-
common::set_struct_body(llty, lltys);
344+
common::set_struct_body(llty, enum_body_types(cx, did, t));
256345
}
257346

258347
// Want refinements! (Or case classes, I guess

0 commit comments

Comments
 (0)