diff options
Diffstat (limited to 'runtime/stack_map.h')
-rw-r--r-- | runtime/stack_map.h | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/runtime/stack_map.h b/runtime/stack_map.h new file mode 100644 index 0000000000..7d3a48fd88 --- /dev/null +++ b/runtime/stack_map.h @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2014 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_RUNTIME_STACK_MAP_H_ +#define ART_RUNTIME_STACK_MAP_H_ + +#include "base/bit_vector.h" +#include "memory_region.h" + +namespace art { + +/** + * Classes in the following file are wrapper on stack map information backed + * by a MemoryRegion. As such they read and write to the region, they don't have + * their own fields. + */ + +/** + * Inline information for a specific PC. The information is of the form: + * [inlining_depth, [method_dex reference]+] + */ +class InlineInfo { + public: + explicit InlineInfo(MemoryRegion region) : region_(region) {} + + uint8_t GetDepth() const { + return region_.Load<uint8_t>(kDepthOffset); + } + + void SetDepth(uint8_t depth) { + region_.Store<uint8_t>(kDepthOffset, depth); + } + + uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const { + return region_.Load<uint32_t>(kFixedSize + depth * SingleEntrySize()); + } + + void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) { + region_.Store<uint32_t>(kFixedSize + depth * SingleEntrySize(), index); + } + + static size_t SingleEntrySize() { + return sizeof(uint32_t); + } + + private: + static constexpr int kDepthOffset = 0; + static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t); + + static constexpr uint32_t kNoInlineInfo = -1; + + MemoryRegion region_; + + template<typename T> friend class CodeInfo; + template<typename T> friend class StackMap; + template<typename T> friend class StackMapStream; +}; + +/** + * Information on dex register values for a specific PC. The information is + * of the form: + * [location_kind, register_value]+. + * + * The location_kind for a Dex register can either be: + * - Constant: register_value holds the constant, + * - Stack: register_value holds the stack offset, + * - Register: register_value holds the register number. + */ +class DexRegisterMap { + public: + explicit DexRegisterMap(MemoryRegion region) : region_(region) {} + + enum LocationKind { + kInStack, + kInRegister, + kConstant + }; + + LocationKind GetLocationKind(uint16_t register_index) const { + return region_.Load<LocationKind>( + kFixedSize + register_index * SingleEntrySize()); + } + + void SetRegisterInfo(uint16_t register_index, LocationKind kind, int32_t value) { + size_t entry = kFixedSize + register_index * SingleEntrySize(); + region_.Store<LocationKind>(entry, kind); + region_.Store<int32_t>(entry + sizeof(LocationKind), value); + } + + int32_t GetValue(uint16_t register_index) const { + return region_.Load<int32_t>( + kFixedSize + sizeof(LocationKind) + register_index * SingleEntrySize()); + } + + static size_t SingleEntrySize() { + return sizeof(LocationKind) + sizeof(int32_t); + } + + private: + static constexpr int kFixedSize = 0; + + MemoryRegion region_; + + template <typename T> friend class CodeInfo; + template <typename T> friend class StackMapStream; +}; + +/** + * A Stack Map holds compilation information for a specific PC necessary for: + * - Mapping it to a dex PC, + * - Knowing which stack entries are objects, + * - Knowing which registers hold objects, + * - Knowing the inlining information, + * - Knowing the values of dex registers. + * + * The information is of the form: + * [dex_pc, native_pc, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask]. + * + * Note that register_mask is fixed size, but stack_mask is variable size, depending on the + * stack size of a method. + */ +template <typename T> +class StackMap { + public: + explicit StackMap(MemoryRegion region) : region_(region) {} + + uint32_t GetDexPc() const { + return region_.Load<uint32_t>(kDexPcOffset); + } + + void SetDexPc(uint32_t dex_pc) { + region_.Store<uint32_t>(kDexPcOffset, dex_pc); + } + + T GetNativePc() const { + return region_.Load<T>(kNativePcOffset); + } + + void SetNativePc(T native_pc) { + return region_.Store<T>(kNativePcOffset, native_pc); + } + + uint32_t GetDexRegisterMapOffset() const { + return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset); + } + + void SetDexRegisterMapOffset(uint32_t offset) { + return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset); + } + + uint32_t GetInlineDescriptorOffset() const { + return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset); + } + + void SetInlineDescriptorOffset(uint32_t offset) { + return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset); + } + + uint32_t GetRegisterMask() const { + return region_.Load<uint32_t>(kRegisterMaskOffset); + } + + void SetRegisterMask(uint32_t mask) { + region_.Store<uint32_t>(kRegisterMaskOffset, mask); + } + + MemoryRegion GetStackMask() const { + return region_.Subregion(kStackMaskOffset, StackMaskSize()); + } + + void SetStackMask(const BitVector& sp_map) { + MemoryRegion region = GetStackMask(); + for (size_t i = 0; i < region.size_in_bits(); i++) { + region.StoreBit(i, sp_map.IsBitSet(i)); + } + } + + bool HasInlineInfo() const { + return GetInlineDescriptorOffset() != InlineInfo::kNoInlineInfo; + } + + bool Equals(const StackMap& other) { + return region_.pointer() == other.region_.pointer() + && region_.size() == other.region_.size(); + } + + private: + static constexpr int kDexPcOffset = 0; + static constexpr int kNativePcOffset = kDexPcOffset + sizeof(uint32_t); + static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffset + sizeof(T); + static constexpr int kInlineDescriptorOffsetOffset = + kDexRegisterMapOffsetOffset + sizeof(uint32_t); + static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t); + static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t); + static constexpr int kStackMaskOffset = kFixedSize; + + size_t StackMaskSize() const { return region_.size() - kFixedSize; } + + MemoryRegion region_; + + template <typename U> friend class CodeInfo; + template <typename U> friend class StackMapStream; +}; + + +/** + * Wrapper around all compiler information collected for a method. + * The information is of the form: + * [number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*]. + */ +template <typename T> +class CodeInfo { + public: + explicit CodeInfo(MemoryRegion region) : region_(region) {} + + StackMap<T> GetStackMapAt(size_t i) const { + size_t size = StackMapSize(); + return StackMap<T>(GetStackMaps().Subregion(i * size, size)); + } + + uint32_t GetStackMaskSize() const { + return region_.Load<uint32_t>(kStackMaskSizeOffset); + } + + void SetStackMaskSize(uint32_t size) { + region_.Store<uint32_t>(kStackMaskSizeOffset, size); + } + + size_t GetNumberOfStackMaps() const { + return region_.Load<uint32_t>(kNumberOfStackMapsOffset); + } + + void SetNumberOfStackMaps(uint32_t number_of_stack_maps) { + region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps); + } + + size_t StackMapSize() const { + return StackMap<T>::kFixedSize + GetStackMaskSize(); + } + + DexRegisterMap GetDexRegisterMapOf(StackMap<T> stack_map, uint32_t number_of_dex_registers) { + uint32_t offset = stack_map.GetDexRegisterMapOffset(); + return DexRegisterMap(region_.Subregion(offset, + DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize())); + } + + InlineInfo GetInlineInfoOf(StackMap<T> stack_map) { + uint32_t offset = stack_map.GetInlineDescriptorOffset(); + uint8_t depth = region_.Load<uint8_t>(offset); + return InlineInfo(region_.Subregion(offset, + InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize())); + } + + StackMap<T> GetStackMapForDexPc(uint32_t dex_pc) { + for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { + StackMap<T> stack_map = GetStackMapAt(i); + if (stack_map.GetDexPc() == dex_pc) { + return stack_map; + } + } + LOG(FATAL) << "Unreachable"; + return StackMap<T>(MemoryRegion()); + } + + StackMap<T> GetStackMapForNativePc(T native_pc) { + // TODO: stack maps are sorted by native pc, we can do a binary search. + for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { + StackMap<T> stack_map = GetStackMapAt(i); + if (stack_map.GetNativePc() == native_pc) { + return stack_map; + } + } + LOG(FATAL) << "Unreachable"; + return StackMap<T>(MemoryRegion()); + } + + private: + static constexpr int kNumberOfStackMapsOffset = 0; + static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t); + static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t); + + MemoryRegion GetStackMaps() const { + return region_.size() == 0 + ? MemoryRegion() + : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps()); + } + + MemoryRegion region_; + template<typename U> friend class StackMapStream; +}; + +} // namespace art + +#endif // ART_RUNTIME_STACK_MAP_H_ |