File: memory_region.h

package info (click to toggle)
android-platform-art 11.0.0%2Br48-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 78,932 kB
  • sloc: cpp: 459,858; java: 163,268; asm: 22,644; python: 9,815; sh: 6,330; ansic: 4,117; xml: 2,855; perl: 77; makefile: 73
file content (163 lines) | stat: -rw-r--r-- 5,854 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_LIBARTBASE_BASE_MEMORY_REGION_H_
#define ART_LIBARTBASE_BASE_MEMORY_REGION_H_

#include <stdint.h>
#include <type_traits>

#include <android-base/logging.h>

#include "bit_utils.h"
#include "casts.h"
#include "enums.h"
#include "globals.h"
#include "macros.h"
#include "value_object.h"

namespace art {

// Memory regions are useful for accessing memory with bounds check in
// debug mode. They can be safely passed by value and do not assume ownership
// of the region.
class MemoryRegion final : public ValueObject {
 public:
  struct ContentEquals {
    constexpr bool operator()(const MemoryRegion& lhs, const MemoryRegion& rhs) const {
      return lhs.size() == rhs.size() && memcmp(lhs.begin(), rhs.begin(), lhs.size()) == 0;
    }
  };

  MemoryRegion() : pointer_(nullptr), size_(0) {}
  MemoryRegion(void* pointer_in, uintptr_t size_in) : pointer_(pointer_in), size_(size_in) {}

  void* pointer() const { return pointer_; }
  size_t size() const { return size_; }
  size_t size_in_bits() const { return size_ * kBitsPerByte; }

  static size_t pointer_offset() {
    return OFFSETOF_MEMBER(MemoryRegion, pointer_);
  }

  uint8_t* begin() const { return reinterpret_cast<uint8_t*>(pointer_); }
  uint8_t* end() const { return begin() + size_; }

  // Load value of type `T` at `offset`.  The memory address corresponding
  // to `offset` should be word-aligned (on ARM, this is a requirement).
  template<typename T>
  ALWAYS_INLINE T Load(uintptr_t offset) const {
    T* address = ComputeInternalPointer<T>(offset);
    DCHECK(IsWordAligned(address));
    return *address;
  }

  // Store `value` (of type `T`) at `offset`.  The memory address
  // corresponding to `offset` should be word-aligned (on ARM, this is
  // a requirement).
  template<typename T>
  ALWAYS_INLINE void Store(uintptr_t offset, T value) const {
    T* address = ComputeInternalPointer<T>(offset);
    DCHECK(IsWordAligned(address));
    *address = value;
  }

  // Load value of type `T` at `offset`.  The memory address corresponding
  // to `offset` does not need to be word-aligned.
  template<typename T>
  ALWAYS_INLINE T LoadUnaligned(uintptr_t offset) const {
    // Equivalent unsigned integer type corresponding to T.
    typedef typename std::make_unsigned<T>::type U;
    U equivalent_unsigned_integer_value = 0;
    // Read the value byte by byte in a little-endian fashion.
    for (size_t i = 0; i < sizeof(U); ++i) {
      equivalent_unsigned_integer_value +=
          *ComputeInternalPointer<uint8_t>(offset + i) << (i * kBitsPerByte);
    }
    return bit_cast<T, U>(equivalent_unsigned_integer_value);
  }

  // Store `value` (of type `T`) at `offset`.  The memory address
  // corresponding to `offset` does not need to be word-aligned.
  template<typename T>
  ALWAYS_INLINE void StoreUnaligned(uintptr_t offset, T value) const {
    // Equivalent unsigned integer type corresponding to T.
    typedef typename std::make_unsigned<T>::type U;
    U equivalent_unsigned_integer_value = bit_cast<U, T>(value);
    // Write the value byte by byte in a little-endian fashion.
    for (size_t i = 0; i < sizeof(U); ++i) {
      *ComputeInternalPointer<uint8_t>(offset + i) =
          (equivalent_unsigned_integer_value >> (i * kBitsPerByte)) & 0xFF;
    }
  }

  template<typename T>
  ALWAYS_INLINE T* PointerTo(uintptr_t offset) const {
    return ComputeInternalPointer<T>(offset);
  }

  void CopyFrom(size_t offset, const MemoryRegion& from) const;

  template<class Vector>
  void CopyFromVector(size_t offset, Vector& vector) const {
    if (!vector.empty()) {
      CopyFrom(offset, MemoryRegion(vector.data(), vector.size()));
    }
  }

  // Compute a sub memory region based on an existing one.
  ALWAYS_INLINE MemoryRegion Subregion(uintptr_t offset, uintptr_t size_in) const {
    CHECK_GE(this->size(), size_in);
    CHECK_LE(offset,  this->size() - size_in);
    return MemoryRegion(reinterpret_cast<void*>(begin() + offset), size_in);
  }

  // Compute an extended memory region based on an existing one.
  ALWAYS_INLINE void Extend(const MemoryRegion& region, uintptr_t extra) {
    pointer_ = region.pointer();
    size_ = (region.size() + extra);
  }

 private:
  template<typename T>
  ALWAYS_INLINE T* ComputeInternalPointer(size_t offset) const {
    CHECK_GE(size(), sizeof(T));
    CHECK_LE(offset, size() - sizeof(T));
    return reinterpret_cast<T*>(begin() + offset);
  }

  // Locate the bit with the given offset. Returns a pointer to the byte
  // containing the bit, and sets bit_mask to the bit within that byte.
  ALWAYS_INLINE uint8_t* ComputeBitPointer(uintptr_t bit_offset, uint8_t* bit_mask) const {
    uintptr_t bit_remainder = (bit_offset & (kBitsPerByte - 1));
    *bit_mask = (1U << bit_remainder);
    uintptr_t byte_offset = (bit_offset >> kBitsPerByteLog2);
    return ComputeInternalPointer<uint8_t>(byte_offset);
  }

  // Is `address` aligned on a machine word?
  template<typename T> static constexpr bool IsWordAligned(const T* address) {
    // Word alignment in bytes.  Determined from pointer size.
    return IsAligned<kRuntimePointerSize>(address);
  }

  void* pointer_;
  size_t size_;
};

}  // namespace art

#endif  // ART_LIBARTBASE_BASE_MEMORY_REGION_H_