@@ -1327,7 +1327,8 @@ fn dynamic_size_of(&@block_ctxt cx, ty::t t) -> result {
1327
1327
auto bcx = rslt. bcx;
1328
1328
auto llunitszptr = rslt. val;
1329
1329
auto llunitsz = bcx. build. Load ( llunitszptr) ;
1330
- auto llsz = bcx. build. Add ( llsize_of( T_opaque_ivec ( ) ) , llunitsz) ;
1330
+ auto llsz = bcx. build. Add ( llsize_of( T_opaque_ivec ( ) ) ,
1331
+ bcx. build. Mul ( llunitsz, C_uint ( abi:: ivec_default_length) ) ) ;
1331
1332
ret res( bcx, llsz) ;
1332
1333
}
1333
1334
}
@@ -2969,9 +2970,21 @@ fn memmove_ty(&@block_ctxt cx, ValueRef dst, ValueRef src, &ty::t t) ->
2969
2970
} else { ret res( cx, cx. build. Store ( cx. build. Load ( src) , dst) ) ; }
2970
2971
}
2971
2972
2973
+ // Duplicates the heap-owned memory owned by a value of the given type.
2974
+ fn duplicate_heap_parts( & @block_ctxt cx, ValueRef vptr, ty:: t typ) -> result {
2975
+ alt ( ty:: struct ( cx. fcx. lcx. ccx. tcx, typ) ) {
2976
+ case ( ty:: ty_ivec( ?tm) ) {
2977
+ ret ivec:: duplicate_heap_part( cx, vptr, tm. ty) ;
2978
+ }
2979
+ case ( ty:: ty_str) {
2980
+ ret ivec:: duplicate_heap_part( cx, vptr,
2981
+ ty:: mk_mach( cx. fcx. lcx. ccx. tcx, common:: ty_u8) ) ;
2982
+ }
2983
+ }
2984
+ }
2985
+
2972
2986
tag copy_action { INIT ; DROP_EXISTING ; }
2973
2987
2974
- // FIXME: This should copy the contents of the heap part for ivecs.
2975
2988
fn copy_val( & @block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
2976
2989
& ty:: t t) -> result {
2977
2990
@@ -2991,7 +3004,11 @@ fn copy_val(&@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
2991
3004
ty:: type_has_dynamic_size( cx. fcx. lcx. ccx. tcx, t) ) {
2992
3005
auto r = take_ty( cx, src, t) ;
2993
3006
if ( action == DROP_EXISTING ) { r = drop_ty( r. bcx, dst, t) ; }
2994
- ret memmove_ty( r. bcx, dst, src, t) ;
3007
+ r = memmove_ty( r. bcx, dst, src, t) ;
3008
+ if ( ty:: type_owns_heap_mem( cx. fcx. lcx. ccx. tcx, t) ) {
3009
+ r = duplicate_heap_parts( cx, dst, t) ;
3010
+ }
3011
+ ret r;
2995
3012
}
2996
3013
cx. fcx. lcx. ccx. sess. bug( "unexpected type in trans:: copy_val: " +
2997
3014
ty_to_str( cx. fcx. lcx. ccx. tcx, t) ) ;
@@ -3501,8 +3518,8 @@ mod ivec {
3501
3518
copy_loop_body_cx. llbb,
3502
3519
next_cx. llbb) ;
3503
3520
auto copy_src_ptr = copy_loop_body_cx. build. Load ( src_ptr) ;
3504
- rslt =
3505
- copy_val ( copy_loop_body_cx , INIT , copy_dest_ptr , copy_src_ptr , t ) ;
3521
+ rslt = copy_val ( copy_loop_body_cx , INIT , copy_dest_ptr , copy_src_ptr ,
3522
+ unit_ty ) ;
3506
3523
auto post_copy_cx = rslt. bcx;
3507
3524
// Increment both pointers.
3508
3525
@@ -3740,6 +3757,66 @@ mod ivec {
3740
3757
3741
3758
ret res( next_cx, llvecptr) ;
3742
3759
}
3760
+
3761
+ // NB: This does *not* adjust reference counts. The caller must have done
3762
+ // this via take_ty() beforehand.
3763
+ fn duplicate_heap_part( & @block_ctxt cx, ValueRef orig_vptr,
3764
+ ty:: t unit_ty) -> result {
3765
+ // Cast to an opaque interior vector if we can't trust the pointer
3766
+ // type.
3767
+ auto vptr;
3768
+ if ( ty:: type_has_dynamic_size( cx. fcx. lcx. ccx. tcx, unit_ty) ) {
3769
+ vptr = cx. build. PointerCast ( orig_vptr, T_ptr ( T_opaque_ivec ( ) ) ) ;
3770
+ } else {
3771
+ vptr = orig_vptr;
3772
+ }
3773
+
3774
+ auto llunitty = type_of_or_i8( cx, unit_ty) ;
3775
+ auto llheappartty = T_ivec_heap_part ( llunitty) ;
3776
+
3777
+ // Check to see if the vector is heapified.
3778
+ auto stack_len_ptr = cx. build. InBoundsGEP ( vptr, [ C_int ( 0 ) ,
3779
+ C_uint ( abi:: ivec_elt_len) ] ) ;
3780
+ auto stack_len = cx. build. Load ( stack_len_ptr) ;
3781
+ auto stack_len_is_zero = cx. build. ICmp ( lib:: llvm:: LLVMIntEQ ,
3782
+ stack_len, C_int ( 0 ) ) ;
3783
+ auto maybe_on_heap_cx = new_sub_block_ctxt( cx, "maybe_on_heap") ;
3784
+ auto next_cx = new_sub_block_ctxt( cx, "next") ;
3785
+ cx. build. CondBr ( stack_len_is_zero, maybe_on_heap_cx. llbb,
3786
+ next_cx. llbb) ;
3787
+
3788
+ auto stub_ptr = maybe_on_heap_cx. build. PointerCast ( vptr,
3789
+ T_ptr ( T_ivec_heap ( llunitty) ) ) ;
3790
+ auto heap_ptr_ptr = maybe_on_heap_cx. build. InBoundsGEP ( stub_ptr,
3791
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_ptr) ] ) ;
3792
+ auto heap_ptr = maybe_on_heap_cx. build. Load ( heap_ptr_ptr) ;
3793
+ auto heap_ptr_is_nonnull = maybe_on_heap_cx. build. ICmp (
3794
+ lib:: llvm:: LLVMIntNE , heap_ptr, C_null ( T_ptr ( llheappartty) ) ) ;
3795
+ auto on_heap_cx = new_sub_block_ctxt( cx, "on_heap") ;
3796
+ maybe_on_heap_cx. build. CondBr ( heap_ptr_is_nonnull, on_heap_cx. llbb,
3797
+ next_cx. llbb) ;
3798
+
3799
+ // Ok, the vector is on the heap. Copy the heap part.
3800
+ auto alen_ptr = on_heap_cx. build. InBoundsGEP ( stub_ptr,
3801
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_alen) ] ) ;
3802
+ auto alen = on_heap_cx. build. Load ( alen_ptr) ;
3803
+
3804
+ auto heap_part_sz = on_heap_cx. build. Add ( alen,
3805
+ llsize_of( T_opaque_ivec_heap_part ( ) ) ) ;
3806
+ auto rslt = trans_raw_malloc( on_heap_cx, T_ptr ( llheappartty) ,
3807
+ heap_part_sz) ;
3808
+ on_heap_cx = rslt. bcx;
3809
+ auto new_heap_ptr = rslt. val;
3810
+
3811
+ rslt = call_memmove( on_heap_cx, new_heap_ptr, heap_ptr, heap_part_sz,
3812
+ C_int ( 4 ) ) ; // FIXME: align
3813
+ on_heap_cx = rslt. bcx;
3814
+
3815
+ on_heap_cx. build. Store ( new_heap_ptr, heap_ptr_ptr) ;
3816
+ on_heap_cx. build. Br ( next_cx. llbb) ;
3817
+
3818
+ ret res( next_cx, C_nil ( ) ) ;
3819
+ }
3743
3820
}
3744
3821
3745
3822
fn trans_vec_add( & @block_ctxt cx, & ty:: t t, ValueRef lhs, ValueRef rhs) ->
@@ -5431,6 +5508,8 @@ fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann) ->
5431
5508
auto unit_sz = ares. llunitsz;
5432
5509
auto llalen = ares. llalen;
5433
5510
5511
+ find_scope_cx( bcx) . cleanups += [ clean( bind drop_ty( _, llvecptr, typ) ) ] ;
5512
+
5434
5513
auto lllen = bcx. build. Mul ( C_uint ( vec:: len( args) ) , unit_sz) ;
5435
5514
// Allocate the vector pieces and store length and allocated length.
5436
5515
@@ -5459,15 +5538,17 @@ fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann) ->
5459
5538
auto llstubty = T_ivec_heap ( llunitty) ;
5460
5539
auto llstubptr = bcx. build. PointerCast ( llvecptr, T_ptr ( llstubty) ) ;
5461
5540
bcx. build. Store ( C_int ( 0 ) , bcx. build. InBoundsGEP ( llstubptr, stub_z) ) ;
5462
- bcx. build. Store ( lllen, bcx. build. InBoundsGEP ( llstubptr, stub_a) ) ;
5463
5541
auto llheapty = T_ivec_heap_part ( llunitty) ;
5464
5542
if ( vec:: len( args) == 0 u) {
5465
5543
// Null heap pointer indicates a zero-length vector.
5466
5544
5545
+ bcx. build. Store ( llalen, bcx. build. InBoundsGEP ( llstubptr, stub_a) ) ;
5467
5546
bcx. build. Store ( C_null ( T_ptr ( llheapty) ) ,
5468
5547
bcx. build. InBoundsGEP ( llstubptr, stub_p) ) ;
5469
5548
llfirsteltptr = C_null ( T_ptr ( llunitty) ) ;
5470
5549
} else {
5550
+ bcx. build. Store ( lllen, bcx. build. InBoundsGEP ( llstubptr, stub_a) ) ;
5551
+
5471
5552
auto llheapsz = bcx. build. Add ( llsize_of( llheapty) , lllen) ;
5472
5553
auto rslt = trans_raw_malloc( bcx, T_ptr ( llheapty) , llheapsz) ;
5473
5554
bcx = rslt. bcx;
0 commit comments