stack_map.h revision 442b46a087c389a91a0b51547ac9205058432364
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#include "utils.h" 23 24namespace art { 25 26/** 27 * Classes in the following file are wrapper on stack map information backed 28 * by a MemoryRegion. As such they read and write to the region, they don't have 29 * their own fields. 30 */ 31 32/** 33 * Inline information for a specific PC. The information is of the form: 34 * [inlining_depth, [method_dex reference]+] 35 */ 36class InlineInfo { 37 public: 38 explicit InlineInfo(MemoryRegion region) : region_(region) {} 39 40 uint8_t GetDepth() const { 41 return region_.Load<uint8_t>(kDepthOffset); 42 } 43 44 void SetDepth(uint8_t depth) { 45 region_.Store<uint8_t>(kDepthOffset, depth); 46 } 47 48 uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const { 49 return region_.Load<uint32_t>(kFixedSize + depth * SingleEntrySize()); 50 } 51 52 void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) { 53 region_.Store<uint32_t>(kFixedSize + depth * SingleEntrySize(), index); 54 } 55 56 static size_t SingleEntrySize() { 57 return sizeof(uint32_t); 58 } 59 60 private: 61 static constexpr int kDepthOffset = 0; 62 static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t); 63 64 MemoryRegion region_; 65 66 friend class CodeInfo; 67 friend class StackMap; 68 friend class StackMapStream; 69}; 70 71/** 72 * Information on dex register values for a specific PC. The information is 73 * of the form: 74 * [location_kind, register_value]+. 75 * 76 * The location_kind for a Dex register can either be: 77 * - kConstant: register_value holds the constant, 78 * - kStack: register_value holds the stack offset, 79 * - kRegister: register_value holds the physical register number. 80 * - kFpuRegister: register_value holds the physical register number. 81 * - kNone: the register has no location yet, meaning it has not been set. 82 */ 83class DexRegisterMap { 84 public: 85 explicit DexRegisterMap(MemoryRegion region) : region_(region) {} 86 87 enum LocationKind { 88 kNone, 89 kInStack, 90 kInRegister, 91 kInFpuRegister, 92 kConstant 93 }; 94 95 static const char* PrettyDescriptor(LocationKind kind) { 96 switch (kind) { 97 case kNone: 98 return "none"; 99 case kInStack: 100 return "in stack"; 101 case kInRegister: 102 return "in register"; 103 case kInFpuRegister: 104 return "in fpu register"; 105 case kConstant: 106 return "as constant"; 107 default: 108 LOG(FATAL) << "Invalid location kind " << static_cast<int>(kind); 109 return nullptr; 110 } 111 } 112 113 LocationKind GetLocationKind(uint16_t register_index) const { 114 return region_.Load<LocationKind>( 115 kFixedSize + register_index * SingleEntrySize()); 116 } 117 118 void SetRegisterInfo(uint16_t register_index, LocationKind kind, int32_t value) { 119 size_t entry = kFixedSize + register_index * SingleEntrySize(); 120 region_.Store<LocationKind>(entry, kind); 121 region_.Store<int32_t>(entry + sizeof(LocationKind), value); 122 } 123 124 int32_t GetValue(uint16_t register_index) const { 125 return region_.Load<int32_t>( 126 kFixedSize + sizeof(LocationKind) + register_index * SingleEntrySize()); 127 } 128 129 static size_t SingleEntrySize() { 130 return sizeof(LocationKind) + sizeof(int32_t); 131 } 132 133 private: 134 static constexpr int kFixedSize = 0; 135 136 MemoryRegion region_; 137 138 friend class CodeInfo; 139 friend class StackMapStream; 140}; 141 142/** 143 * A Stack Map holds compilation information for a specific PC necessary for: 144 * - Mapping it to a dex PC, 145 * - Knowing which stack entries are objects, 146 * - Knowing which registers hold objects, 147 * - Knowing the inlining information, 148 * - Knowing the values of dex registers. 149 * 150 * The information is of the form: 151 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask]. 152 * 153 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the 154 * stack size of a method. 155 */ 156class StackMap { 157 public: 158 explicit StackMap(MemoryRegion region) : region_(region) {} 159 160 uint32_t GetDexPc() const { 161 return region_.Load<uint32_t>(kDexPcOffset); 162 } 163 164 void SetDexPc(uint32_t dex_pc) { 165 region_.Store<uint32_t>(kDexPcOffset, dex_pc); 166 } 167 168 uint32_t GetNativePcOffset() const { 169 return region_.Load<uint32_t>(kNativePcOffsetOffset); 170 } 171 172 void SetNativePcOffset(uint32_t native_pc_offset) { 173 return region_.Store<uint32_t>(kNativePcOffsetOffset, native_pc_offset); 174 } 175 176 uint32_t GetDexRegisterMapOffset() const { 177 return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset); 178 } 179 180 void SetDexRegisterMapOffset(uint32_t offset) { 181 return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset); 182 } 183 184 uint32_t GetInlineDescriptorOffset() const { 185 return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset); 186 } 187 188 void SetInlineDescriptorOffset(uint32_t offset) { 189 return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset); 190 } 191 192 uint32_t GetRegisterMask() const { 193 return region_.Load<uint32_t>(kRegisterMaskOffset); 194 } 195 196 void SetRegisterMask(uint32_t mask) { 197 region_.Store<uint32_t>(kRegisterMaskOffset, mask); 198 } 199 200 MemoryRegion GetStackMask() const { 201 return region_.Subregion(kStackMaskOffset, StackMaskSize()); 202 } 203 204 void SetStackMask(const BitVector& sp_map) { 205 MemoryRegion region = GetStackMask(); 206 for (size_t i = 0; i < region.size_in_bits(); i++) { 207 region.StoreBit(i, sp_map.IsBitSet(i)); 208 } 209 } 210 211 bool HasDexRegisterMap() const { 212 return GetDexRegisterMapOffset() != kNoDexRegisterMap; 213 } 214 215 bool HasInlineInfo() const { 216 return GetInlineDescriptorOffset() != kNoInlineInfo; 217 } 218 219 bool Equals(const StackMap& other) const { 220 return region_.pointer() == other.region_.pointer() 221 && region_.size() == other.region_.size(); 222 } 223 224 static size_t ComputeAlignedStackMapSize(size_t stack_mask_size) { 225 // On ARM, the stack maps must be 4-byte aligned. 226 return RoundUp(StackMap::kFixedSize + stack_mask_size, 4); 227 } 228 229 // Special (invalid) offset for the DexRegisterMapOffset field meaning 230 // that there is no Dex register map for this stack map. 231 static constexpr uint32_t kNoDexRegisterMap = -1; 232 233 // Special (invalid) offset for the InlineDescriptorOffset field meaning 234 // that there is no inline info for this stack map. 235 static constexpr uint32_t kNoInlineInfo = -1; 236 237 private: 238 static constexpr int kDexPcOffset = 0; 239 static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t); 240 static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t); 241 static constexpr int kInlineDescriptorOffsetOffset = 242 kDexRegisterMapOffsetOffset + sizeof(uint32_t); 243 static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t); 244 static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t); 245 static constexpr int kStackMaskOffset = kFixedSize; 246 247 size_t StackMaskSize() const { return region_.size() - kFixedSize; } 248 249 MemoryRegion region_; 250 251 friend class CodeInfo; 252 friend class StackMapStream; 253}; 254 255 256/** 257 * Wrapper around all compiler information collected for a method. 258 * The information is of the form: 259 * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*]. 260 */ 261class CodeInfo { 262 public: 263 explicit CodeInfo(MemoryRegion region) : region_(region) {} 264 265 explicit CodeInfo(const void* data) { 266 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0]; 267 region_ = MemoryRegion(const_cast<void*>(data), size); 268 } 269 270 StackMap GetStackMapAt(size_t i) const { 271 size_t size = StackMapSize(); 272 return StackMap(GetStackMaps().Subregion(i * size, size)); 273 } 274 275 uint32_t GetOverallSize() const { 276 return region_.Load<uint32_t>(kOverallSizeOffset); 277 } 278 279 void SetOverallSize(uint32_t size) { 280 region_.Store<uint32_t>(kOverallSizeOffset, size); 281 } 282 283 uint32_t GetStackMaskSize() const { 284 return region_.Load<uint32_t>(kStackMaskSizeOffset); 285 } 286 287 void SetStackMaskSize(uint32_t size) { 288 region_.Store<uint32_t>(kStackMaskSizeOffset, size); 289 } 290 291 size_t GetNumberOfStackMaps() const { 292 return region_.Load<uint32_t>(kNumberOfStackMapsOffset); 293 } 294 295 void SetNumberOfStackMaps(uint32_t number_of_stack_maps) { 296 region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps); 297 } 298 299 size_t StackMapSize() const { 300 return StackMap::ComputeAlignedStackMapSize(GetStackMaskSize()); 301 } 302 303 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) const { 304 DCHECK(stack_map.HasDexRegisterMap()); 305 uint32_t offset = stack_map.GetDexRegisterMapOffset(); 306 return DexRegisterMap(region_.Subregion(offset, 307 DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize())); 308 } 309 310 InlineInfo GetInlineInfoOf(StackMap stack_map) const { 311 DCHECK(stack_map.HasInlineInfo()); 312 uint32_t offset = stack_map.GetInlineDescriptorOffset(); 313 uint8_t depth = region_.Load<uint8_t>(offset); 314 return InlineInfo(region_.Subregion(offset, 315 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize())); 316 } 317 318 StackMap GetStackMapForDexPc(uint32_t dex_pc) const { 319 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { 320 StackMap stack_map = GetStackMapAt(i); 321 if (stack_map.GetDexPc() == dex_pc) { 322 return stack_map; 323 } 324 } 325 LOG(FATAL) << "Unreachable"; 326 UNREACHABLE(); 327 } 328 329 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const { 330 // TODO: stack maps are sorted by native pc, we can do a binary search. 331 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { 332 StackMap stack_map = GetStackMapAt(i); 333 if (stack_map.GetNativePcOffset() == native_pc_offset) { 334 return stack_map; 335 } 336 } 337 LOG(FATAL) << "Unreachable"; 338 UNREACHABLE(); 339 } 340 341 private: 342 static constexpr int kOverallSizeOffset = 0; 343 static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t); 344 static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t); 345 static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t); 346 347 MemoryRegion GetStackMaps() const { 348 return region_.size() == 0 349 ? MemoryRegion() 350 : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps()); 351 } 352 353 MemoryRegion region_; 354 friend class StackMapStream; 355}; 356 357} // namespace art 358 359#endif // ART_RUNTIME_STACK_MAP_H_ 360