diff options
-rw-r--r-- | build/Android.gtest.mk | 1 | ||||
-rw-r--r-- | compiler/optimizing/stack_map_stream.h | 210 | ||||
-rw-r--r-- | compiler/optimizing/stack_map_test.cc | 134 | ||||
-rw-r--r-- | runtime/memory_region.h | 29 | ||||
-rw-r--r-- | runtime/stack_map.h | 307 |
5 files changed, 674 insertions, 7 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index ee51fcd92e..08b78a6542 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -145,6 +145,7 @@ COMPILER_GTEST_COMMON_SRC_FILES := \ compiler/optimizing/pretty_printer_test.cc \ compiler/optimizing/register_allocator_test.cc \ compiler/optimizing/ssa_test.cc \ + compiler/optimizing/stack_map_test.cc \ compiler/output_stream_test.cc \ compiler/utils/arena_allocator_test.cc \ compiler/utils/dedupe_set_test.cc \ diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h new file mode 100644 index 0000000000..3c6ad8fd72 --- /dev/null +++ b/compiler/optimizing/stack_map_stream.h @@ -0,0 +1,210 @@ +/* + * 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_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_ +#define ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_ + +#include "base/bit_vector.h" +#include "memory_region.h" +#include "stack_map.h" +#include "utils/allocation.h" +#include "utils/growable_array.h" + +namespace art { + +/** + * Collects and builds a CodeInfo for a method. + */ +template<typename T> +class StackMapStream : public ValueObject { + public: + explicit StackMapStream(ArenaAllocator* allocator) + : stack_maps_(allocator, 10), + dex_register_maps_(allocator, 10 * 4), + inline_infos_(allocator, 2), + stack_mask_max_(-1) {} + + // Compute bytes needed to encode a mask with the given maximum element. + static uint32_t StackMaskEncodingSize(int max_element) { + int number_of_bits = max_element + 1; // Need room for max element too. + return RoundUp(number_of_bits, kBitsPerByte) / kBitsPerByte; + } + + // See runtime/stack_map.h to know what these fields contain. + struct StackMapEntry { + uint32_t dex_pc; + T native_pc; + uint32_t register_mask; + BitVector* sp_mask; + uint32_t num_dex_registers; + uint8_t inlining_depth; + size_t dex_register_maps_start_index; + size_t inline_infos_start_index; + }; + + struct DexRegisterEntry { + DexRegisterMap::LocationKind kind; + int32_t value; + }; + + struct InlineInfoEntry { + uint32_t method_index; + }; + + void AddStackMapEntry(uint32_t dex_pc, + T native_pc, + uint32_t register_mask, + BitVector* sp_mask, + uint32_t num_dex_registers, + uint8_t inlining_depth) { + StackMapEntry entry; + entry.dex_pc = dex_pc; + entry.native_pc = native_pc; + entry.register_mask = register_mask; + entry.sp_mask = sp_mask; + entry.num_dex_registers = num_dex_registers; + entry.inlining_depth = inlining_depth; + entry.dex_register_maps_start_index = dex_register_maps_.Size(); + entry.inline_infos_start_index = inline_infos_.Size(); + stack_maps_.Add(entry); + + stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet()); + if (inlining_depth > 0) { + number_of_stack_maps_with_inline_info_++; + } + } + + void AddDexRegisterEntry(DexRegisterMap::LocationKind kind, int32_t value) { + DexRegisterEntry entry; + entry.kind = kind; + entry.value = value; + dex_register_maps_.Add(entry); + } + + void AddInlineInfoEntry(uint32_t method_index) { + InlineInfoEntry entry; + entry.method_index = method_index; + inline_infos_.Add(entry); + } + + size_t ComputeNeededSize() const { + return CodeInfo<T>::kFixedSize + + ComputeStackMapSize() + + ComputeDexRegisterMapSize() + + ComputeInlineInfoSize(); + } + + size_t ComputeStackMapSize() const { + return stack_maps_.Size() * (StackMap<T>::kFixedSize + StackMaskEncodingSize(stack_mask_max_)); + } + + size_t ComputeDexRegisterMapSize() const { + // We currently encode all dex register information per stack map. + return stack_maps_.Size() * DexRegisterMap::kFixedSize + // For each dex register entry. + + (dex_register_maps_.Size() * DexRegisterMap::SingleEntrySize()); + } + + size_t ComputeInlineInfoSize() const { + return inline_infos_.Size() * InlineInfo::SingleEntrySize() + // For encoding the depth. + + (number_of_stack_maps_with_inline_info_ * InlineInfo::kFixedSize); + } + + size_t ComputeInlineInfoStart() const { + return ComputeDexRegisterMapStart() + ComputeDexRegisterMapSize(); + } + + size_t ComputeDexRegisterMapStart() const { + return CodeInfo<T>::kFixedSize + ComputeStackMapSize(); + } + + void FillIn(MemoryRegion region) { + CodeInfo<T> code_info(region); + + size_t stack_mask_size = StackMaskEncodingSize(stack_mask_max_); + uint8_t* memory_start = region.start(); + + MemoryRegion dex_register_maps_region = region.Subregion( + ComputeDexRegisterMapStart(), + ComputeDexRegisterMapSize()); + + MemoryRegion inline_infos_region = region.Subregion( + ComputeInlineInfoStart(), + ComputeInlineInfoSize()); + + code_info.SetNumberOfStackMaps(stack_maps_.Size()); + code_info.SetStackMaskSize(stack_mask_size); + + uintptr_t next_dex_register_map_offset = 0; + uintptr_t next_inline_info_offset = 0; + for (size_t i = 0, e = stack_maps_.Size(); i < e; ++i) { + StackMap<T> stack_map = code_info.GetStackMapAt(i); + StackMapEntry entry = stack_maps_.Get(i); + + stack_map.SetDexPc(entry.dex_pc); + stack_map.SetNativePc(entry.native_pc); + stack_map.SetRegisterMask(entry.register_mask); + stack_map.SetStackMask(*entry.sp_mask); + + // Set the register map. + MemoryRegion region = dex_register_maps_region.Subregion( + next_dex_register_map_offset, + DexRegisterMap::kFixedSize + entry.num_dex_registers * DexRegisterMap::SingleEntrySize()); + next_dex_register_map_offset += region.size(); + DexRegisterMap dex_register_map(region); + stack_map.SetDexRegisterMapOffset(region.start() - memory_start); + + for (size_t i = 0; i < entry.num_dex_registers; ++i) { + DexRegisterEntry register_entry = + dex_register_maps_.Get(i + entry.dex_register_maps_start_index); + dex_register_map.SetRegisterInfo(i, register_entry.kind, register_entry.value); + } + + // Set the inlining info. + if (entry.inlining_depth != 0) { + MemoryRegion region = inline_infos_region.Subregion( + next_inline_info_offset, + InlineInfo::kFixedSize + entry.inlining_depth * InlineInfo::SingleEntrySize()); + next_inline_info_offset += region.size(); + InlineInfo inline_info(region); + + stack_map.SetInlineDescriptorOffset(region.start() - memory_start); + + inline_info.SetDepth(entry.inlining_depth); + for (size_t i = 0; i < entry.inlining_depth; ++i) { + InlineInfoEntry inline_entry = inline_infos_.Get(i + entry.inline_infos_start_index); + inline_info.SetMethodReferenceIndexAtDepth(i, inline_entry.method_index); + } + } else { + stack_map.SetInlineDescriptorOffset(InlineInfo::kNoInlineInfo); + } + } + } + + private: + GrowableArray<StackMapEntry> stack_maps_; + GrowableArray<DexRegisterEntry> dex_register_maps_; + GrowableArray<InlineInfoEntry> inline_infos_; + int stack_mask_max_; + size_t number_of_stack_maps_with_inline_info_; + + DISALLOW_COPY_AND_ASSIGN(StackMapStream); +}; + +} // namespace art + +#endif // ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_ diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc new file mode 100644 index 0000000000..a70259e7b9 --- /dev/null +++ b/compiler/optimizing/stack_map_test.cc @@ -0,0 +1,134 @@ +/* + * 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. + */ + +#include "stack_map.h" +#include "stack_map_stream.h" +#include "utils/arena_bit_vector.h" + +#include "gtest/gtest.h" + +namespace art { + +bool SameBits(MemoryRegion region, const BitVector& bit_vector) { + for (size_t i = 0; i < region.size_in_bits(); ++i) { + if (region.LoadBit(i) != bit_vector.IsBitSet(i)) { + return false; + } + } + return true; +} + +TEST(StackMapTest, Test1) { + ArenaPool pool; + ArenaAllocator arena(&pool); + StackMapStream<size_t> stream(&arena); + + ArenaBitVector sp_mask(&arena, 0, false); + stream.AddStackMapEntry(0, 64, 0x3, &sp_mask, 2, 0); + stream.AddDexRegisterEntry(DexRegisterMap::kInStack, 0); + stream.AddDexRegisterEntry(DexRegisterMap::kConstant, -2); + + size_t size = stream.ComputeNeededSize(); + void* memory = arena.Alloc(size, kArenaAllocMisc); + MemoryRegion region(memory, size); + stream.FillIn(region); + + CodeInfo<size_t> code_info(region); + ASSERT_EQ(0u, code_info.GetStackMaskSize()); + ASSERT_EQ(1u, code_info.GetNumberOfStackMaps()); + + StackMap<size_t> stack_map = code_info.GetStackMapAt(0); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePc(64))); + ASSERT_EQ(0u, stack_map.GetDexPc()); + ASSERT_EQ(64u, stack_map.GetNativePc()); + ASSERT_EQ(0x3u, stack_map.GetRegisterMask()); + ASSERT_FALSE(stack_map.HasInlineInfo()); + + MemoryRegion stack_mask = stack_map.GetStackMask(); + ASSERT_TRUE(SameBits(stack_mask, sp_mask)); + + DexRegisterMap dex_registers = code_info.GetDexRegisterMapOf(stack_map, 2); + ASSERT_EQ(DexRegisterMap::kInStack, dex_registers.GetLocationKind(0)); + ASSERT_EQ(DexRegisterMap::kConstant, dex_registers.GetLocationKind(1)); + ASSERT_EQ(0, dex_registers.GetValue(0)); + ASSERT_EQ(-2, dex_registers.GetValue(1)); +} + +TEST(StackMapTest, Test2) { + ArenaPool pool; + ArenaAllocator arena(&pool); + StackMapStream<size_t> stream(&arena); + + ArenaBitVector sp_mask1(&arena, 0, true); + sp_mask1.SetBit(2); + sp_mask1.SetBit(4); + stream.AddStackMapEntry(0, 64, 0x3, &sp_mask1, 2, 2); + stream.AddDexRegisterEntry(DexRegisterMap::kInStack, 0); + stream.AddDexRegisterEntry(DexRegisterMap::kConstant, -2); + stream.AddInlineInfoEntry(42); + stream.AddInlineInfoEntry(82); + + ArenaBitVector sp_mask2(&arena, 0, true); + sp_mask2.SetBit(3); + sp_mask1.SetBit(8); + stream.AddStackMapEntry(1, 128, 0xFF, &sp_mask2, 1, 0); + stream.AddDexRegisterEntry(DexRegisterMap::kInRegister, 0); + + size_t size = stream.ComputeNeededSize(); + void* memory = arena.Alloc(size, kArenaAllocMisc); + MemoryRegion region(memory, size); + stream.FillIn(region); + + CodeInfo<size_t> code_info(region); + ASSERT_EQ(1u, code_info.GetStackMaskSize()); + ASSERT_EQ(2u, code_info.GetNumberOfStackMaps()); + + StackMap<size_t> stack_map = code_info.GetStackMapAt(0); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePc(64))); + ASSERT_EQ(0u, stack_map.GetDexPc()); + ASSERT_EQ(64u, stack_map.GetNativePc()); + ASSERT_EQ(0x3u, stack_map.GetRegisterMask()); + + MemoryRegion stack_mask = stack_map.GetStackMask(); + ASSERT_TRUE(SameBits(stack_mask, sp_mask1)); + + DexRegisterMap dex_registers = code_info.GetDexRegisterMapOf(stack_map, 2); + ASSERT_EQ(DexRegisterMap::kInStack, dex_registers.GetLocationKind(0)); + ASSERT_EQ(DexRegisterMap::kConstant, dex_registers.GetLocationKind(1)); + ASSERT_EQ(0, dex_registers.GetValue(0)); + ASSERT_EQ(-2, dex_registers.GetValue(1)); + + InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); + ASSERT_EQ(2u, inline_info.GetDepth()); + ASSERT_EQ(42u, inline_info.GetMethodReferenceIndexAtDepth(0)); + ASSERT_EQ(82u, inline_info.GetMethodReferenceIndexAtDepth(1)); + + stack_map = code_info.GetStackMapAt(1); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1u))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePc(128u))); + ASSERT_EQ(1u, stack_map.GetDexPc()); + ASSERT_EQ(128u, stack_map.GetNativePc()); + ASSERT_EQ(0xFFu, stack_map.GetRegisterMask()); + + stack_mask = stack_map.GetStackMask(); + ASSERT_TRUE(SameBits(stack_mask, sp_mask2)); + + ASSERT_FALSE(stack_map.HasInlineInfo()); +} + +} // namespace art diff --git a/runtime/memory_region.h b/runtime/memory_region.h index 849ab1c420..bab2e862b9 100644 --- a/runtime/memory_region.h +++ b/runtime/memory_region.h @@ -56,14 +56,31 @@ class MemoryRegion { return ComputeInternalPointer<T>(offset); } + // Load a single bit in the region. The bit at offset 0 is the least + // significant bit in the first byte. + bool LoadBit(uintptr_t bit_offset) const { + uint8_t bit_mask; + uint8_t byte = *ComputeBitPointer(bit_offset, &bit_mask); + return byte & bit_mask; + } + + void StoreBit(uintptr_t bit_offset, bool value) const { + uint8_t bit_mask; + uint8_t* byte = ComputeBitPointer(bit_offset, &bit_mask); + if (value) { + *byte |= bit_mask; + } else { + *byte &= ~bit_mask; + } + } + void CopyFrom(size_t offset, const MemoryRegion& from) const; // Compute a sub memory region based on an existing one. - void Subregion(const MemoryRegion& from, uintptr_t offset, uintptr_t size) { - CHECK_GE(from.size(), size); - CHECK_LE(offset, from.size() - size); - pointer_ = reinterpret_cast<void*>(from.start() + offset); - size_ = size; + MemoryRegion Subregion(uintptr_t offset, uintptr_t size) const { + CHECK_GE(this->size(), size); + CHECK_LE(offset, this->size() - size); + return MemoryRegion(reinterpret_cast<void*>(start() + offset), size); } // Compute an extended memory region based on an existing one. @@ -90,8 +107,6 @@ class MemoryRegion { void* pointer_; size_t size_; - - DISALLOW_COPY_AND_ASSIGN(MemoryRegion); }; } // namespace art 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_ |