@@ -101,8 +101,7 @@ impl AllocationExtra<(), ()> for () {
101101impl < Tag , Extra > Allocation < Tag , Extra > {
102102 /// Creates a read-only allocation initialized by the given bytes
103103 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 ) ;
106105 Self {
107106 bytes : slice. to_owned ( ) ,
108107 relocations : Relocations :: new ( ) ,
@@ -122,7 +121,7 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
122121 Allocation {
123122 bytes : vec ! [ 0 ; size. bytes( ) as usize ] ,
124123 relocations : Relocations :: new ( ) ,
125- undef_mask : UndefMask :: new ( size) ,
124+ undef_mask : UndefMask :: new ( size, false ) ,
126125 align,
127126 mutability : Mutability :: Mutable ,
128127 extra,
@@ -614,8 +613,9 @@ impl<Tag> DerefMut for Relocations<Tag> {
614613////////////////////////////////////////////////////////////////////////////////
615614
616615type Block = u64 ;
617- const BLOCK_SIZE : u64 = 64 ;
618616
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.
619619#[ derive( Clone , Debug , Eq , PartialEq , PartialOrd , Ord , Hash , RustcEncodable , RustcDecodable ) ]
620620pub struct UndefMask {
621621 blocks : Vec < Block > ,
@@ -625,12 +625,14 @@ pub struct UndefMask {
625625impl_stable_hash_for ! ( struct mir:: interpret:: UndefMask { blocks, len} ) ;
626626
627627impl 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 {
629631 let mut m = UndefMask {
630632 blocks : vec ! [ ] ,
631633 len : Size :: ZERO ,
632634 } ;
633- m. grow ( size, false ) ;
635+ m. grow ( size, state ) ;
634636 m
635637 }
636638
@@ -644,6 +646,7 @@ impl UndefMask {
644646 return Err ( self . len ) ;
645647 }
646648
649+ // FIXME(oli-obk): optimize this for allocations larger than a block.
647650 let idx = ( start. bytes ( ) ..end. bytes ( ) )
648651 . map ( |i| Size :: from_bytes ( i) )
649652 . find ( |& i| !self . get ( i) ) ;
@@ -663,20 +666,63 @@ impl UndefMask {
663666 }
664667
665668 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+ }
668709 }
669710 }
670711
671712 #[ inline]
672713 pub fn get ( & self , i : Size ) -> bool {
673714 let ( block, bit) = bit_index ( i) ;
674- ( self . blocks [ block] & 1 << bit) != 0
715+ ( self . blocks [ block] & ( 1 << bit) ) != 0
675716 }
676717
677718 #[ inline]
678719 pub fn set ( & mut self , i : Size , new_state : bool ) {
679720 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 ) {
680726 if new_state {
681727 self . blocks [ block] |= 1 << bit;
682728 } else {
@@ -685,11 +731,15 @@ impl UndefMask {
685731 }
686732
687733 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 ( ) ;
689738 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 ;
691740 assert_eq ! ( additional_blocks as usize as u64 , additional_blocks) ;
692741 self . blocks . extend (
742+ // FIXME(oli-obk): optimize this by repeating `new_state as Block`
693743 iter:: repeat ( 0 ) . take ( additional_blocks as usize ) ,
694744 ) ;
695745 }
@@ -702,8 +752,8 @@ impl UndefMask {
702752#[ inline]
703753fn bit_index ( bits : Size ) -> ( usize , usize ) {
704754 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 ;
707757 assert_eq ! ( a as usize as u64 , a) ;
708758 assert_eq ! ( b as usize as u64 , b) ;
709759 ( a as usize , b as usize )
0 commit comments