1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_RUNTIME_STACK_MAP_H_ 18 #define ART_RUNTIME_STACK_MAP_H_ 19 20 #include "base/bit_vector.h" 21 #include "memory_region.h" 22 23 namespace art { 24 25 /** 26 * Classes in the following file are wrapper on stack map information backed 27 * by a MemoryRegion. As such they read and write to the region, they don't have 28 * their own fields. 29 */ 30 31 /** 32 * Inline information for a specific PC. The information is of the form: 33 * [inlining_depth, [method_dex reference]+] 34 */ 35 class InlineInfo { 36 public: InlineInfo(MemoryRegion region)37 explicit InlineInfo(MemoryRegion region) : region_(region) {} 38 GetDepth()39 uint8_t GetDepth() const { 40 return region_.Load<uint8_t>(kDepthOffset); 41 } 42 SetDepth(uint8_t depth)43 void SetDepth(uint8_t depth) { 44 region_.Store<uint8_t>(kDepthOffset, depth); 45 } 46 GetMethodReferenceIndexAtDepth(uint8_t depth)47 uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const { 48 return region_.Load<uint32_t>(kFixedSize + depth * SingleEntrySize()); 49 } 50 SetMethodReferenceIndexAtDepth(uint8_t depth,uint32_t index)51 void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) { 52 region_.Store<uint32_t>(kFixedSize + depth * SingleEntrySize(), index); 53 } 54 SingleEntrySize()55 static size_t SingleEntrySize() { 56 return sizeof(uint32_t); 57 } 58 59 private: 60 static constexpr int kDepthOffset = 0; 61 static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t); 62 63 static constexpr uint32_t kNoInlineInfo = -1; 64 65 MemoryRegion region_; 66 67 template<typename T> friend class CodeInfo; 68 template<typename T> friend class StackMap; 69 template<typename T> friend class StackMapStream; 70 }; 71 72 /** 73 * Information on dex register values for a specific PC. The information is 74 * of the form: 75 * [location_kind, register_value]+. 76 * 77 * The location_kind for a Dex register can either be: 78 * - Constant: register_value holds the constant, 79 * - Stack: register_value holds the stack offset, 80 * - Register: register_value holds the register number. 81 */ 82 class DexRegisterMap { 83 public: DexRegisterMap(MemoryRegion region)84 explicit DexRegisterMap(MemoryRegion region) : region_(region) {} 85 86 enum LocationKind { 87 kInStack, 88 kInRegister, 89 kConstant 90 }; 91 GetLocationKind(uint16_t register_index)92 LocationKind GetLocationKind(uint16_t register_index) const { 93 return region_.Load<LocationKind>( 94 kFixedSize + register_index * SingleEntrySize()); 95 } 96 SetRegisterInfo(uint16_t register_index,LocationKind kind,int32_t value)97 void SetRegisterInfo(uint16_t register_index, LocationKind kind, int32_t value) { 98 size_t entry = kFixedSize + register_index * SingleEntrySize(); 99 region_.Store<LocationKind>(entry, kind); 100 region_.Store<int32_t>(entry + sizeof(LocationKind), value); 101 } 102 GetValue(uint16_t register_index)103 int32_t GetValue(uint16_t register_index) const { 104 return region_.Load<int32_t>( 105 kFixedSize + sizeof(LocationKind) + register_index * SingleEntrySize()); 106 } 107 SingleEntrySize()108 static size_t SingleEntrySize() { 109 return sizeof(LocationKind) + sizeof(int32_t); 110 } 111 112 private: 113 static constexpr int kFixedSize = 0; 114 115 MemoryRegion region_; 116 117 template <typename T> friend class CodeInfo; 118 template <typename T> friend class StackMapStream; 119 }; 120 121 /** 122 * A Stack Map holds compilation information for a specific PC necessary for: 123 * - Mapping it to a dex PC, 124 * - Knowing which stack entries are objects, 125 * - Knowing which registers hold objects, 126 * - Knowing the inlining information, 127 * - Knowing the values of dex registers. 128 * 129 * The information is of the form: 130 * [dex_pc, native_pc, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask]. 131 * 132 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the 133 * stack size of a method. 134 */ 135 template <typename T> 136 class StackMap { 137 public: StackMap(MemoryRegion region)138 explicit StackMap(MemoryRegion region) : region_(region) {} 139 GetDexPc()140 uint32_t GetDexPc() const { 141 return region_.Load<uint32_t>(kDexPcOffset); 142 } 143 SetDexPc(uint32_t dex_pc)144 void SetDexPc(uint32_t dex_pc) { 145 region_.Store<uint32_t>(kDexPcOffset, dex_pc); 146 } 147 GetNativePc()148 T GetNativePc() const { 149 return region_.Load<T>(kNativePcOffset); 150 } 151 SetNativePc(T native_pc)152 void SetNativePc(T native_pc) { 153 return region_.Store<T>(kNativePcOffset, native_pc); 154 } 155 GetDexRegisterMapOffset()156 uint32_t GetDexRegisterMapOffset() const { 157 return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset); 158 } 159 SetDexRegisterMapOffset(uint32_t offset)160 void SetDexRegisterMapOffset(uint32_t offset) { 161 return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset); 162 } 163 GetInlineDescriptorOffset()164 uint32_t GetInlineDescriptorOffset() const { 165 return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset); 166 } 167 SetInlineDescriptorOffset(uint32_t offset)168 void SetInlineDescriptorOffset(uint32_t offset) { 169 return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset); 170 } 171 GetRegisterMask()172 uint32_t GetRegisterMask() const { 173 return region_.Load<uint32_t>(kRegisterMaskOffset); 174 } 175 SetRegisterMask(uint32_t mask)176 void SetRegisterMask(uint32_t mask) { 177 region_.Store<uint32_t>(kRegisterMaskOffset, mask); 178 } 179 GetStackMask()180 MemoryRegion GetStackMask() const { 181 return region_.Subregion(kStackMaskOffset, StackMaskSize()); 182 } 183 SetStackMask(const BitVector & sp_map)184 void SetStackMask(const BitVector& sp_map) { 185 MemoryRegion region = GetStackMask(); 186 for (size_t i = 0; i < region.size_in_bits(); i++) { 187 region.StoreBit(i, sp_map.IsBitSet(i)); 188 } 189 } 190 HasInlineInfo()191 bool HasInlineInfo() const { 192 return GetInlineDescriptorOffset() != InlineInfo::kNoInlineInfo; 193 } 194 Equals(const StackMap & other)195 bool Equals(const StackMap& other) { 196 return region_.pointer() == other.region_.pointer() 197 && region_.size() == other.region_.size(); 198 } 199 200 private: 201 static constexpr int kDexPcOffset = 0; 202 static constexpr int kNativePcOffset = kDexPcOffset + sizeof(uint32_t); 203 static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffset + sizeof(T); 204 static constexpr int kInlineDescriptorOffsetOffset = 205 kDexRegisterMapOffsetOffset + sizeof(uint32_t); 206 static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t); 207 static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t); 208 static constexpr int kStackMaskOffset = kFixedSize; 209 StackMaskSize()210 size_t StackMaskSize() const { return region_.size() - kFixedSize; } 211 212 MemoryRegion region_; 213 214 template <typename U> friend class CodeInfo; 215 template <typename U> friend class StackMapStream; 216 }; 217 218 219 /** 220 * Wrapper around all compiler information collected for a method. 221 * The information is of the form: 222 * [number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*]. 223 */ 224 template <typename T> 225 class CodeInfo { 226 public: CodeInfo(MemoryRegion region)227 explicit CodeInfo(MemoryRegion region) : region_(region) {} 228 GetStackMapAt(size_t i)229 StackMap<T> GetStackMapAt(size_t i) const { 230 size_t size = StackMapSize(); 231 return StackMap<T>(GetStackMaps().Subregion(i * size, size)); 232 } 233 GetStackMaskSize()234 uint32_t GetStackMaskSize() const { 235 return region_.Load<uint32_t>(kStackMaskSizeOffset); 236 } 237 SetStackMaskSize(uint32_t size)238 void SetStackMaskSize(uint32_t size) { 239 region_.Store<uint32_t>(kStackMaskSizeOffset, size); 240 } 241 GetNumberOfStackMaps()242 size_t GetNumberOfStackMaps() const { 243 return region_.Load<uint32_t>(kNumberOfStackMapsOffset); 244 } 245 SetNumberOfStackMaps(uint32_t number_of_stack_maps)246 void SetNumberOfStackMaps(uint32_t number_of_stack_maps) { 247 region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps); 248 } 249 StackMapSize()250 size_t StackMapSize() const { 251 return StackMap<T>::kFixedSize + GetStackMaskSize(); 252 } 253 GetDexRegisterMapOf(StackMap<T> stack_map,uint32_t number_of_dex_registers)254 DexRegisterMap GetDexRegisterMapOf(StackMap<T> stack_map, uint32_t number_of_dex_registers) { 255 uint32_t offset = stack_map.GetDexRegisterMapOffset(); 256 return DexRegisterMap(region_.Subregion(offset, 257 DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize())); 258 } 259 GetInlineInfoOf(StackMap<T> stack_map)260 InlineInfo GetInlineInfoOf(StackMap<T> stack_map) { 261 uint32_t offset = stack_map.GetInlineDescriptorOffset(); 262 uint8_t depth = region_.Load<uint8_t>(offset); 263 return InlineInfo(region_.Subregion(offset, 264 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize())); 265 } 266 GetStackMapForDexPc(uint32_t dex_pc)267 StackMap<T> GetStackMapForDexPc(uint32_t dex_pc) { 268 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { 269 StackMap<T> stack_map = GetStackMapAt(i); 270 if (stack_map.GetDexPc() == dex_pc) { 271 return stack_map; 272 } 273 } 274 LOG(FATAL) << "Unreachable"; 275 return StackMap<T>(MemoryRegion()); 276 } 277 GetStackMapForNativePc(T native_pc)278 StackMap<T> GetStackMapForNativePc(T native_pc) { 279 // TODO: stack maps are sorted by native pc, we can do a binary search. 280 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { 281 StackMap<T> stack_map = GetStackMapAt(i); 282 if (stack_map.GetNativePc() == native_pc) { 283 return stack_map; 284 } 285 } 286 LOG(FATAL) << "Unreachable"; 287 return StackMap<T>(MemoryRegion()); 288 } 289 290 private: 291 static constexpr int kNumberOfStackMapsOffset = 0; 292 static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t); 293 static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t); 294 GetStackMaps()295 MemoryRegion GetStackMaps() const { 296 return region_.size() == 0 297 ? MemoryRegion() 298 : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps()); 299 } 300 301 MemoryRegion region_; 302 template<typename U> friend class StackMapStream; 303 }; 304 305 } // namespace art 306 307 #endif // ART_RUNTIME_STACK_MAP_H_ 308