@@ -415,28 +415,31 @@ fn llalign_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
415
415
}
416
416
417
417
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)
419
420
}
420
421
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)
432
425
}
433
426
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 {
435
434
let ccx = bcx_ccx ( cx) ;
436
435
if check type_has_static_size ( ccx, t) {
437
436
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
+ }
440
443
}
441
444
442
445
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)
542
545
}
543
546
}
544
547
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 {
548
560
//
549
561
// C padding rules:
550
562
//
@@ -553,49 +565,44 @@ fn dynamic_size_of(cx: @block_ctxt, t: ty::t, mode: align_mode) -> result {
553
565
// - Pad after final structure member so that whole structure
554
566
// is aligned to max alignment of interior.
555
567
//
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 ) ;
560
571
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) ;
562
574
bcx = elt_align. bcx ;
563
- let elt_size = size_of ( bcx, e) ;
575
+ let elt_size = size_of ( bcx, e, opt_ev ) ;
564
576
bcx = elt_size. bcx ;
565
577
let aligned_off = align_to ( bcx, off, elt_align. val ) ;
566
578
off = Add ( bcx, aligned_off, elt_size. val ) ;
567
579
max_align = umax ( bcx, max_align, elt_align. val ) ;
568
580
}
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 } ;
579
582
}
580
- alt ty:: struct ( bcx_tcx ( cx) , t) {
583
+
584
+ alt ty:: struct ( bcx_tcx ( bcx) , t) {
581
585
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) } ;
584
591
}
585
592
ty:: ty_rec ( flds) {
586
593
let tys: [ ty:: t ] = [ ] ;
587
594
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 ) ;
589
596
}
590
597
ty:: ty_tup ( elts) {
591
598
let tys = [ ] ;
592
599
for tp in elts { tys += [ tp] ; }
593
- ret align_elements ( cx , tys, mode ) ;
600
+ ret compute_elements_metrics ( bcx , tys, opt_v ) ;
594
601
}
595
602
ty:: ty_tag ( tid, tps) {
596
- let bcx = cx ;
603
+ let bcx = bcx ;
597
604
let ccx = bcx_ccx ( bcx) ;
598
- // Compute max(variant sizes).
605
+ // Compute max(variant sizes) and max(variant alignments) .
599
606
600
607
let max_size: ValueRef = alloca ( bcx, ccx. int_type ) ;
601
608
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 {
606
613
let raw_tys: [ ty:: t ] = variant. args ;
607
614
let tys: [ ty:: t ] = [ ] ;
608
615
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) ;
610
617
tys += [ t] ;
611
618
}
612
- let rslt = align_elements ( bcx, tys, mode ) ;
619
+ let rslt = align_elements ( bcx, tys, opt_v ) ;
613
620
bcx = rslt. bcx ;
614
621
let this_size = rslt. val ;
615
622
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 {
620
627
if vec:: len ( * variants) != 1 u {
621
628
Add ( bcx, max_size_val, llsize_of ( ccx, ccx. int_type ) )
622
629
} 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 } ;
624
655
}
625
656
}
626
657
}
627
658
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] ) ;
660
665
}
661
666
662
667
// Increment a pointer by a given amount and then cast it to be a pointer
663
668
// to a given type.
664
669
fn bump_ptr ( bcx : @block_ctxt , t : ty:: t , base : ValueRef , sz : ValueRef ) ->
665
670
ValueRef {
666
- let raw = PointerCast ( bcx, base, T_ptr ( T_i8 ( ) ) ) ;
667
- let bumped = GEP ( bcx, raw, [ sz] ) ;
668
671
let ccx = bcx_ccx ( bcx) ;
672
+ let bumped = ptr_offs ( bcx, base, sz) ;
669
673
if check type_has_static_size ( ccx, t) {
670
674
let sp = bcx. sp ;
671
675
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])
686
690
// ty::struct and knows what to do when it runs into a ty_param stuck in the
687
691
// middle of the thing it's GEP'ing into. Much like size_of and align_of,
688
692
// 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 {
691
695
// 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) ) ;
694
698
}
695
699
// It is a dynamic-containing type that, if we convert directly to an LLVM
696
700
// 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])
751
755
// the tuple parens are associative so it doesn't matter that we've
752
756
// flattened the incoming structure.
753
757
754
- let s = split_type ( bcx_ccx ( cx ) , t, ixs, 0 u) ;
758
+ let s = split_type ( bcx_ccx ( bcx ) , t, ixs, 0 u) ;
755
759
756
760
let args = [ ] ;
757
761
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) ) ;
763
767
}
764
768
765
769
0 commit comments