@@ -101,8 +101,7 @@ impl AllocationExtra<(), ()> for () {
101
101
impl < Tag , Extra > Allocation < Tag , Extra > {
102
102
/// Creates a read-only allocation initialized by the given bytes
103
103
pub fn from_bytes ( slice : & [ u8 ] , align : Align , extra : Extra ) -> Self {
104
- let mut undef_mask = UndefMask :: new ( Size :: ZERO ) ;
105
- undef_mask. grow ( Size :: from_bytes ( slice. len ( ) as u64 ) , true ) ;
104
+ let undef_mask = UndefMask :: new ( Size :: from_bytes ( slice. len ( ) as u64 ) , true ) ;
106
105
Self {
107
106
bytes : slice. to_owned ( ) ,
108
107
relocations : Relocations :: new ( ) ,
@@ -122,7 +121,7 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
122
121
Allocation {
123
122
bytes : vec ! [ 0 ; size. bytes( ) as usize ] ,
124
123
relocations : Relocations :: new ( ) ,
125
- undef_mask : UndefMask :: new ( size) ,
124
+ undef_mask : UndefMask :: new ( size, false ) ,
126
125
align,
127
126
mutability : Mutability :: Mutable ,
128
127
extra,
@@ -614,8 +613,9 @@ impl<Tag> DerefMut for Relocations<Tag> {
614
613
////////////////////////////////////////////////////////////////////////////////
615
614
616
615
type Block = u64 ;
617
- const BLOCK_SIZE : u64 = 64 ;
618
616
617
+ /// A bitmask where each bit refers to the byte with the same index. If the bit is `true`, the byte
618
+ /// is defined. If it is `false` the byte is undefined.
619
619
#[ derive( Clone , Debug , Eq , PartialEq , PartialOrd , Ord , Hash , RustcEncodable , RustcDecodable ) ]
620
620
pub struct UndefMask {
621
621
blocks : Vec < Block > ,
@@ -625,12 +625,14 @@ pub struct UndefMask {
625
625
impl_stable_hash_for ! ( struct mir:: interpret:: UndefMask { blocks, len} ) ;
626
626
627
627
impl UndefMask {
628
- pub fn new ( size : Size ) -> Self {
628
+ pub const BLOCK_SIZE : u64 = 64 ;
629
+
630
+ pub fn new ( size : Size , state : bool ) -> Self {
629
631
let mut m = UndefMask {
630
632
blocks : vec ! [ ] ,
631
633
len : Size :: ZERO ,
632
634
} ;
633
- m. grow ( size, false ) ;
635
+ m. grow ( size, state ) ;
634
636
m
635
637
}
636
638
@@ -644,6 +646,7 @@ impl UndefMask {
644
646
return Err ( self . len ) ;
645
647
}
646
648
649
+ // FIXME(oli-obk): optimize this for allocations larger than a block.
647
650
let idx = ( start. bytes ( ) ..end. bytes ( ) )
648
651
. map ( |i| Size :: from_bytes ( i) )
649
652
. find ( |& i| !self . get ( i) ) ;
@@ -663,20 +666,63 @@ impl UndefMask {
663
666
}
664
667
665
668
pub fn set_range_inbounds ( & mut self , start : Size , end : Size , new_state : bool ) {
666
- for i in start. bytes ( ) ..end. bytes ( ) {
667
- self . set ( Size :: from_bytes ( i) , new_state) ;
669
+ let ( blocka, bita) = bit_index ( start) ;
670
+ let ( blockb, bitb) = bit_index ( end) ;
671
+ if blocka == blockb {
672
+ // first set all bits but the first `bita`
673
+ // then unset the last `64 - bitb` bits
674
+ let range = if bitb == 0 {
675
+ u64:: max_value ( ) << bita
676
+ } else {
677
+ ( u64:: max_value ( ) << bita) & ( u64:: max_value ( ) >> ( 64 - bitb) )
678
+ } ;
679
+ if new_state {
680
+ self . blocks [ blocka] |= range;
681
+ } else {
682
+ self . blocks [ blocka] &= !range;
683
+ }
684
+ return ;
685
+ }
686
+ // across block boundaries
687
+ if new_state {
688
+ // set bita..64 to 1
689
+ self . blocks [ blocka] |= u64:: max_value ( ) << bita;
690
+ // set 0..bitb to 1
691
+ if bitb != 0 {
692
+ self . blocks [ blockb] |= u64:: max_value ( ) >> ( 64 - bitb) ;
693
+ }
694
+ // fill in all the other blocks (much faster than one bit at a time)
695
+ for block in ( blocka + 1 ) .. blockb {
696
+ self . blocks [ block] = u64:: max_value ( ) ;
697
+ }
698
+ } else {
699
+ // set bita..64 to 0
700
+ self . blocks [ blocka] &= !( u64:: max_value ( ) << bita) ;
701
+ // set 0..bitb to 0
702
+ if bitb != 0 {
703
+ self . blocks [ blockb] &= !( u64:: max_value ( ) >> ( 64 - bitb) ) ;
704
+ }
705
+ // fill in all the other blocks (much faster than one bit at a time)
706
+ for block in ( blocka + 1 ) .. blockb {
707
+ self . blocks [ block] = 0 ;
708
+ }
668
709
}
669
710
}
670
711
671
712
#[ inline]
672
713
pub fn get ( & self , i : Size ) -> bool {
673
714
let ( block, bit) = bit_index ( i) ;
674
- ( self . blocks [ block] & 1 << bit) != 0
715
+ ( self . blocks [ block] & ( 1 << bit) ) != 0
675
716
}
676
717
677
718
#[ inline]
678
719
pub fn set ( & mut self , i : Size , new_state : bool ) {
679
720
let ( block, bit) = bit_index ( i) ;
721
+ self . set_bit ( block, bit, new_state) ;
722
+ }
723
+
724
+ #[ inline]
725
+ fn set_bit ( & mut self , block : usize , bit : usize , new_state : bool ) {
680
726
if new_state {
681
727
self . blocks [ block] |= 1 << bit;
682
728
} else {
@@ -685,11 +731,15 @@ impl UndefMask {
685
731
}
686
732
687
733
pub fn grow ( & mut self , amount : Size , new_state : bool ) {
688
- let unused_trailing_bits = self . blocks . len ( ) as u64 * BLOCK_SIZE - self . len . bytes ( ) ;
734
+ if amount. bytes ( ) == 0 {
735
+ return ;
736
+ }
737
+ let unused_trailing_bits = self . blocks . len ( ) as u64 * Self :: BLOCK_SIZE - self . len . bytes ( ) ;
689
738
if amount. bytes ( ) > unused_trailing_bits {
690
- let additional_blocks = amount. bytes ( ) / BLOCK_SIZE + 1 ;
739
+ let additional_blocks = amount. bytes ( ) / Self :: BLOCK_SIZE + 1 ;
691
740
assert_eq ! ( additional_blocks as usize as u64 , additional_blocks) ;
692
741
self . blocks . extend (
742
+ // FIXME(oli-obk): optimize this by repeating `new_state as Block`
693
743
iter:: repeat ( 0 ) . take ( additional_blocks as usize ) ,
694
744
) ;
695
745
}
@@ -702,8 +752,8 @@ impl UndefMask {
702
752
#[ inline]
703
753
fn bit_index ( bits : Size ) -> ( usize , usize ) {
704
754
let bits = bits. bytes ( ) ;
705
- let a = bits / BLOCK_SIZE ;
706
- let b = bits % BLOCK_SIZE ;
755
+ let a = bits / UndefMask :: BLOCK_SIZE ;
756
+ let b = bits % UndefMask :: BLOCK_SIZE ;
707
757
assert_eq ! ( a as usize as u64 , a) ;
708
758
assert_eq ! ( b as usize as u64 , b) ;
709
759
( a as usize , b as usize )
0 commit comments