namespace linker { class CodeInfoTableDeduper;
} // namespace linker
class OatQuickMethodHeader; class VariableIndentationOutputStream;
// Size of a frame slot, in bytes. This constant is a signed value, // to please the compiler in arithmetic operations involving int32_t // (signed) values. static constexpr ssize_t kFrameSlotSize = 4;
// The delta compression of dex register maps means we need to scan the stackmaps backwards. // We compress the data in such a way so that there is an upper bound on the search distance. // Max distance 0 means each stack map must be fully defined and no scanning back is allowed. // If this value is changed, the oat file version should be incremented (for DCHECK to pass). static constexpr size_t kMaxDexRegisterMapSearchDistance = 32;
// Information on Dex register locations for a specific PC. // Effectively just a convenience wrapper for DexRegisterLocation vector. // If the size is small enough, it keeps the data on the stack. // TODO: Replace this with generic purpose "small-vector" implementation. class DexRegisterMap { public: using iterator = DexRegisterLocation*; using const_iterator = const DexRegisterLocation*;
// Create map for given number of registers and initialize them to the given value.
DexRegisterMap(size_t count, DexRegisterLocation value) : count_(count), regs_small_{} { if (count_ <= kSmallCount) {
std::fill_n(regs_small_.begin(), count, value);
} else {
regs_large_.resize(count, value);
}
}
private: // Store the data inline if the number of registers is small to avoid memory allocations. // If count_ <= kSmallCount, we use the regs_small_ array, and regs_large_ otherwise. static constexpr size_t kSmallCount = 16;
size_t count_;
std::array<DexRegisterLocation, kSmallCount> regs_small_;
dchecked_vector<DexRegisterLocation> regs_large_;
};
/** *InlineinformationforaspecificPC. *TherowreferencedfromtheStackMapholdsinformationatdepth0. *Followingrowsholdinformationforfurtherdepths.
*/ class InlineInfo : public BitTableAccessor<6> { public:
BIT_TABLE_HEADER(InlineInfo)
BIT_TABLE_COLUMN(0, IsLast) // Determines if there are further rows for further depths.
BIT_TABLE_COLUMN(1, DexPc)
BIT_TABLE_COLUMN(2, MethodInfoIndex)
BIT_TABLE_COLUMN(3, ArtMethodHi) // High bits of ArtMethod*.
BIT_TABLE_COLUMN(4, ArtMethodLo) // Low bits of ArtMethod*.
BIT_TABLE_COLUMN(5, NumberOfDexRegisters) // Includes outer levels and the main method.
static uint32_t UnpackValue(DexRegisterLocation::Kind kind, uint32_t packed_value) {
uint32_t value = packed_value; if (kind == DexRegisterLocation::Kind::kInStack) {
value *= kFrameSlotSize;
} return value;
}
};
// Register masks tend to have many trailing zero bits (caller-saves are usually not encoded), // therefore it is worth encoding the mask as value+shift. class RegisterMask : public BitTableAccessor<2> { public:
BIT_TABLE_HEADER(RegisterMask)
BIT_TABLE_COLUMN(0, Value)
BIT_TABLE_COLUMN(1, Shift)
// Method indices are not very dedup friendly. // Separating them greatly improves dedup efficiency of the other tables. class MethodInfo : public BitTableAccessor<3> { public:
BIT_TABLE_HEADER(MethodInfo)
BIT_TABLE_COLUMN(0, MethodIndex)
BIT_TABLE_COLUMN(1, DexFileIndexKind)
BIT_TABLE_COLUMN(2, DexFileIndex)
// The following methods decode only part of the data. static CodeInfo DecodeGcMasksOnly(const OatQuickMethodHeader* header); static CodeInfo DecodeInlineInfoOnly(const OatQuickMethodHeader* header);
// Returns the dex registers for `stack_map`, ignoring any inlined dex registers.
ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map) const { return GetDexRegisterMapOf(stack_map, /* first= */ 0, number_of_dex_registers_);
}
// Returns the dex register map of `inline_info`, and just those registers.
ALWAYS_INLINE DexRegisterMap GetInlineDexRegisterMapOf(StackMap stack_map,
InlineInfo inline_info) const { if (stack_map.HasDexRegisterMap()) {
DCHECK(stack_map.HasInlineInfoIndex());
uint32_t depth = inline_info.Row() - stack_map.GetInlineInfoIndex(); // The register counts are commutative and include all outer levels. // This allows us to determine the range [first, last) in just two lookups. // If we are at depth 0 (the first inlinee), the count from the main method is used.
uint32_t first = (depth == 0)
? number_of_dex_registers_
: inline_infos_.GetRow(inline_info.Row() - 1).GetNumberOfDexRegisters();
uint32_t last = inline_info.GetNumberOfDexRegisters(); return GetDexRegisterMapOf(stack_map, first, last);
} return DexRegisterMap(0, DexRegisterLocation::None());
}
// Returns the dex register map of `stack_map` in the range the range [first, last).
ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
uint32_t first,
uint32_t last) const { if (stack_map.HasDexRegisterMap()) {
DCHECK_LE(first, last);
DexRegisterMap map(last - first, DexRegisterLocation::Invalid());
DecodeDexRegisterMap(stack_map.Row(), first, &map); return map;
} return DexRegisterMap(0, DexRegisterLocation::None());
}
BitTableRange<InlineInfo> GetInlineInfosOf(StackMap stack_map) const {
uint32_t index = stack_map.GetInlineInfoIndex(); if (index != StackMap::kNoValue) { auto begin = inline_infos_.begin() + index; auto end = begin; while ((*end++).GetIsLast() == InlineInfo::kMore) { } return BitTableRange<InlineInfo>(begin, end);
} else { return BitTableRange<InlineInfo>();
}
}
StackMap GetCatchStackMapForDexPc(ArrayRef<const uint32_t> dex_pcs) const { // Searches the stack map list backwards because catch stack maps are stored at the end. for (size_t i = GetNumberOfStackMaps(); i > 0; --i) {
StackMap stack_map = GetStackMapAt(i - 1); if (UNLIKELY(stack_map.GetKind() != StackMap::Kind::Catch)) { // Early break since we should have catch stack maps only at the end. if (kIsDebugBuild) { for (size_t j = i - 1; j > 0; --j) {
DCHECK(GetStackMapAt(j - 1).GetKind() != StackMap::Kind::Catch);
}
} break;
}
// Both the handler dex_pc and all of the inline dex_pcs have to match i.e. we want dex_pcs to // be [stack_map_dex_pc, inline_dex_pc_1, ..., inline_dex_pc_n]. if (stack_map.GetDexPc() != dex_pcs.front()) { continue;
}
EXPORT StackMap GetStackMapForNativePcOffset(uintptr_t pc,
InstructionSet isa = kRuntimeQuickCodeISA) const;
// Dump this CodeInfo object on `vios`. // `code_offset` is the (absolute) native PC of the compiled method.
EXPORT void Dump(VariableIndentationOutputStream* vios,
uint32_t code_offset, bool verbose,
InstructionSet instruction_set) const;
// Accumulate code info size statistics into the given Stats tree.
EXPORT staticvoid CollectSizeStats(const uint8_t* code_info, /*out*/ Stats& parent);
template <uint32_t kFlag>
ALWAYS_INLINE staticbool HasFlag(const uint8_t* code_info_data) { // Fast path - read just the one specific bit from the header. bool result;
uint8_t varint = (*code_info_data) & MaxInt<uint8_t>(kVarintBits); if (LIKELY(varint <= kVarintMax)) {
result = (varint & kFlag) != 0;
} else {
DCHECK_EQ(varint, kVarintMax + 1); // Only up to 8 flags are supported for now.
constexpr uint32_t bit_offset = kNumHeaders * kVarintBits + WhichPowerOf2(kFlag);
result = (code_info_data[bit_offset / kBitsPerByte] & (1 << bit_offset % kBitsPerByte)) != 0;
} // Slow path - dcheck that we got the correct result against the naive implementation.
BitMemoryReader reader(code_info_data);
DCHECK_EQ(result, (reader.ReadInterleavedVarints<kNumHeaders>()[0] & kFlag) != 0); return result;
}
// NB: The first three flags should be the most common ones. // Maximum of 8 flags is supported right now (see the HasFlag method). enum Flags {
kHasInlineInfo = 1 << 0,
kHasShouldDeoptimizeFlag = 1 << 1,
kIsBaseline = 1 << 2,
kIsDebuggable = 1 << 3,
kIsFast = 1 << 4,
};
// The CodeInfo starts with sequence of variable-length bit-encoded integers. // (Please see kVarintMax for more details about encoding). static constexpr size_t kNumHeaders = 7;
uint32_t flags_ = 0;
uint32_t code_size_ = 0; // The size of native PC range in bytes.
uint32_t packed_frame_size_ = 0; // Frame size in kStackAlignment units.
uint32_t core_spill_mask_ = 0;
uint32_t fp_spill_mask_ = 0;
uint32_t number_of_dex_registers_ = 0;
uint32_t bit_table_flags_ = 0;
// The encoded bit-tables follow the header. Based on the above flags field, // bit-tables might be omitted or replaced by relative bit-offset if deduped. static constexpr size_t kNumBitTables = 8;
BitTable<StackMap> stack_maps_;
BitTable<RegisterMask> register_masks_;
BitTable<StackMask> stack_masks_;
BitTable<InlineInfo> inline_infos_;
BitTable<MethodInfo> method_infos_;
BitTable<DexRegisterMask> dex_register_masks_;
BitTable<DexRegisterMapInfo> dex_register_maps_;
BitTable<DexRegisterInfo> dex_register_catalog_;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.