Skip to content

Commit 4f52e5a

Browse files
committed
make size_of and align_of take an optional value
1 parent 2074e06 commit 4f52e5a

File tree

4 files changed

+135
-101
lines changed

4 files changed

+135
-101
lines changed

src/comp/middle/trans.rs

Lines changed: 92 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -415,28 +415,31 @@ fn llalign_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
415415
}
416416

417417
fn size_of(cx: @block_ctxt, t: ty::t) -> result {
418-
size_of_(cx, t, align_total)
418+
let {bcx, sz, align} = metrics(cx, t, none);
419+
rslt(bcx, align)
419420
}
420421

421-
tag align_mode {
422-
align_total;
423-
align_next(ty::t);
424-
}
425-
426-
fn size_of_(cx: @block_ctxt, t: ty::t, mode: align_mode) -> result {
427-
let ccx = bcx_ccx(cx);
428-
if check type_has_static_size(ccx, t) {
429-
let sp = cx.sp;
430-
rslt(cx, llsize_of(bcx_ccx(cx), type_of(ccx, sp, t)))
431-
} else { dynamic_size_of(cx, t, mode) }
422+
fn align_of(cx: @block_ctxt, t: ty::t) -> result {
423+
let {bcx, sz, align} = metrics(cx, t, none);
424+
rslt(bcx, align)
432425
}
433426

434-
fn align_of(cx: @block_ctxt, t: ty::t) -> result {
427+
// Computes the size/alignment of the type `t`. `opt_v`, if provided, should
428+
// be a pointer to the instance of type `t` whose size/alignment are being
429+
// computed. For most types, `opt_v` is not needed, because all instances
430+
// have the same size/alignment. However, for opaque types like closures, the
431+
// instance is required.
432+
fn metrics(bcx: @block_ctxt, t: ty::t, opt_v: option<ValueRef>)
433+
-> metrics_result {
435434
let ccx = bcx_ccx(cx);
436435
if check type_has_static_size(ccx, t) {
437436
let sp = cx.sp;
438-
rslt(cx, llalign_of(bcx_ccx(cx), type_of(ccx, sp, t)))
439-
} else { dynamic_align_of(cx, t) }
437+
let sz = llsize_of(bcx_ccx(cx), type_of(ccx, sp, t));
438+
let align = llalign_of(bcx_ccx(cx), type_of(ccx, sp, t));
439+
ret {bcx: bcx, sz: sz, align: align};
440+
} else {
441+
ret dynamic_metrics(bcx, t, opt_v);
442+
}
440443
}
441444

442445
fn alloca(cx: @block_ctxt, t: TypeRef) -> ValueRef {
@@ -542,9 +545,18 @@ fn static_size_of_tag(cx: @crate_ctxt, sp: span, t: ty::t)
542545
}
543546
}
544547

