]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/interpret/allocation.rs
rename Allocation::retag -> with_tags_and_extra
[rust.git] / src / librustc / mir / interpret / allocation.rs
1 //! The virtual memory representation of the MIR interpreter.
2
3 use super::{
4     Pointer, InterpResult, AllocId, ScalarMaybeUndef, write_target_uint, read_target_uint, Scalar,
5 };
6
7 use crate::mir;
8 use crate::ty::layout::{Size, Align};
9
10 use rustc_data_structures::sorted_map::SortedMap;
11 use rustc_target::abi::HasDataLayout;
12 use syntax::ast::Mutability;
13 use std::iter;
14 use std::ops::{Range, Deref, DerefMut};
15 use std::borrow::Cow;
16
17 // NOTE: When adding new fields, make sure to adjust the `Snapshot` impl in
18 // `src/librustc_mir/interpret/snapshot.rs`.
19 #[derive(
20     Clone,
21     Debug,
22     Eq,
23     PartialEq,
24     PartialOrd,
25     Ord,
26     Hash,
27     RustcEncodable,
28     RustcDecodable,
29     HashStable,
30 )]
31 pub struct Allocation<Tag = (),Extra = ()> {
32     /// The actual bytes of the allocation.
33     /// Note that the bytes of a pointer represent the offset of the pointer.
34     bytes: Vec<u8>,
35     /// Maps from byte addresses to extra data for each pointer.
36     /// Only the first byte of a pointer is inserted into the map; i.e.,
37     /// every entry in this map applies to `pointer_size` consecutive bytes starting
38     /// at the given offset.
39     relocations: Relocations<Tag>,
40     /// Denotes which part of this allocation is initialized.
41     undef_mask: UndefMask,
42     /// The size of the allocation. Currently, must always equal `bytes.len()`.
43     pub size: Size,
44     /// The alignment of the allocation to detect unaligned reads.
45     pub align: Align,
46     /// `true` if the allocation is mutable.
47     /// Also used by codegen to determine if a static should be put into mutable memory,
48     /// which happens for `static mut` and `static` with interior mutability.
49     pub mutability: Mutability,
50     /// Extra state for the machine.
51     pub extra: Extra,
52 }
53
54 pub trait AllocationExtra<Tag>: ::std::fmt::Debug + Clone {
55     // There is no constructor in here because the constructor's type depends
56     // on `MemoryKind`, and making things sufficiently generic leads to painful
57     // inference failure.
58
59     /// Hook for performing extra checks on a memory read access.
60     ///
61     /// Takes read-only access to the allocation so we can keep all the memory read
62     /// operations take `&self`. Use a `RefCell` in `AllocExtra` if you
63     /// need to mutate.
64     #[inline(always)]
65     fn memory_read(
66         _alloc: &Allocation<Tag, Self>,
67         _ptr: Pointer<Tag>,
68         _size: Size,
69     ) -> InterpResult<'tcx> {
70         Ok(())
71     }
72
73     /// Hook for performing extra checks on a memory write access.
74     #[inline(always)]
75     fn memory_written(
76         _alloc: &mut Allocation<Tag, Self>,
77         _ptr: Pointer<Tag>,
78         _size: Size,
79     ) -> InterpResult<'tcx> {
80         Ok(())
81     }
82
83     /// Hook for performing extra checks on a memory deallocation.
84     /// `size` will be the size of the allocation.
85     #[inline(always)]
86     fn memory_deallocated(
87         _alloc: &mut Allocation<Tag, Self>,
88         _ptr: Pointer<Tag>,
89         _size: Size,
90     ) -> InterpResult<'tcx> {
91         Ok(())
92     }
93 }
94
95 // For `Tag = ()` and no extra state, we have a trivial implementation.
96 impl AllocationExtra<()> for () { }
97
98 // The constructors are all without extra; the extra gets added by a machine hook later.
99 impl<Tag> Allocation<Tag> {
100     /// Creates a read-only allocation initialized by the given bytes
101     pub fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self {
102         let bytes = slice.into().into_owned();
103         let size = Size::from_bytes(bytes.len() as u64);
104         Self {
105             bytes,
106             relocations: Relocations::new(),
107             undef_mask: UndefMask::new(size, true),
108             size,
109             align,
110             mutability: Mutability::Immutable,
111             extra: (),
112         }
113     }
114
115     pub fn from_byte_aligned_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>) -> Self {
116         Allocation::from_bytes(slice, Align::from_bytes(1).unwrap())
117     }
118
119     pub fn undef(size: Size, align: Align) -> Self {
120         assert_eq!(size.bytes() as usize as u64, size.bytes());
121         Allocation {
122             bytes: vec![0; size.bytes() as usize],
123             relocations: Relocations::new(),
124             undef_mask: UndefMask::new(size, false),
125             size,
126             align,
127             mutability: Mutability::Mutable,
128             extra: (),
129         }
130     }
131 }
132
133 impl Allocation<(), ()> {
134     /// Add Tag and Extra fields
135     pub fn with_tags_and_extra<T, E>(
136         self,
137         mut tagger: impl FnMut(AllocId) -> T,
138         extra: E,
139     ) -> Allocation<T, E> {
140         Allocation {
141             bytes: self.bytes,
142             size: self.size,
143             relocations: Relocations::from_presorted(
144                 self.relocations.iter()
145                     // The allocations in the relocations (pointers stored *inside* this allocation)
146                     // all get the base pointer tag.
147                     .map(|&(offset, ((), alloc))| {
148                         let tag = tagger(alloc);
149                         (offset, (tag, alloc))
150                     })
151                     .collect()
152             ),
153             undef_mask: self.undef_mask,
154             align: self.align,
155             mutability: self.mutability,
156             extra,
157         }
158     }
159 }
160
161 /// Raw accessors. Provide access to otherwise private bytes.
162 impl<Tag, Extra> Allocation<Tag, Extra> {
163     pub fn len(&self) -> usize {
164         self.size.bytes() as usize
165     }
166
167     /// Looks at a slice which may describe undefined bytes or describe a relocation. This differs
168     /// from `get_bytes_with_undef_and_ptr` in that it does no relocation checks (even on the
169     /// edges) at all. It further ignores `AllocationExtra` callbacks.
170     /// This must not be used for reads affecting the interpreter execution.
171     pub fn inspect_with_undef_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] {
172         &self.bytes[range]
173     }
174
175     /// Returns the undef mask.
176     pub fn undef_mask(&self) -> &UndefMask {
177         &self.undef_mask
178     }
179
180     /// Returns the relocation list.
181     pub fn relocations(&self) -> &Relocations<Tag> {
182         &self.relocations
183     }
184 }
185
186 impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx Allocation {}
187
188 /// Byte accessors.
189 impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
190     /// Just a small local helper function to avoid a bit of code repetition.
191     /// Returns the range of this allocation that was meant.
192     #[inline]
193     fn check_bounds(
194         &self,
195         offset: Size,
196         size: Size
197     ) -> Range<usize> {
198         let end = offset + size; // This does overflow checking.
199         assert_eq!(
200             end.bytes() as usize as u64, end.bytes(),
201             "cannot handle this access on this host architecture"
202         );
203         let end = end.bytes() as usize;
204         assert!(
205             end <= self.len(),
206             "Out-of-bounds access at offset {}, size {} in allocation of size {}",
207             offset.bytes(), size.bytes(), self.len()
208         );
209         (offset.bytes() as usize)..end
210     }
211
212     /// The last argument controls whether we error out when there are undefined
213     /// or pointer bytes. You should never call this, call `get_bytes` or
214     /// `get_bytes_with_undef_and_ptr` instead,
215     ///
216     /// This function also guarantees that the resulting pointer will remain stable
217     /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
218     /// on that.
219     ///
220     /// It is the caller's responsibility to check bounds and alignment beforehand.
221     fn get_bytes_internal(
222         &self,
223         cx: &impl HasDataLayout,
224         ptr: Pointer<Tag>,
225         size: Size,
226         check_defined_and_ptr: bool,
227     ) -> InterpResult<'tcx, &[u8]>
228     {
229         let range = self.check_bounds(ptr.offset, size);
230
231         if check_defined_and_ptr {
232             self.check_defined(ptr, size)?;
233             self.check_relocations(cx, ptr, size)?;
234         } else {
235             // We still don't want relocations on the *edges*.
236             self.check_relocation_edges(cx, ptr, size)?;
237         }
238
239         AllocationExtra::memory_read(self, ptr, size)?;
240
241         Ok(&self.bytes[range])
242     }
243
244     /// Checks that these bytes are initialized and not pointer bytes, and then return them
245     /// as a slice.
246     ///
247     /// It is the caller's responsibility to check bounds and alignment beforehand.
248     #[inline]
249     pub fn get_bytes(
250         &self,
251         cx: &impl HasDataLayout,
252         ptr: Pointer<Tag>,
253         size: Size,
254     ) -> InterpResult<'tcx, &[u8]>
255     {
256         self.get_bytes_internal(cx, ptr, size, true)
257     }
258
259     /// It is the caller's responsibility to handle undefined and pointer bytes.
260     /// However, this still checks that there are no relocations on the *edges*.
261     ///
262     /// It is the caller's responsibility to check bounds and alignment beforehand.
263     #[inline]
264     pub fn get_bytes_with_undef_and_ptr(
265         &self,
266         cx: &impl HasDataLayout,
267         ptr: Pointer<Tag>,
268         size: Size,
269     ) -> InterpResult<'tcx, &[u8]>
270     {
271         self.get_bytes_internal(cx, ptr, size, false)
272     }
273
274     /// Just calling this already marks everything as defined and removes relocations,
275     /// so be sure to actually put data there!
276     ///
277     /// It is the caller's responsibility to check bounds and alignment beforehand.
278     pub fn get_bytes_mut(
279         &mut self,
280         cx: &impl HasDataLayout,
281         ptr: Pointer<Tag>,
282         size: Size,
283     ) -> InterpResult<'tcx, &mut [u8]>
284     {
285         let range = self.check_bounds(ptr.offset, size);
286
287         self.mark_definedness(ptr, size, true);
288         self.clear_relocations(cx, ptr, size)?;
289
290         AllocationExtra::memory_written(self, ptr, size)?;
291
292         Ok(&mut self.bytes[range])
293     }
294 }
295
296 /// Reading and writing.
297 impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
298     /// Reads bytes until a `0` is encountered. Will error if the end of the allocation is reached
299     /// before a `0` is found.
300     pub fn read_c_str(
301         &self,
302         cx: &impl HasDataLayout,
303         ptr: Pointer<Tag>,
304     ) -> InterpResult<'tcx, &[u8]>
305     {
306         assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
307         let offset = ptr.offset.bytes() as usize;
308         Ok(match self.bytes[offset..].iter().position(|&c| c == 0) {
309             Some(size) => {
310                 let size_with_null = Size::from_bytes((size + 1) as u64);
311                 // Go through `get_bytes` for checks and AllocationExtra hooks.
312                 // We read the null, so we include it in the request, but we want it removed
313                 // from the result, so we do subslicing.
314                 &self.get_bytes(cx, ptr, size_with_null)?[..size]
315             }
316             // This includes the case where `offset` is out-of-bounds to begin with.
317             None => throw_unsup!(UnterminatedCString(ptr.erase_tag())),
318         })
319     }
320
321     /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
322     /// relocation. If `allow_ptr_and_undef` is `false`, also enforces that the memory in the
323     /// given range contains neither relocations nor undef bytes.
324     pub fn check_bytes(
325         &self,
326         cx: &impl HasDataLayout,
327         ptr: Pointer<Tag>,
328         size: Size,
329         allow_ptr_and_undef: bool,
330     ) -> InterpResult<'tcx>
331     {
332         // Check bounds and relocations on the edges.
333         self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
334         // Check undef and ptr.
335         if !allow_ptr_and_undef {
336             self.check_defined(ptr, size)?;
337             self.check_relocations(cx, ptr, size)?;
338         }
339         Ok(())
340     }
341
342     /// Writes `src` to the memory starting at `ptr.offset`.
343     ///
344     /// It is the caller's responsibility to check bounds and alignment beforehand.
345     pub fn write_bytes(
346         &mut self,
347         cx: &impl HasDataLayout,
348         ptr: Pointer<Tag>,
349         src: &[u8],
350     ) -> InterpResult<'tcx>
351     {
352         let bytes = self.get_bytes_mut(cx, ptr, Size::from_bytes(src.len() as u64))?;
353         bytes.clone_from_slice(src);
354         Ok(())
355     }
356
357     /// Sets `count` bytes starting at `ptr.offset` with `val`. Basically `memset`.
358     ///
359     /// It is the caller's responsibility to check bounds and alignment beforehand.
360     pub fn write_repeat(
361         &mut self,
362         cx: &impl HasDataLayout,
363         ptr: Pointer<Tag>,
364         val: u8,
365         count: Size
366     ) -> InterpResult<'tcx>
367     {
368         let bytes = self.get_bytes_mut(cx, ptr, count)?;
369         for b in bytes {
370             *b = val;
371         }
372         Ok(())
373     }
374
375     /// Reads a *non-ZST* scalar.
376     ///
377     /// ZSTs can't be read for two reasons:
378     /// * byte-order cannot work with zero-element buffers;
379     /// * in order to obtain a `Pointer`, we need to check for ZSTness anyway due to integer
380     ///   pointers being valid for ZSTs.
381     ///
382     /// It is the caller's responsibility to check bounds and alignment beforehand.
383     pub fn read_scalar(
384         &self,
385         cx: &impl HasDataLayout,
386         ptr: Pointer<Tag>,
387         size: Size
388     ) -> InterpResult<'tcx, ScalarMaybeUndef<Tag>>
389     {
390         // `get_bytes_unchecked` tests relocation edges.
391         let bytes = self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
392         // Undef check happens *after* we established that the alignment is correct.
393         // We must not return `Ok()` for unaligned pointers!
394         if self.check_defined(ptr, size).is_err() {
395             // This inflates undefined bytes to the entire scalar, even if only a few
396             // bytes are undefined.
397             return Ok(ScalarMaybeUndef::Undef);
398         }
399         // Now we do the actual reading.
400         let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
401         // See if we got a pointer.
402         if size != cx.data_layout().pointer_size {
403             // *Now*, we better make sure that the inside is free of relocations too.
404             self.check_relocations(cx, ptr, size)?;
405         } else {
406             match self.relocations.get(&ptr.offset) {
407                 Some(&(tag, alloc_id)) => {
408                     let ptr = Pointer::new_with_tag(alloc_id, Size::from_bytes(bits as u64), tag);
409                     return Ok(ScalarMaybeUndef::Scalar(ptr.into()))
410                 }
411                 None => {},
412             }
413         }
414         // We don't. Just return the bits.
415         Ok(ScalarMaybeUndef::Scalar(Scalar::from_uint(bits, size)))
416     }
417
418     /// Reads a pointer-sized scalar.
419     ///
420     /// It is the caller's responsibility to check bounds and alignment beforehand.
421     pub fn read_ptr_sized(
422         &self,
423         cx: &impl HasDataLayout,
424         ptr: Pointer<Tag>,
425     ) -> InterpResult<'tcx, ScalarMaybeUndef<Tag>>
426     {
427         self.read_scalar(cx, ptr, cx.data_layout().pointer_size)
428     }
429
430     /// Writes a *non-ZST* scalar.
431     ///
432     /// ZSTs can't be read for two reasons:
433     /// * byte-order cannot work with zero-element buffers;
434     /// * in order to obtain a `Pointer`, we need to check for ZSTness anyway due to integer
435     ///   pointers being valid for ZSTs.
436     ///
437     /// It is the caller's responsibility to check bounds and alignment beforehand.
438     pub fn write_scalar(
439         &mut self,
440         cx: &impl HasDataLayout,
441         ptr: Pointer<Tag>,
442         val: ScalarMaybeUndef<Tag>,
443         type_size: Size,
444     ) -> InterpResult<'tcx>
445     {
446         let val = match val {
447             ScalarMaybeUndef::Scalar(scalar) => scalar,
448             ScalarMaybeUndef::Undef => {
449                 self.mark_definedness(ptr, type_size, false);
450                 return Ok(());
451             },
452         };
453
454         let bytes = match val.to_bits_or_ptr(type_size, cx) {
455             Err(val) => val.offset.bytes() as u128,
456             Ok(data) => data,
457         };
458
459         let endian = cx.data_layout().endian;
460         let dst = self.get_bytes_mut(cx, ptr, type_size)?;
461         write_target_uint(endian, dst, bytes).unwrap();
462
463         // See if we have to also write a relocation.
464         match val {
465             Scalar::Ptr(val) => {
466                 self.relocations.insert(
467                     ptr.offset,
468                     (val.tag, val.alloc_id),
469                 );
470             }
471             _ => {}
472         }
473
474         Ok(())
475     }
476
477     /// Writes a pointer-sized scalar.
478     ///
479     /// It is the caller's responsibility to check bounds and alignment beforehand.
480     pub fn write_ptr_sized(
481         &mut self,
482         cx: &impl HasDataLayout,
483         ptr: Pointer<Tag>,
484         val: ScalarMaybeUndef<Tag>
485     ) -> InterpResult<'tcx>
486     {
487         let ptr_size = cx.data_layout().pointer_size;
488         self.write_scalar(cx, ptr.into(), val, ptr_size)
489     }
490 }
491
492 /// Relocations.
493 impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
494     /// Returns all relocations overlapping with the given pointer-offset pair.
495     pub fn get_relocations(
496         &self,
497         cx: &impl HasDataLayout,
498         ptr: Pointer<Tag>,
499         size: Size,
500     ) -> &[(Size, (Tag, AllocId))] {
501         // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
502         // the beginning of this range.
503         let start = ptr.offset.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1);
504         let end = ptr.offset + size; // This does overflow checking.
505         self.relocations.range(Size::from_bytes(start)..end)
506     }
507
508     /// Checks that there are no relocations overlapping with the given range.
509     #[inline(always)]
510     fn check_relocations(
511         &self,
512         cx: &impl HasDataLayout,
513         ptr: Pointer<Tag>,
514         size: Size,
515     ) -> InterpResult<'tcx> {
516         if self.get_relocations(cx, ptr, size).is_empty() {
517             Ok(())
518         } else {
519             throw_unsup!(ReadPointerAsBytes)
520         }
521     }
522
523     /// Removes all relocations inside the given range.
524     /// If there are relocations overlapping with the edges, they
525     /// are removed as well *and* the bytes they cover are marked as
526     /// uninitialized. This is a somewhat odd "spooky action at a distance",
527     /// but it allows strictly more code to run than if we would just error
528     /// immediately in that case.
529     fn clear_relocations(
530         &mut self,
531         cx: &impl HasDataLayout,
532         ptr: Pointer<Tag>,
533         size: Size,
534     ) -> InterpResult<'tcx> {
535         // Find the start and end of the given range and its outermost relocations.
536         let (first, last) = {
537             // Find all relocations overlapping the given range.
538             let relocations = self.get_relocations(cx, ptr, size);
539             if relocations.is_empty() {
540                 return Ok(());
541             }
542
543             (relocations.first().unwrap().0,
544              relocations.last().unwrap().0 + cx.data_layout().pointer_size)
545         };
546         let start = ptr.offset;
547         let end = start + size;
548
549         // Mark parts of the outermost relocations as undefined if they partially fall outside the
550         // given range.
551         if first < start {
552             self.undef_mask.set_range(first, start, false);
553         }
554         if last > end {
555             self.undef_mask.set_range(end, last, false);
556         }
557
558         // Forget all the relocations.
559         self.relocations.remove_range(first..last);
560
561         Ok(())
562     }
563
564     /// Errors if there are relocations overlapping with the edges of the
565     /// given memory range.
566     #[inline]
567     fn check_relocation_edges(
568         &self,
569         cx: &impl HasDataLayout,
570         ptr: Pointer<Tag>,
571         size: Size,
572     ) -> InterpResult<'tcx> {
573         self.check_relocations(cx, ptr, Size::ZERO)?;
574         self.check_relocations(cx, ptr.offset(size, cx)?, Size::ZERO)?;
575         Ok(())
576     }
577 }
578
579
580 /// Undefined bytes.
581 impl<'tcx, Tag, Extra> Allocation<Tag, Extra> {
582     /// Checks that a range of bytes is defined. If not, returns the `ReadUndefBytes`
583     /// error which will report the first byte which is undefined.
584     #[inline]
585     fn check_defined(&self, ptr: Pointer<Tag>, size: Size) -> InterpResult<'tcx> {
586         self.undef_mask.is_range_defined(
587             ptr.offset,
588             ptr.offset + size,
589         ).or_else(|idx| throw_unsup!(ReadUndefBytes(idx)))
590     }
591
592     pub fn mark_definedness(
593         &mut self,
594         ptr: Pointer<Tag>,
595         size: Size,
596         new_state: bool,
597     ) {
598         if size.bytes() == 0 {
599             return;
600         }
601         self.undef_mask.set_range(
602             ptr.offset,
603             ptr.offset + size,
604             new_state,
605         );
606     }
607 }
608
609 /// Run-length encoding of the undef mask.
610 /// Used to copy parts of a mask multiple times to another allocation.
611 pub struct AllocationDefinedness {
612     /// The definedness of the first range.
613     initial: bool,
614     /// The lengths of ranges that are run-length encoded.
615     /// The definedness of the ranges alternate starting with `initial`.
616     ranges: smallvec::SmallVec::<[u64; 1]>,
617 }
618
619 /// Transferring the definedness mask to other allocations.
620 impl<Tag, Extra> Allocation<Tag, Extra> {
621     /// Creates a run-length encoding of the undef mask.
622     pub fn compress_undef_range(
623         &self,
624         src: Pointer<Tag>,
625         size: Size,
626     ) -> AllocationDefinedness {
627         // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`),
628         // a naive undef mask copying algorithm would repeatedly have to read the undef mask from
629         // the source and write it to the destination. Even if we optimized the memory accesses,
630         // we'd be doing all of this `repeat` times.
631         // Therefor we precompute a compressed version of the undef mask of the source value and
632         // then write it back `repeat` times without computing any more information from the source.
633
634         // A precomputed cache for ranges of defined/undefined bits
635         // 0000010010001110 will become
636         // `[5, 1, 2, 1, 3, 3, 1]`,
637         // where each element toggles the state.
638
639         let mut ranges = smallvec::SmallVec::<[u64; 1]>::new();
640         let initial = self.undef_mask.get(src.offset);
641         let mut cur_len = 1;
642         let mut cur = initial;
643
644         for i in 1..size.bytes() {
645             // FIXME: optimize to bitshift the current undef block's bits and read the top bit.
646             if self.undef_mask.get(src.offset + Size::from_bytes(i)) == cur {
647                 cur_len += 1;
648             } else {
649                 ranges.push(cur_len);
650                 cur_len = 1;
651                 cur = !cur;
652             }
653         }
654
655         ranges.push(cur_len);
656
657         AllocationDefinedness { ranges, initial, }
658     }
659
660     /// Applies multiple instances of the run-length encoding to the undef mask.
661     pub fn mark_compressed_undef_range(
662         &mut self,
663         defined: &AllocationDefinedness,
664         dest: Pointer<Tag>,
665         size: Size,
666         repeat: u64,
667     ) {
668         // An optimization where we can just overwrite an entire range of definedness bits if
669         // they are going to be uniformly `1` or `0`.
670         if defined.ranges.len() <= 1 {
671             self.undef_mask.set_range_inbounds(
672                 dest.offset,
673                 dest.offset + size * repeat,
674                 defined.initial,
675             );
676             return;
677         }
678
679         for mut j in 0..repeat {
680             j *= size.bytes();
681             j += dest.offset.bytes();
682             let mut cur = defined.initial;
683             for range in &defined.ranges {
684                 let old_j = j;
685                 j += range;
686                 self.undef_mask.set_range_inbounds(
687                     Size::from_bytes(old_j),
688                     Size::from_bytes(j),
689                     cur,
690                 );
691                 cur = !cur;
692             }
693         }
694     }
695 }
696
697 /// Relocations.
698 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
699 pub struct Relocations<Tag = (), Id = AllocId>(SortedMap<Size, (Tag, Id)>);
700
701 impl<Tag, Id> Relocations<Tag, Id> {
702     pub fn new() -> Self {
703         Relocations(SortedMap::new())
704     }
705
706     // The caller must guarantee that the given relocations are already sorted
707     // by address and contain no duplicates.
708     pub fn from_presorted(r: Vec<(Size, (Tag, Id))>) -> Self {
709         Relocations(SortedMap::from_presorted_elements(r))
710     }
711 }
712
713 impl<Tag> Deref for Relocations<Tag> {
714     type Target = SortedMap<Size, (Tag, AllocId)>;
715
716     fn deref(&self) -> &Self::Target {
717         &self.0
718     }
719 }
720
721 impl<Tag> DerefMut for Relocations<Tag> {
722     fn deref_mut(&mut self) -> &mut Self::Target {
723         &mut self.0
724     }
725 }
726
727 /// A partial, owned list of relocations to transfer into another allocation.
728 pub struct AllocationRelocations<Tag> {
729     relative_relocations: Vec<(Size, (Tag, AllocId))>,
730 }
731
732 impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
733     pub fn prepare_relocation_copy(
734         &self,
735         cx: &impl HasDataLayout,
736         src: Pointer<Tag>,
737         size: Size,
738         dest: Pointer<Tag>,
739         length: u64,
740     ) -> AllocationRelocations<Tag> {
741         let relocations = self.get_relocations(cx, src, size);
742         if relocations.is_empty() {
743             return AllocationRelocations { relative_relocations: Vec::new() };
744         }
745
746         let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize));
747
748         for i in 0..length {
749             new_relocations.extend(
750                 relocations
751                 .iter()
752                 .map(|&(offset, reloc)| {
753                     // compute offset for current repetition
754                     let dest_offset = dest.offset + (i * size);
755                     (
756                         // shift offsets from source allocation to destination allocation
757                         offset + dest_offset - src.offset,
758                         reloc,
759                     )
760                 })
761             );
762         }
763
764         AllocationRelocations {
765             relative_relocations: new_relocations,
766         }
767     }
768
769     /// Applies a relocation copy.
770     /// The affected range, as defined in the parameters to `prepare_relocation_copy` is expected
771     /// to be clear of relocations.
772     pub fn mark_relocation_range(
773         &mut self,
774         relocations: AllocationRelocations<Tag>,
775     ) {
776         self.relocations.insert_presorted(relocations.relative_relocations);
777     }
778 }
779
780 ////////////////////////////////////////////////////////////////////////////////
781 // Undefined byte tracking
782 ////////////////////////////////////////////////////////////////////////////////
783
784 type Block = u64;
785
786 /// A bitmask where each bit refers to the byte with the same index. If the bit is `true`, the byte
787 /// is defined. If it is `false` the byte is undefined.
788 #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
789 pub struct UndefMask {
790     blocks: Vec<Block>,
791     len: Size,
792 }
793
794 impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len});
795
796 impl UndefMask {
797     pub const BLOCK_SIZE: u64 = 64;
798
799     pub fn new(size: Size, state: bool) -> Self {
800         let mut m = UndefMask {
801             blocks: vec![],
802             len: Size::ZERO,
803         };
804         m.grow(size, state);
805         m
806     }
807
808     /// Checks whether the range `start..end` (end-exclusive) is entirely defined.
809     ///
810     /// Returns `Ok(())` if it's defined. Otherwise returns the index of the byte
811     /// at which the first undefined access begins.
812     #[inline]
813     pub fn is_range_defined(&self, start: Size, end: Size) -> Result<(), Size> {
814         if end > self.len {
815             return Err(self.len);
816         }
817
818         // FIXME(oli-obk): optimize this for allocations larger than a block.
819         let idx = (start.bytes()..end.bytes())
820             .map(|i| Size::from_bytes(i))
821             .find(|&i| !self.get(i));
822
823         match idx {
824             Some(idx) => Err(idx),
825             None => Ok(())
826         }
827     }
828
829     pub fn set_range(&mut self, start: Size, end: Size, new_state: bool) {
830         let len = self.len;
831         if end > len {
832             self.grow(end - len, new_state);
833         }
834         self.set_range_inbounds(start, end, new_state);
835     }
836
837     pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) {
838         let (blocka, bita) = bit_index(start);
839         let (blockb, bitb) = bit_index(end);
840         if blocka == blockb {
841             // First set all bits except the first `bita`,
842             // then unset the last `64 - bitb` bits.
843             let range = if bitb == 0 {
844                 u64::max_value() << bita
845             } else {
846                 (u64::max_value() << bita) & (u64::max_value() >> (64 - bitb))
847             };
848             if new_state {
849                 self.blocks[blocka] |= range;
850             } else {
851                 self.blocks[blocka] &= !range;
852             }
853             return;
854         }
855         // across block boundaries
856         if new_state {
857             // Set `bita..64` to `1`.
858             self.blocks[blocka] |= u64::max_value() << bita;
859             // Set `0..bitb` to `1`.
860             if bitb != 0 {
861                 self.blocks[blockb] |= u64::max_value() >> (64 - bitb);
862             }
863             // Fill in all the other blocks (much faster than one bit at a time).
864             for block in (blocka + 1) .. blockb {
865                 self.blocks[block] = u64::max_value();
866             }
867         } else {
868             // Set `bita..64` to `0`.
869             self.blocks[blocka] &= !(u64::max_value() << bita);
870             // Set `0..bitb` to `0`.
871             if bitb != 0 {
872                 self.blocks[blockb] &= !(u64::max_value() >> (64 - bitb));
873             }
874             // Fill in all the other blocks (much faster than one bit at a time).
875             for block in (blocka + 1) .. blockb {
876                 self.blocks[block] = 0;
877             }
878         }
879     }
880
881     #[inline]
882     pub fn get(&self, i: Size) -> bool {
883         let (block, bit) = bit_index(i);
884         (self.blocks[block] & (1 << bit)) != 0
885     }
886
887     #[inline]
888     pub fn set(&mut self, i: Size, new_state: bool) {
889         let (block, bit) = bit_index(i);
890         self.set_bit(block, bit, new_state);
891     }
892
893     #[inline]
894     fn set_bit(&mut self, block: usize, bit: usize, new_state: bool) {
895         if new_state {
896             self.blocks[block] |= 1 << bit;
897         } else {
898             self.blocks[block] &= !(1 << bit);
899         }
900     }
901
902     pub fn grow(&mut self, amount: Size, new_state: bool) {
903         if amount.bytes() == 0 {
904             return;
905         }
906         let unused_trailing_bits = self.blocks.len() as u64 * Self::BLOCK_SIZE - self.len.bytes();
907         if amount.bytes() > unused_trailing_bits {
908             let additional_blocks = amount.bytes() / Self::BLOCK_SIZE + 1;
909             assert_eq!(additional_blocks as usize as u64, additional_blocks);
910             self.blocks.extend(
911                 // FIXME(oli-obk): optimize this by repeating `new_state as Block`.
912                 iter::repeat(0).take(additional_blocks as usize),
913             );
914         }
915         let start = self.len;
916         self.len += amount;
917         self.set_range_inbounds(start, start + amount, new_state);
918     }
919 }
920
921 #[inline]
922 fn bit_index(bits: Size) -> (usize, usize) {
923     let bits = bits.bytes();
924     let a = bits / UndefMask::BLOCK_SIZE;
925     let b = bits % UndefMask::BLOCK_SIZE;
926     assert_eq!(a as usize as u64, a);
927     assert_eq!(b as usize as u64, b);
928     (a as usize, b as usize)
929 }