stack_map.h revision 12baf476389359d54ae04d7898190ef6f81ab0b2
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 size_t Size() const { 134 return region_.size(); 135 } 136 137 static constexpr int kFixedSize = 0; 138 139 private: 140 MemoryRegion region_; 141}; 142 143/** 144 * A Stack Map holds compilation information for a specific PC necessary for: 145 * - Mapping it to a dex PC, 146 * - Knowing which stack entries are objects, 147 * - Knowing which registers hold objects, 148 * - Knowing the inlining information, 149 * - Knowing the values of dex registers. 150 * 151 * The information is of the form: 152 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask]. 153 * 154 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the 155 * stack size of a method. 156 */ 157class StackMap { 158 public: 159 explicit StackMap(MemoryRegion region) : region_(region) {} 160 161 uint32_t GetDexPc() const { 162 return region_.Load<uint32_t>(kDexPcOffset); 163 } 164 165 void SetDexPc(uint32_t dex_pc) { 166 region_.Store<uint32_t>(kDexPcOffset, dex_pc); 167 } 168 169 uint32_t GetNativePcOffset() const { 170 return region_.Load<uint32_t>(kNativePcOffsetOffset); 171 } 172 173 void SetNativePcOffset(uint32_t native_pc_offset) { 174 return region_.Store<uint32_t>(kNativePcOffsetOffset, native_pc_offset); 175 } 176 177 uint32_t GetDexRegisterMapOffset() const { 178 return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset); 179 } 180 181 void SetDexRegisterMapOffset(uint32_t offset) { 182 return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset); 183 } 184 185 uint32_t GetInlineDescriptorOffset() const { 186 return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset); 187 } 188 189 void SetInlineDescriptorOffset(uint32_t offset) { 190 return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset); 191 } 192 193 uint32_t GetRegisterMask() const { 194 return region_.Load<uint32_t>(kRegisterMaskOffset); 195 } 196 197 void SetRegisterMask(uint32_t mask) { 198 region_.Store<uint32_t>(kRegisterMaskOffset, mask); 199 } 200 201 MemoryRegion GetStackMask() const { 202 return region_.Subregion(kStackMaskOffset, StackMaskSize()); 203 } 204 205 void SetStackMask(const BitVector& sp_map) { 206 MemoryRegion region = GetStackMask(); 207 for (size_t i = 0; i < region.size_in_bits(); i++) { 208 region.StoreBit(i, sp_map.IsBitSet(i)); 209 } 210 } 211 212 bool HasDexRegisterMap() const { 213 return GetDexRegisterMapOffset() != kNoDexRegisterMap; 214 } 215 216 bool HasInlineInfo() const { 217 return GetInlineDescriptorOffset() != kNoInlineInfo; 218 } 219 220 bool Equals(const StackMap& other) const { 221 return region_.pointer() == other.region_.pointer() 222 && region_.size() == other.region_.size(); 223 } 224 225 static size_t ComputeAlignedStackMapSize(size_t stack_mask_size) { 226 // On ARM, the stack maps must be 4-byte aligned. 227 return RoundUp(StackMap::kFixedSize + stack_mask_size, 4); 228 } 229 230 // Special (invalid) offset for the DexRegisterMapOffset field meaning 231 // that there is no Dex register map for this stack map. 232 static constexpr uint32_t kNoDexRegisterMap = -1; 233 234 // Special (invalid) offset for the InlineDescriptorOffset field meaning 235 // that there is no inline info for this stack map. 236 static constexpr uint32_t kNoInlineInfo = -1; 237 238 private: 239 static constexpr int kDexPcOffset = 0; 240 static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t); 241 static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t); 242 static constexpr int kInlineDescriptorOffsetOffset = 243 kDexRegisterMapOffsetOffset + sizeof(uint32_t); 244 static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t); 245 static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t); 246 static constexpr int kStackMaskOffset = kFixedSize; 247 248 size_t StackMaskSize() const { return region_.size() - kFixedSize; } 249 250 MemoryRegion region_; 251 252 friend class CodeInfo; 253 friend class StackMapStream; 254}; 255 256 257/** 258 * Wrapper around all compiler information collected for a method. 259 * The information is of the form: 260 * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*]. 261 */ 262class CodeInfo { 263 public: 264 explicit CodeInfo(MemoryRegion region) : region_(region) {} 265 266 explicit CodeInfo(const void* data) { 267 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0]; 268 region_ = MemoryRegion(const_cast<void*>(data), size); 269 } 270 271 StackMap GetStackMapAt(size_t i) const { 272 size_t size = StackMapSize(); 273 return StackMap(GetStackMaps().Subregion(i * size, size)); 274 } 275 276 uint32_t GetOverallSize() const { 277 return region_.Load<uint32_t>(kOverallSizeOffset); 278 } 279 280 void SetOverallSize(uint32_t size) { 281 region_.Store<uint32_t>(kOverallSizeOffset, size); 282 } 283 284 uint32_t GetStackMaskSize() const { 285 return region_.Load<uint32_t>(kStackMaskSizeOffset); 286 } 287 288 void SetStackMaskSize(uint32_t size) { 289 region_.Store<uint32_t>(kStackMaskSizeOffset, size); 290 } 291 292 size_t GetNumberOfStackMaps() const { 293 return region_.Load<uint32_t>(kNumberOfStackMapsOffset); 294 } 295 296 void SetNumberOfStackMaps(uint32_t number_of_stack_maps) { 297 region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps); 298 } 299 300 size_t StackMapSize() const { 301 return StackMap::ComputeAlignedStackMapSize(GetStackMaskSize()); 302 } 303 304 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) const { 305 DCHECK(stack_map.HasDexRegisterMap()); 306 uint32_t offset = stack_map.GetDexRegisterMapOffset(); 307 return DexRegisterMap(region_.Subregion(offset, 308 DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize())); 309 } 310 311 InlineInfo GetInlineInfoOf(StackMap stack_map) const { 312 DCHECK(stack_map.HasInlineInfo()); 313 uint32_t offset = stack_map.GetInlineDescriptorOffset(); 314 uint8_t depth = region_.Load<uint8_t>(offset); 315 return InlineInfo(region_.Subregion(offset, 316 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize())); 317 } 318 319 StackMap GetStackMapForDexPc(uint32_t dex_pc) const { 320 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { 321 StackMap stack_map = GetStackMapAt(i); 322 if (stack_map.GetDexPc() == dex_pc) { 323 return stack_map; 324 } 325 } 326 LOG(FATAL) << "Unreachable"; 327 UNREACHABLE(); 328 } 329 330 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const { 331 // TODO: stack maps are sorted by native pc, we can do a binary search. 332 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { 333 StackMap stack_map = GetStackMapAt(i); 334 if (stack_map.GetNativePcOffset() == native_pc_offset) { 335 return stack_map; 336 } 337 } 338 LOG(FATAL) << "Unreachable"; 339 UNREACHABLE(); 340 } 341 342 private: 343 static constexpr int kOverallSizeOffset = 0; 344 static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t); 345 static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t); 346 static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t); 347 348 MemoryRegion GetStackMaps() const { 349 return region_.size() == 0 350 ? MemoryRegion() 351 : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps()); 352 } 353 354 MemoryRegion region_; 355 friend class StackMapStream; 356}; 357 358} // namespace art 359 360#endif // ART_RUNTIME_STACK_MAP_H_ 361