@@ -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,12 +2970,23 @@ 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
-
2978
2990
if ( ty:: type_is_scalar( cx. fcx. lcx. ccx. tcx, t) ||
2979
2991
ty:: type_is_native( cx. fcx. lcx. ccx. tcx, t) ) {
2980
2992
ret res( cx, cx. build. Store ( src, dst) ) ;
@@ -2991,7 +3003,11 @@ fn copy_val(&@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
2991
3003
ty:: type_has_dynamic_size( cx. fcx. lcx. ccx. tcx, t) ) {
2992
3004
auto r = take_ty( cx, src, t) ;
2993
3005
if ( action == DROP_EXISTING ) { r = drop_ty( r. bcx, dst, t) ; }
2994
- ret memmove_ty( r. bcx, dst, src, t) ;
3006
+ r = memmove_ty( r. bcx, dst, src, t) ;
3007
+ if ( ty:: type_owns_heap_mem( cx. fcx. lcx. ccx. tcx, t) ) {
3008
+ r = duplicate_heap_parts( cx, dst, t) ;
3009
+ }
3010
+ ret r;
2995
3011
}
2996
3012
cx. fcx. lcx. ccx. sess. bug( "unexpected type in trans:: copy_val: " +
2997
3013
ty_to_str( cx. fcx. lcx. ccx. tcx, t) ) ;
@@ -3500,9 +3516,13 @@ mod ivec {
3500
3516
copy_loop_header_cx. build. CondBr ( not_yet_at_end,
3501
3517
copy_loop_body_cx. llbb,
3502
3518
next_cx. llbb) ;
3519
+
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
+ auto copy_src = load_if_immediate( copy_loop_body_cx, copy_src_ptr,
3522
+ unit_ty) ;
3523
+
3524
+ rslt = copy_val( copy_loop_body_cx, INIT , copy_dest_ptr, copy_src,
3525
+ unit_ty) ;
3506
3526
auto post_copy_cx = rslt. bcx;
3507
3527
// Increment both pointers.
3508
3528
@@ -3575,6 +3595,9 @@ mod ivec {
3575
3595
auto unit_sz = ares. llunitsz;
3576
3596
auto llalen = ares. llalen;
3577
3597
3598
+ find_scope_cx( bcx) . cleanups +=
3599
+ [ clean( bind drop_ty( _, llvecptr, vec_ty) ) ] ;
3600
+
3578
3601
auto llunitty = type_of_or_i8( bcx, unit_ty) ;
3579
3602
auto llheappartty = T_ivec_heap_part ( llunitty) ;
3580
3603
auto lhs_len_and_data = get_len_and_data( bcx, lhs, unit_ty) ;
@@ -3740,6 +3763,66 @@ mod ivec {
3740
3763
3741
3764
ret res( next_cx, llvecptr) ;
3742
3765
}
3766
+
3767
+ // NB: This does *not* adjust reference counts. The caller must have done
3768
+ // this via take_ty() beforehand.
3769
+ fn duplicate_heap_part( & @block_ctxt cx, ValueRef orig_vptr,
3770
+ ty:: t unit_ty) -> result {
3771
+ // Cast to an opaque interior vector if we can't trust the pointer
3772
+ // type.
3773
+ auto vptr;
3774
+ if ( ty:: type_has_dynamic_size( cx. fcx. lcx. ccx. tcx, unit_ty) ) {
3775
+ vptr = cx. build. PointerCast ( orig_vptr, T_ptr ( T_opaque_ivec ( ) ) ) ;
3776
+ } else {
3777
+ vptr = orig_vptr;
3778
+ }
3779
+
3780
+ auto llunitty = type_of_or_i8( cx, unit_ty) ;
3781
+ auto llheappartty = T_ivec_heap_part ( llunitty) ;
3782
+
3783
+ // Check to see if the vector is heapified.
3784
+ auto stack_len_ptr = cx. build. InBoundsGEP ( vptr, [ C_int ( 0 ) ,
3785
+ C_uint ( abi:: ivec_elt_len) ] ) ;
3786
+ auto stack_len = cx. build. Load ( stack_len_ptr) ;
3787
+ auto stack_len_is_zero = cx. build. ICmp ( lib:: llvm:: LLVMIntEQ ,
3788
+ stack_len, C_int ( 0 ) ) ;
3789
+ auto maybe_on_heap_cx = new_sub_block_ctxt( cx, "maybe_on_heap") ;
3790
+ auto next_cx = new_sub_block_ctxt( cx, "next") ;
3791
+ cx. build. CondBr ( stack_len_is_zero, maybe_on_heap_cx. llbb,
3792
+ next_cx. llbb) ;
3793
+
3794
+ auto stub_ptr = maybe_on_heap_cx. build. PointerCast ( vptr,
3795
+ T_ptr ( T_ivec_heap ( llunitty) ) ) ;
3796
+ auto heap_ptr_ptr = maybe_on_heap_cx. build. InBoundsGEP ( stub_ptr,
3797
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_ptr) ] ) ;
3798
+ auto heap_ptr = maybe_on_heap_cx. build. Load ( heap_ptr_ptr) ;
3799
+ auto heap_ptr_is_nonnull = maybe_on_heap_cx. build. ICmp (
3800
+ lib:: llvm:: LLVMIntNE , heap_ptr, C_null ( T_ptr ( llheappartty) ) ) ;
3801
+ auto on_heap_cx = new_sub_block_ctxt( cx, "on_heap") ;
3802
+ maybe_on_heap_cx. build. CondBr ( heap_ptr_is_nonnull, on_heap_cx. llbb,
3803
+ next_cx. llbb) ;
3804
+
3805
+ // Ok, the vector is on the heap. Copy the heap part.
3806
+ auto alen_ptr = on_heap_cx. build. InBoundsGEP ( stub_ptr,
3807
+ [ C_int ( 0 ) , C_uint ( abi:: ivec_heap_stub_elt_alen) ] ) ;
3808
+ auto alen = on_heap_cx. build. Load ( alen_ptr) ;
3809
+
3810
+ auto heap_part_sz = on_heap_cx. build. Add ( alen,
3811
+ llsize_of( T_opaque_ivec_heap_part ( ) ) ) ;
3812
+ auto rslt = trans_raw_malloc( on_heap_cx, T_ptr ( llheappartty) ,
3813
+ heap_part_sz) ;
3814
+ on_heap_cx = rslt. bcx;
3815
+ auto new_heap_ptr = rslt. val;
3816
+
3817
+ rslt = call_memmove( on_heap_cx, new_heap_ptr, heap_ptr, heap_part_sz,
3818
+ C_int ( 4 ) ) ; // FIXME: align
3819
+ on_heap_cx = rslt. bcx;
3820
+
3821
+ on_heap_cx. build. Store ( new_heap_ptr, heap_ptr_ptr) ;
3822
+ on_heap_cx. build. Br ( next_cx. llbb) ;
3823
+
3824
+ ret res( next_cx, C_nil ( ) ) ;
3825
+ }
3743
3826
}
3744
3827
3745
3828
fn trans_vec_add( & @block_ctxt cx, & ty:: t t, ValueRef lhs, ValueRef rhs) ->
@@ -5431,6 +5514,8 @@ fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann) ->
5431
5514
auto unit_sz = ares. llunitsz;
5432
5515
auto llalen = ares. llalen;
5433
5516
5517
+ find_scope_cx( bcx) . cleanups += [ clean( bind drop_ty( _, llvecptr, typ) ) ] ;
5518
+
5434
5519
auto lllen = bcx. build. Mul ( C_uint ( vec:: len( args) ) , unit_sz) ;
5435
5520
// Allocate the vector pieces and store length and allocated length.
5436
5521
@@ -5459,15 +5544,17 @@ fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann) ->
5459
5544
auto llstubty = T_ivec_heap ( llunitty) ;
5460
5545
auto llstubptr = bcx. build. PointerCast ( llvecptr, T_ptr ( llstubty) ) ;
5461
5546
bcx. build. Store ( C_int ( 0 ) , bcx. build. InBoundsGEP ( llstubptr, stub_z) ) ;
5462
- bcx. build. Store ( lllen, bcx. build. InBoundsGEP ( llstubptr, stub_a) ) ;
5463
5547
auto llheapty = T_ivec_heap_part ( llunitty) ;
5464
5548
if ( vec:: len( args) == 0 u) {
5465
5549
// Null heap pointer indicates a zero-length vector.
5466
5550
5551
+ bcx. build. Store ( llalen, bcx. build. InBoundsGEP ( llstubptr, stub_a) ) ;
5467
5552
bcx. build. Store ( C_null ( T_ptr ( llheapty) ) ,
5468
5553
bcx. build. InBoundsGEP ( llstubptr, stub_p) ) ;
5469
5554
llfirsteltptr = C_null ( T_ptr ( llunitty) ) ;
5470
5555
} else {
5556
+ bcx. build. Store ( lllen, bcx. build. InBoundsGEP ( llstubptr, stub_a) ) ;
5557
+
5471
5558
auto llheapsz = bcx. build. Add ( llsize_of( llheapty) , lllen) ;
5472
5559
auto rslt = trans_raw_malloc( bcx, T_ptr ( llheapty) , llheapsz) ;
5473
5560
bcx = rslt. bcx;
0 commit comments