308 lines
9.1 KiB
C++
308 lines
9.1 KiB
C++
/*
|
|
* 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_
|