545-
fn dynamic_size_of(cx: @block_ctxt, t: ty::t, mode: align_mode) -> result {
546-
fn align_elements(cx: @block_ctxt, elts: [ty::t],
547-
mode: align_mode) -> result {
548+
type metrics_result = {
549+
bcx: @block_ctxt,
550+
sz: ValueRef,
551+
align: ValueRef
552+
};
553+
554+
fn dynamic_metrics(bcx: @block_ctxt,
555+
elts: [ty::t],
556+
opts_v: option<ValueRef>) -> metrics_result {
557+
fn compute_elements_metrics(bcx: @block_ctxt,
558+
elts: [ty::t],
559+
opt_v: option<ValueRef>) -> metrics_result {
548560
//
549561
// C padding rules:
550562
//
@@ -553,49 +565,44 @@ fn dynamic_size_of(cx: @block_ctxt, t: ty::t, mode: align_mode) -> result {
553565
// - Pad after final structure member so that whole structure
554566
// is aligned to max alignment of interior.
555567
//
556-
557-
let off = C_int(bcx_ccx(cx), 0);
558-
let max_align = C_int(bcx_ccx(cx), 1);
559-
let bcx = cx;
568+
let bcx = bcx;
569+
let off = C_int(bcx_ccx(bcx), 0);
570+
let max_align = C_int(bcx_ccx(bcx), 1);
560571
for e: ty::t in elts {
561-
let elt_align = align_of(bcx, e);
572+
let opt_ev = option::map(opt_v) {|v| ptr_offs(bcx, v, off) };
573+
let elt_align = align_of(bcx, e, opt_ev);
562574
bcx = elt_align.bcx;
563-
let elt_size = size_of(bcx, e);
575+
let elt_size = size_of(bcx, e, opt_ev);
564576
bcx = elt_size.bcx;
565577
let aligned_off = align_to(bcx, off, elt_align.val);
566578
off = Add(bcx, aligned_off, elt_size.val);
567579
max_align = umax(bcx, max_align, elt_align.val);
568580
}
569-
off = alt mode {
570-
align_total. {
571-
align_to(bcx, off, max_align)
572-
}
573-
align_next(t) {
574-
let {bcx, val: align} = align_of(bcx, t);
575-
align_to(bcx, off, align)
576-
}
577-
};
578-
ret rslt(bcx, off);
581+
ret { bcx: bcx, sz: off, align: max_align };
579582
}
580-
alt ty::struct(bcx_tcx(cx), t) {
583+
584+
alt ty::struct(bcx_tcx(bcx), t) {
581585
ty::ty_param(p, _) {
582-
let szptr = field_of_tydesc(cx, t, false, abi::tydesc_field_size);
583-
ret rslt(szptr.bcx, Load(szptr.bcx, szptr.val));
586+
let {bcx, value: szptr} =
587+
field_of_tydesc(bcx, t, false, abi::tydesc_field_size);
588+
let {bcx, value: aptr} =
589+
field_of_tydesc(bcx, t, false, abi::tydesc_field_align);
590+
ret { bcx: bcx, sz: Load(szptr), align: Load(align) };
584591
}
585592
ty::ty_rec(flds) {
586593
let tys: [ty::t] = [];
587594
for f: ty::field in flds { tys += [f.mt.ty]; }
588-
ret align_elements(cx, tys, mode);
595+
ret compute_elements_metrics(bcx, tys, opt_v);
589596
}
590597
ty::ty_tup(elts) {
591598
let tys = [];
592599
for tp in elts { tys += [tp]; }
593-
ret align_elements(cx, tys, mode);
600+
ret compute_elements_metrics(bcx, tys, opt_v);
594601
}
595602
ty::ty_tag(tid, tps) {
596-
let bcx = cx;
603+
let bcx = bcx;
597604
let ccx = bcx_ccx(bcx);
598-
// Compute max(variant sizes).
605+
// Compute max(variant sizes) and max(variant alignments).
599606

600607
let max_size: ValueRef = alloca(bcx, ccx.int_type);
601608
Store(bcx, C_int(ccx, 0), max_size);
@@ -606,10 +613,10 @@ fn dynamic_size_of(cx: @block_ctxt, t: ty::t, mode: align_mode) -> result {
606613
let raw_tys: [ty::t] = variant.args;
607614
let tys: [ty::t] = [];
608615
for raw_ty: ty::t in raw_tys {
609-
let t = ty::substitute_type_params(bcx_tcx(cx), tps, raw_ty);
616+
let t = ty::substitute_type_params(bcx_tcx(bcx), tps, raw_ty);
610617
tys += [t];
611618
}
612-
let rslt = align_elements(bcx, tys, mode);
619+
let rslt = align_elements(bcx, tys, opt_v);
613620
bcx = rslt.bcx;
614621
let this_size = rslt.val;
615622
let old_max_size = Load(bcx, max_size);
@@ -620,52 +627,49 @@ fn dynamic_size_of(cx: @block_ctxt, t: ty::t, mode: align_mode) -> result {
620627
if vec::len(*variants) != 1u {
621628
Add(bcx, max_size_val, llsize_of(ccx, ccx.int_type))
622629
} else { max_size_val };
623-
ret rslt(bcx, total_size);
630+
let total_align = C_int(bcx_ccx(bcx), 1); // FIXME: stub
631+
ret {bcx: bcx, sz: total_size, align: total_align};
632+
}
633+
ty::ty_opaque_closure. {
634+
// Unlike most other types, the type of an opaque closure does not
635+
// fully specify its size. This is because the opaque closure type
636+
// only says that this is a closure over some data, but doesn't say
637+
// how much data there is (hence the word opaque). This is an
638+
// unavoidable consequence of the way that closures encapsulate the
639+
// closed over data. Therefore the only way to know the
640+
// size/alignment of a particular opaque closure instance is to load
641+
// the type descriptor from the instance and consult its
642+
// size/alignment fields. Note that it is meaningless to say "what is
643+
// the size of the type opaque closure?" One can only ask "what is the
644+
// size of this particular opaque closure?"
645+
let v = alt opt_v {
646+
none. { fail "Require value to compute metrics of opaque closures"; }
647+
some(v) { v }
648+
};
649+
let v = PointerCast(bcx, v, T_ptr(T_opaque_closure(bcx_ccx(bcx))));
650+
let tdptrptr = GEPi(bcx, v, [0, abi::closure_elt_tydesc]);
651+
let tdptr = Load(bcx, tdptrptr);
652+
let sz = Load(bcx, GEPi(bcx, tdptr, [0, abi::tydesc_field_size]));
653+
let align = Load(bcx, GEPi(bcx, tdptr, [0, abi::tydesc_field_align]));
654+
ret { bcx: bcx, sz: sz, align: sz };
624655
}
625656
}
626657
}
627658

628-
fn dynamic_align_of(cx: @block_ctxt, t: ty::t) -> result {
629-
// FIXME: Typestate constraint that shows this alt is
630-
// exhaustive
631-
alt ty::struct(bcx_tcx(cx), t) {
632-
ty::ty_param(p, _) {
633-
let aptr = field_of_tydesc(cx, t, false, abi::tydesc_field_align);
634-
ret rslt(aptr.bcx, Load(aptr.bcx, aptr.val));
635-
}
636-
ty::ty_rec(flds) {
637-
let a = C_int(bcx_ccx(cx), 1);
638-
let bcx = cx;
639-
for f: ty::field in flds {
640-
let align = align_of(bcx, f.mt.ty);
641-
bcx = align.bcx;
642-
a = umax(bcx, a, align.val);
643-
}
644-
ret rslt(bcx, a);
645-
}
646-
ty::ty_tag(_, _) {
647-
ret rslt(cx, C_int(bcx_ccx(cx), 1)); // FIXME: stub
648-
}
649-
ty::ty_tup(elts) {
650-
let a = C_int(bcx_ccx(cx), 1);
651-
let bcx = cx;
652-
for e in elts {
653-
let align = align_of(bcx, e);
654-
bcx = align.bcx;
655-
a = umax(bcx, a, align.val);
656-
}
657-
ret rslt(bcx, a);
658-
}
659-
}
659+
// Given a pointer p, returns a pointer sz(p) (i.e., inc'd by sz bytes).
660+
// The type of the returned pointer is always i8*. If you care about the
661+
// return type, use bump_ptr().
662+
fn ptr_offs(bcx: @block_ctxt, base: ValueRef, sz: ValueRef) -> ValueRef {
663+
let raw = PointerCast(bcx, base, T_ptr(T_i8()));
664+
GEP(bcx, raw, [sz]);
660665
}
661666

662667
// Increment a pointer by a given amount and then cast it to be a pointer
663668
// to a given type.
664669
fn bump_ptr(bcx: @block_ctxt, t: ty::t, base: ValueRef, sz: ValueRef) ->
665670
ValueRef {
666-
let raw = PointerCast(bcx, base, T_ptr(T_i8()));
667-
let bumped = GEP(bcx, raw, [sz]);
668671
let ccx = bcx_ccx(bcx);
672+
let bumped = ptr_offs(bcx, base, sz);
669673
if check type_has_static_size(ccx, t) {
670674
let sp = bcx.sp;
671675
let typ = T_ptr(type_of(ccx, sp, t));
@@ -686,11 +690,11 @@ fn GEP_tup_like_1(cx: @block_ctxt, t: ty::t, base: ValueRef, ixs: [int])
686690
// ty::struct and knows what to do when it runs into a ty_param stuck in the
687691
// middle of the thing it's GEP'ing into. Much like size_of and align_of,
688692
// above.
689-
fn GEP_tup_like(cx: @block_ctxt, t: ty::t, base: ValueRef, ixs: [int])
690-
: type_is_tup_like(cx, t) -> result {
693+
fn GEP_tup_like(bcx: @block_ctxt, t: ty::t, base: ValueRef, ixs: [int])
694+
: type_is_tup_like(bcx, t) -> result {
691695
// It might be a static-known type. Handle this.
692-
if !ty::type_has_dynamic_size(bcx_tcx(cx), t) {
693-
ret rslt(cx, GEPi(cx, base, ixs));
696+
if !ty::type_has_dynamic_size(bcx_tcx(bcx), t) {
697+
ret rslt(bcx, GEPi(bcx, base, ixs));
694698
}
695699
// It is a dynamic-containing type that, if we convert directly to an LLVM
696700
// TypeRef, will be all wrong; there's no proper LLVM type to represent
@@ -751,15 +755,15 @@ fn GEP_tup_like(cx: @block_ctxt, t: ty::t, base: ValueRef, ixs: [int])
751755
// the tuple parens are associative so it doesn't matter that we've
752756
// flattened the incoming structure.
753757

754-
let s = split_type(bcx_ccx(cx), t, ixs, 0u);
758+
let s = split_type(bcx_ccx(bcx), t, ixs, 0u);
755759

756760
let args = [];
757761
for typ: ty::t in s.prefix { args += [typ]; }
758-
let prefix_ty = ty::mk_tup(bcx_tcx(cx), args);
759-
760-
let bcx = cx;
761-
let sz = size_of_(bcx, prefix_ty, align_next(s.target));
762-
ret rslt(sz.bcx, bump_ptr(sz.bcx, s.target, base, sz.val));
762+
let prefix_ty = ty::mk_tup(bcx_tcx(bcx), args);
763+
let {bcx, val: prefix_sz} = size_of(bcx, prefix_ty);
764+
let {bcx, val: align} = align_of(bcx, s.target);
765+
let sz = align_to(bcx, prefix_sz, align);
766+
ret rslt(bcx, bump_ptr(bcx, s.target, base, sz));
763767
}
764768

765769

src/comp/middle/trans_uniq.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,17 @@ fn trans_uniq(bcx: @block_ctxt, contents: @ast::expr,
3535

3636
fn alloc_uniq(cx: @block_ctxt, uniq_ty: ty::t)
3737
: type_is_unique_box(cx, uniq_ty) -> result {
38+
ret alloc_uniq_(cx, uniq_ty, none);
39+
}
3840

39-
let bcx = cx;
41+
fn alloc_uniq_(bcx: @block_ctxt, uniq_ty: ty::t, opt_v: option<ValueRef>)
42+
: type_is_unique_box(cx, uniq_ty) -> result {
4043
let contents_ty = content_ty(bcx, uniq_ty);
41-
let r = size_of(bcx, contents_ty);
42-
bcx = r.bcx;
43-
let llsz = r.val;
44-
44+
let {bcx, sz: llsz, align: _} = metrics(bcx, contents_ty, opt_v);
4545
let ccx = bcx_ccx(bcx);
4646
check non_ty_var(ccx, contents_ty);
4747
let llptrty = T_ptr(type_of_inner(ccx, bcx.sp, contents_ty));
48-
49-
r = trans_shared_malloc(bcx, llptrty, llsz);
50-
bcx = r.bcx;
51-
let llptr = r.val;
52-
53-
ret rslt(bcx, llptr);
48+
ret trans_shared_malloc(bcx, llptrty, llsz);
5449
}
5550

5651
fn make_free_glue(cx: @block_ctxt, vptr: ValueRef, t: ty::t)
@@ -88,7 +83,7 @@ fn duplicate(bcx: @block_ctxt, v: ValueRef, t: ty::t)
8883
: type_is_unique_box(bcx, t) -> result {
8984

9085
let content_ty = content_ty(bcx, t);
91-
let {bcx, val: llptr} = alloc_uniq(bcx, t);
86+
let {bcx, val: llptr} = alloc_uniq_(bcx, t, v);
9287

9388
let src = load_if_immediate(bcx, v, content_ty);
9489
let dst = llptr;

src/comp/middle/ty.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,10 @@ pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool unchecked {
11511151
that the type context tracks about types should be immutable.)
11521152
*/
11531153
type_structurally_contains(cx, ty, fn (sty: sty) -> bool {
1154-
alt sty { ty_param(_, _) { true } _ { false }}
1154+
alt sty {
1155+
ty_opaque_closure. | ty_param(_, _) { true }
1156+
_ { false }
1157+
}
11551158
})
11561159
}
11571160

src/test/run-pass/sendfn-deep-copy.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use std;
2+
3+
import std::comm;
4+
import std::comm::chan;
5+
import std::comm::send;
6+
7+
fn main() { test05(); }
8+
9+
fn mk_counter<copy A>() -> sendfn(A) -> (A,uint) {
10+
// The only reason that the counter is generic is so that it closes
11+
// over both a type descriptor and some data.
12+
let v = [mutable 0u];
13+
ret sendfn(a: A) -> (A,uint) {
14+
let n = v[0];
15+
v[0] = n + 1u;
16+
(a, n)
17+
};
18+
}
19+
20+
fn test05() {
21+
let fp0 = mk_counter::<float>();
22+
23+
assert (5.3f, 0u) == fp0(5.3f);
24+
assert (5.5f, 1u) == fp0(5.5f);
25+
26+
let fp1 = copy fp0;
27+
28+
assert (5.3f, 2u) == fp0(5.3f);
29+
assert (5.3f, 2u) == fp1(5.3f);
30+
assert (5.5f, 3u) == fp0(5.5f);
31+
assert (5.5f, 3u) == fp1(5.5f);
32+
}

0 commit comments

Comments
 (0)