blob: 514d30ed0c99077dfc2de1cd757ea4044e4f193e [file] [log] [blame]
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001/*
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
Andreas Gampe69489fa2017-06-08 18:03:25 -070020#include <limits>
21
David Srbeckyf6ba5b32018-06-23 22:05:49 +010022#include "arch/instruction_set.h"
Santiago Aboy Solanesab1d5592022-06-24 11:16:35 +010023#include "base/array_ref.h"
David Sehr1ce2b3b2018-04-05 11:02:03 -070024#include "base/bit_memory_region.h"
David Srbecky052f8ca2018-04-26 15:42:54 +010025#include "base/bit_table.h"
Vladimir Marko80afd022015-05-19 18:08:00 +010026#include "base/bit_utils.h"
Santiago Aboy Solanesab1d5592022-06-24 11:16:35 +010027#include "base/globals.h"
28#include "base/logging.h"
David Sehr1ce2b3b2018-04-05 11:02:03 -070029#include "base/memory_region.h"
David Sehr9e734c72018-01-04 17:56:19 -080030#include "dex/dex_file_types.h"
David Srbecky71ec1cc2018-05-18 15:57:25 +010031#include "dex_register_location.h"
David Srbeckyf6ba5b32018-06-23 22:05:49 +010032#include "quick/quick_method_frame_info.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010033
34namespace art {
35
Vladimir Markoe4ccbb52022-03-15 08:51:33 +000036namespace linker {
37class CodeInfoTableDeduper;
38} // namespace linker
39
David Srbeckyf6ba5b32018-06-23 22:05:49 +010040class OatQuickMethodHeader;
Vladimir Marko8f1e08a2015-06-26 12:06:30 +010041class VariableIndentationOutputStream;
42
Roland Levillaina2d8ec62015-03-12 15:25:29 +000043// Size of a frame slot, in bytes. This constant is a signed value,
44// to please the compiler in arithmetic operations involving int32_t
45// (signed) values.
Roland Levillaina552e1c2015-03-26 15:01:03 +000046static constexpr ssize_t kFrameSlotSize = 4;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000047
David Srbecky6de88332018-06-03 12:00:11 +010048// The delta compression of dex register maps means we need to scan the stackmaps backwards.
49// We compress the data in such a way so that there is an upper bound on the search distance.
50// Max distance 0 means each stack map must be fully defined and no scanning back is allowed.
51// If this value is changed, the oat file version should be incremented (for DCHECK to pass).
52static constexpr size_t kMaxDexRegisterMapSearchDistance = 32;
53
Nicolas Geoffray5d37c152017-01-12 13:25:19 +000054class ArtMethod;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000055class CodeInfo;
David Srbecky86decb62018-06-05 06:41:10 +010056class Stats;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000057
David Srbecky71ec1cc2018-05-18 15:57:25 +010058std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010059
David Srbecky71ec1cc2018-05-18 15:57:25 +010060// Information on Dex register locations for a specific PC.
61// Effectively just a convenience wrapper for DexRegisterLocation vector.
62// If the size is small enough, it keeps the data on the stack.
David Srbeckye1402122018-06-13 18:20:45 +010063// TODO: Replace this with generic purpose "small-vector" implementation.
Roland Levillaina552e1c2015-03-26 15:01:03 +000064class DexRegisterMap {
65 public:
David Srbecky6de88332018-06-03 12:00:11 +010066 using iterator = DexRegisterLocation*;
David Srbeckye1402122018-06-13 18:20:45 +010067 using const_iterator = const DexRegisterLocation*;
David Srbecky6de88332018-06-03 12:00:11 +010068
69 // Create map for given number of registers and initialize them to the given value.
70 DexRegisterMap(size_t count, DexRegisterLocation value) : count_(count), regs_small_{} {
David Srbecky71ec1cc2018-05-18 15:57:25 +010071 if (count_ <= kSmallCount) {
David Srbecky6de88332018-06-03 12:00:11 +010072 std::fill_n(regs_small_.begin(), count, value);
David Srbecky71ec1cc2018-05-18 15:57:25 +010073 } else {
David Srbecky6de88332018-06-03 12:00:11 +010074 regs_large_.resize(count, value);
David Srbecky71ec1cc2018-05-18 15:57:25 +010075 }
Roland Levillaina552e1c2015-03-26 15:01:03 +000076 }
77
David Srbecky71ec1cc2018-05-18 15:57:25 +010078 DexRegisterLocation* data() {
79 return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
80 }
David Srbeckye1402122018-06-13 18:20:45 +010081 const DexRegisterLocation* data() const {
82 return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
83 }
Roland Levillaina552e1c2015-03-26 15:01:03 +000084
David Srbecky6de88332018-06-03 12:00:11 +010085 iterator begin() { return data(); }
86 iterator end() { return data() + count_; }
David Srbeckye1402122018-06-13 18:20:45 +010087 const_iterator begin() const { return data(); }
88 const_iterator end() const { return data() + count_; }
David Srbecky71ec1cc2018-05-18 15:57:25 +010089 size_t size() const { return count_; }
David Srbeckyfd89b072018-06-03 12:00:22 +010090 bool empty() const { return count_ == 0; }
David Srbecky71ec1cc2018-05-18 15:57:25 +010091
David Srbeckye1402122018-06-13 18:20:45 +010092 DexRegisterLocation& operator[](size_t index) {
David Srbecky71ec1cc2018-05-18 15:57:25 +010093 DCHECK_LT(index, count_);
David Srbeckye1402122018-06-13 18:20:45 +010094 return data()[index];
David Srbecky71ec1cc2018-05-18 15:57:25 +010095 }
David Srbeckye1402122018-06-13 18:20:45 +010096 const DexRegisterLocation& operator[](size_t index) const {
97 DCHECK_LT(index, count_);
98 return data()[index];
Roland Levillaina552e1c2015-03-26 15:01:03 +000099 }
100
David Srbecky71ec1cc2018-05-18 15:57:25 +0100101 size_t GetNumberOfLiveDexRegisters() const {
David Srbeckye1402122018-06-13 18:20:45 +0100102 return std::count_if(begin(), end(), [](auto& loc) { return loc.IsLive(); });
Roland Levillaina552e1c2015-03-26 15:01:03 +0000103 }
104
David Srbecky71ec1cc2018-05-18 15:57:25 +0100105 bool HasAnyLiveDexRegisters() const {
David Srbeckye1402122018-06-13 18:20:45 +0100106 return std::any_of(begin(), end(), [](auto& loc) { return loc.IsLive(); });
David Srbecky21d45b42018-05-30 06:35:05 +0100107 }
108
David Srbeckye1402122018-06-13 18:20:45 +0100109 void Dump(VariableIndentationOutputStream* vios) const;
110
Roland Levillaina552e1c2015-03-26 15:01:03 +0000111 private:
David Srbecky71ec1cc2018-05-18 15:57:25 +0100112 // Store the data inline if the number of registers is small to avoid memory allocations.
113 // If count_ <= kSmallCount, we use the regs_small_ array, and regs_large_ otherwise.
114 static constexpr size_t kSmallCount = 16;
115 size_t count_;
116 std::array<DexRegisterLocation, kSmallCount> regs_small_;
117 dchecked_vector<DexRegisterLocation> regs_large_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000118};
119
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100120/**
121 * A Stack Map holds compilation information for a specific PC necessary for:
122 * - Mapping it to a dex PC,
123 * - Knowing which stack entries are objects,
124 * - Knowing which registers hold objects,
125 * - Knowing the inlining information,
126 * - Knowing the values of dex registers.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100127 */
David Srbeckycf7833e2018-06-14 16:45:22 +0100128class StackMap : public BitTableAccessor<8> {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100129 public:
David Srbecky50fac062018-06-13 18:55:35 +0100130 enum Kind {
131 Default = -1,
132 Catch = 0,
133 OSR = 1,
134 Debug = 2,
135 };
David Srbecky42deda82018-08-10 11:23:27 +0100136 BIT_TABLE_HEADER(StackMap)
David Srbecky50fac062018-06-13 18:55:35 +0100137 BIT_TABLE_COLUMN(0, Kind)
138 BIT_TABLE_COLUMN(1, PackedNativePc)
139 BIT_TABLE_COLUMN(2, DexPc)
140 BIT_TABLE_COLUMN(3, RegisterMaskIndex)
141 BIT_TABLE_COLUMN(4, StackMaskIndex)
142 BIT_TABLE_COLUMN(5, InlineInfoIndex)
143 BIT_TABLE_COLUMN(6, DexRegisterMaskIndex)
144 BIT_TABLE_COLUMN(7, DexRegisterMapIndex)
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100145
David Srbecky052f8ca2018-04-26 15:42:54 +0100146 ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const {
David Srbeckycf7833e2018-06-14 16:45:22 +0100147 return UnpackNativePc(GetPackedNativePc(), instruction_set);
David Brazdilf677ebf2015-05-29 16:29:43 +0100148 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100149
David Srbeckyd97e0822018-06-03 12:00:24 +0100150 ALWAYS_INLINE bool HasInlineInfo() const {
151 return HasInlineInfoIndex();
152 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100153
David Srbeckyd97e0822018-06-03 12:00:24 +0100154 ALWAYS_INLINE bool HasDexRegisterMap() const {
155 return HasDexRegisterMapIndex();
156 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100157
David Srbeckyd02b23f2018-05-29 23:27:22 +0100158 static uint32_t PackNativePc(uint32_t native_pc, InstructionSet isa) {
David Srbeckyd775f962018-05-30 18:12:52 +0100159 DCHECK_ALIGNED_PARAM(native_pc, GetInstructionSetInstructionAlignment(isa));
David Srbeckyd02b23f2018-05-29 23:27:22 +0100160 return native_pc / GetInstructionSetInstructionAlignment(isa);
161 }
162
163 static uint32_t UnpackNativePc(uint32_t packed_native_pc, InstructionSet isa) {
164 uint32_t native_pc = packed_native_pc * GetInstructionSetInstructionAlignment(isa);
165 DCHECK_EQ(native_pc / GetInstructionSetInstructionAlignment(isa), packed_native_pc);
166 return native_pc;
167 }
168
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100169 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100170 const CodeInfo& code_info,
171 uint32_t code_offset,
David Srbecky71ec1cc2018-05-18 15:57:25 +0100172 InstructionSet instruction_set) const;
David Srbecky61b28a12016-02-25 21:55:03 +0000173};
174
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100175/**
David Srbecky052f8ca2018-04-26 15:42:54 +0100176 * Inline information for a specific PC.
177 * The row referenced from the StackMap holds information at depth 0.
178 * Following rows hold information for further depths.
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100179 */
David Srbeckycf7833e2018-06-14 16:45:22 +0100180class InlineInfo : public BitTableAccessor<6> {
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100181 public:
David Srbecky42deda82018-08-10 11:23:27 +0100182 BIT_TABLE_HEADER(InlineInfo)
David Srbeckyd97e0822018-06-03 12:00:24 +0100183 BIT_TABLE_COLUMN(0, IsLast) // Determines if there are further rows for further depths.
184 BIT_TABLE_COLUMN(1, DexPc)
185 BIT_TABLE_COLUMN(2, MethodInfoIndex)
186 BIT_TABLE_COLUMN(3, ArtMethodHi) // High bits of ArtMethod*.
187 BIT_TABLE_COLUMN(4, ArtMethodLo) // Low bits of ArtMethod*.
David Srbecky6de88332018-06-03 12:00:11 +0100188 BIT_TABLE_COLUMN(5, NumberOfDexRegisters) // Includes outer levels and the main method.
David Srbeckyd97e0822018-06-03 12:00:24 +0100189
David Srbecky052f8ca2018-04-26 15:42:54 +0100190 static constexpr uint32_t kLast = -1;
191 static constexpr uint32_t kMore = 0;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100192
David Srbecky6e69e522018-06-03 12:00:14 +0100193 bool EncodesArtMethod() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100194 return HasArtMethodLo();
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100195 }
196
David Srbecky6e69e522018-06-03 12:00:14 +0100197 ArtMethod* GetArtMethod() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100198 uint64_t lo = GetArtMethodLo();
199 uint64_t hi = GetArtMethodHi();
David Srbecky71ec1cc2018-05-18 15:57:25 +0100200 return reinterpret_cast<ArtMethod*>((hi << 32) | lo);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100201 }
202
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100203 void Dump(VariableIndentationOutputStream* vios,
David Srbecky61b28a12016-02-25 21:55:03 +0000204 const CodeInfo& info,
David Srbecky8cd54542018-07-15 23:58:44 +0100205 const StackMap& stack_map) const;
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800206};
207
David Srbecky42deda82018-08-10 11:23:27 +0100208class StackMask : public BitTableAccessor<1> {
David Srbecky86decb62018-06-05 06:41:10 +0100209 public:
David Srbecky42deda82018-08-10 11:23:27 +0100210 BIT_TABLE_HEADER(StackMask)
211 BIT_TABLE_COLUMN(0, Mask)
212};
213
214class DexRegisterMask : public BitTableAccessor<1> {
215 public:
216 BIT_TABLE_HEADER(DexRegisterMask)
David Srbecky86decb62018-06-05 06:41:10 +0100217 BIT_TABLE_COLUMN(0, Mask)
218};
219
David Srbeckycf7833e2018-06-14 16:45:22 +0100220class DexRegisterMapInfo : public BitTableAccessor<1> {
David Srbecky86decb62018-06-05 06:41:10 +0100221 public:
David Srbecky42deda82018-08-10 11:23:27 +0100222 BIT_TABLE_HEADER(DexRegisterMapInfo)
David Srbecky86decb62018-06-05 06:41:10 +0100223 BIT_TABLE_COLUMN(0, CatalogueIndex)
224};
225
David Srbeckycf7833e2018-06-14 16:45:22 +0100226class DexRegisterInfo : public BitTableAccessor<2> {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100227 public:
David Srbecky42deda82018-08-10 11:23:27 +0100228 BIT_TABLE_HEADER(DexRegisterInfo)
David Srbeckyd97e0822018-06-03 12:00:24 +0100229 BIT_TABLE_COLUMN(0, Kind)
230 BIT_TABLE_COLUMN(1, PackedValue)
David Srbecky71ec1cc2018-05-18 15:57:25 +0100231
232 ALWAYS_INLINE DexRegisterLocation GetLocation() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100233 DexRegisterLocation::Kind kind = static_cast<DexRegisterLocation::Kind>(GetKind());
234 return DexRegisterLocation(kind, UnpackValue(kind, GetPackedValue()));
David Srbecky71ec1cc2018-05-18 15:57:25 +0100235 }
236
237 static uint32_t PackValue(DexRegisterLocation::Kind kind, uint32_t value) {
238 uint32_t packed_value = value;
239 if (kind == DexRegisterLocation::Kind::kInStack) {
240 DCHECK(IsAligned<kFrameSlotSize>(packed_value));
241 packed_value /= kFrameSlotSize;
242 }
243 return packed_value;
244 }
245
246 static uint32_t UnpackValue(DexRegisterLocation::Kind kind, uint32_t packed_value) {
247 uint32_t value = packed_value;
248 if (kind == DexRegisterLocation::Kind::kInStack) {
249 value *= kFrameSlotSize;
250 }
251 return value;
252 }
253};
254
David Srbecky4b59d102018-05-29 21:46:10 +0000255// Register masks tend to have many trailing zero bits (caller-saves are usually not encoded),
256// therefore it is worth encoding the mask as value+shift.
David Srbeckycf7833e2018-06-14 16:45:22 +0100257class RegisterMask : public BitTableAccessor<2> {
David Srbecky4b59d102018-05-29 21:46:10 +0000258 public:
David Srbecky42deda82018-08-10 11:23:27 +0100259 BIT_TABLE_HEADER(RegisterMask)
David Srbeckyd97e0822018-06-03 12:00:24 +0100260 BIT_TABLE_COLUMN(0, Value)
261 BIT_TABLE_COLUMN(1, Shift)
David Srbecky4b59d102018-05-29 21:46:10 +0000262
263 ALWAYS_INLINE uint32_t GetMask() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100264 return GetValue() << GetShift();
David Srbecky4b59d102018-05-29 21:46:10 +0000265 }
266};
267
David Srbecky8cd54542018-07-15 23:58:44 +0100268// Method indices are not very dedup friendly.
269// Separating them greatly improves dedup efficiency of the other tables.
Santiago Aboy Solanes970ba212021-10-21 10:52:47 +0100270class MethodInfo : public BitTableAccessor<3> {
David Srbecky8cd54542018-07-15 23:58:44 +0100271 public:
David Srbecky42deda82018-08-10 11:23:27 +0100272 BIT_TABLE_HEADER(MethodInfo)
David Srbecky8cd54542018-07-15 23:58:44 +0100273 BIT_TABLE_COLUMN(0, MethodIndex)
Santiago Aboy Solanes970ba212021-10-21 10:52:47 +0100274 BIT_TABLE_COLUMN(1, DexFileIndexKind)
275 BIT_TABLE_COLUMN(2, DexFileIndex)
276
277 static constexpr uint32_t kKindNonBCP = -1;
278 static constexpr uint32_t kKindBCP = 0;
Santiago Aboy Solanese43aa3f2021-11-01 09:02:09 +0000279
280 static constexpr uint32_t kSameDexFile = -1;
David Srbecky8cd54542018-07-15 23:58:44 +0100281};
282
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100283/**
284 * Wrapper around all compiler information collected for a method.
David Srbecky71ec1cc2018-05-18 15:57:25 +0100285 * See the Decode method at the end for the precise binary format.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100286 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100287class CodeInfo {
288 public:
David Srbecky0d4567f2019-05-30 22:45:40 +0100289 ALWAYS_INLINE CodeInfo() {}
290 ALWAYS_INLINE explicit CodeInfo(const uint8_t* data, size_t* num_read_bits = nullptr);
291 ALWAYS_INLINE explicit CodeInfo(const OatQuickMethodHeader* header);
David Srbecky6ee06e92018-07-25 21:45:54 +0100292
David Srbecky0d4567f2019-05-30 22:45:40 +0100293 // The following methods decode only part of the data.
David Srbecky0d4567f2019-05-30 22:45:40 +0100294 static CodeInfo DecodeGcMasksOnly(const OatQuickMethodHeader* header);
295 static CodeInfo DecodeInlineInfoOnly(const OatQuickMethodHeader* header);
David Srbecky0983f592021-04-08 16:36:19 +0100296
297 ALWAYS_INLINE static uint32_t DecodeCodeSize(const uint8_t* code_info_data) {
298 return DecodeHeaderOnly(code_info_data).code_size_;
299 }
300
301 ALWAYS_INLINE static QuickMethodFrameInfo DecodeFrameInfo(const uint8_t* code_info_data) {
302 CodeInfo code_info = DecodeHeaderOnly(code_info_data);
303 return QuickMethodFrameInfo(code_info.packed_frame_size_ * kStackAlignment,
304 code_info.core_spill_mask_,
305 code_info.fp_spill_mask_);
306 }
307
308 ALWAYS_INLINE static CodeInfo DecodeHeaderOnly(const uint8_t* code_info_data) {
309 CodeInfo code_info;
310 BitMemoryReader reader(code_info_data);
311 std::array<uint32_t, kNumHeaders> header = reader.ReadInterleavedVarints<kNumHeaders>();
312 ForEachHeaderField([&code_info, &header](size_t i, auto member_pointer) {
313 code_info.*member_pointer = header[i];
314 });
315 return code_info;
316 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000317
David Srbecky93bd3612018-07-02 19:30:18 +0100318 ALWAYS_INLINE const BitTable<StackMap>& GetStackMaps() const {
319 return stack_maps_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100320 }
321
David Srbecky052f8ca2018-04-26 15:42:54 +0100322 ALWAYS_INLINE StackMap GetStackMapAt(size_t index) const {
David Srbeckycf7833e2018-06-14 16:45:22 +0100323 return stack_maps_.GetRow(index);
David Srbecky45aa5982016-03-18 02:15:09 +0000324 }
325
David Srbecky052f8ca2018-04-26 15:42:54 +0100326 BitMemoryRegion GetStackMask(size_t index) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000327 return stack_masks_.GetBitMemoryRegion(index);
Mathieu Chartier1a20b682017-01-31 14:25:16 -0800328 }
329
David Srbecky052f8ca2018-04-26 15:42:54 +0100330 BitMemoryRegion GetStackMaskOf(const StackMap& stack_map) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000331 uint32_t index = stack_map.GetStackMaskIndex();
332 return (index == StackMap::kNoValue) ? BitMemoryRegion() : GetStackMask(index);
Mathieu Chartier1a20b682017-01-31 14:25:16 -0800333 }
334
David Srbecky052f8ca2018-04-26 15:42:54 +0100335 uint32_t GetRegisterMaskOf(const StackMap& stack_map) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000336 uint32_t index = stack_map.GetRegisterMaskIndex();
David Srbeckycf7833e2018-06-14 16:45:22 +0100337 return (index == StackMap::kNoValue) ? 0 : register_masks_.GetRow(index).GetMask();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100338 }
339
David Srbecky052f8ca2018-04-26 15:42:54 +0100340 uint32_t GetNumberOfLocationCatalogEntries() const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100341 return dex_register_catalog_.NumRows();
Roland Levillaina552e1c2015-03-26 15:01:03 +0000342 }
343
David Srbecky71ec1cc2018-05-18 15:57:25 +0100344 ALWAYS_INLINE DexRegisterLocation GetDexRegisterCatalogEntry(size_t index) const {
David Srbecky6de88332018-06-03 12:00:11 +0100345 return (index == StackMap::kNoValue)
346 ? DexRegisterLocation::None()
David Srbeckycf7833e2018-06-14 16:45:22 +0100347 : dex_register_catalog_.GetRow(index).GetLocation();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100348 }
349
David Srbecky93bd3612018-07-02 19:30:18 +0100350 bool HasInlineInfo() const {
351 return inline_infos_.NumRows() > 0;
352 }
353
David Srbecky052f8ca2018-04-26 15:42:54 +0100354 uint32_t GetNumberOfStackMaps() const {
355 return stack_maps_.NumRows();
Nicolas Geoffray6530baf2015-05-26 15:22:58 +0100356 }
357
Santiago Aboy Solanese43aa3f2021-11-01 09:02:09 +0000358 MethodInfo GetMethodInfoOf(InlineInfo inline_info) const {
359 return method_infos_.GetRow(inline_info.GetMethodInfoIndex());
360 }
361
David Srbecky8cd54542018-07-15 23:58:44 +0100362 uint32_t GetMethodIndexOf(InlineInfo inline_info) const {
Santiago Aboy Solanese43aa3f2021-11-01 09:02:09 +0000363 return GetMethodInfoOf(inline_info).GetMethodIndex();
David Srbecky8cd54542018-07-15 23:58:44 +0100364 }
365
Santiago Aboy Solanesab1d5592022-06-24 11:16:35 +0100366 // Returns the dex registers for `stack_map`, ignoring any inlined dex registers.
David Srbeckyfd89b072018-06-03 12:00:22 +0100367 ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map) const {
Santiago Aboy Solanesab1d5592022-06-24 11:16:35 +0100368 return GetDexRegisterMapOf(stack_map, /* first= */ 0, number_of_dex_registers_);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100369 }
370
Santiago Aboy Solanesab1d5592022-06-24 11:16:35 +0100371 // Returns the dex register map of `inline_info`, and just those registers.
David Srbecky93bd3612018-07-02 19:30:18 +0100372 ALWAYS_INLINE DexRegisterMap GetInlineDexRegisterMapOf(StackMap stack_map,
373 InlineInfo inline_info) const {
David Srbecky6de88332018-06-03 12:00:11 +0100374 if (stack_map.HasDexRegisterMap()) {
David Srbecky93bd3612018-07-02 19:30:18 +0100375 DCHECK(stack_map.HasInlineInfoIndex());
376 uint32_t depth = inline_info.Row() - stack_map.GetInlineInfoIndex();
David Srbecky6de88332018-06-03 12:00:11 +0100377 // The register counts are commutative and include all outer levels.
378 // This allows us to determine the range [first, last) in just two lookups.
379 // If we are at depth 0 (the first inlinee), the count from the main method is used.
David Srbecky93bd3612018-07-02 19:30:18 +0100380 uint32_t first = (depth == 0)
381 ? number_of_dex_registers_
382 : inline_infos_.GetRow(inline_info.Row() - 1).GetNumberOfDexRegisters();
383 uint32_t last = inline_info.GetNumberOfDexRegisters();
Santiago Aboy Solanesab1d5592022-06-24 11:16:35 +0100384 return GetDexRegisterMapOf(stack_map, first, last);
385 }
386 return DexRegisterMap(0, DexRegisterLocation::None());
387 }
388
389 // Returns the dex register map of `stack_map` in the range the range [first, last).
390 ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
391 uint32_t first,
392 uint32_t last) const {
393 if (stack_map.HasDexRegisterMap()) {
394 DCHECK_LE(first, last);
David Srbecky6de88332018-06-03 12:00:11 +0100395 DexRegisterMap map(last - first, DexRegisterLocation::Invalid());
396 DecodeDexRegisterMap(stack_map.Row(), first, &map);
397 return map;
398 }
399 return DexRegisterMap(0, DexRegisterLocation::None());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100400 }
401
David Srbecky93bd3612018-07-02 19:30:18 +0100402 BitTableRange<InlineInfo> GetInlineInfosOf(StackMap stack_map) const {
David Srbecky052f8ca2018-04-26 15:42:54 +0100403 uint32_t index = stack_map.GetInlineInfoIndex();
David Srbecky6e69e522018-06-03 12:00:14 +0100404 if (index != StackMap::kNoValue) {
David Srbecky93bd3612018-07-02 19:30:18 +0100405 auto begin = inline_infos_.begin() + index;
406 auto end = begin;
407 while ((*end++).GetIsLast() == InlineInfo::kMore) { }
408 return BitTableRange<InlineInfo>(begin, end);
409 } else {
410 return BitTableRange<InlineInfo>();
David Srbecky6e69e522018-06-03 12:00:14 +0100411 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100412 }
413
David Srbecky052f8ca2018-04-26 15:42:54 +0100414 StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
David Srbecky93bd3612018-07-02 19:30:18 +0100415 for (StackMap stack_map : stack_maps_) {
David Srbecky50fac062018-06-13 18:55:35 +0100416 if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() != StackMap::Kind::Debug) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100417 return stack_map;
418 }
419 }
David Srbeckya45a85c2018-06-21 16:03:12 +0100420 return stack_maps_.GetInvalidRow();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100421 }
422
Santiago Aboy Solanesab1d5592022-06-24 11:16:35 +0100423 StackMap GetCatchStackMapForDexPc(ArrayRef<const uint32_t> dex_pcs) const {
424 // Searches the stack map list backwards because catch stack maps are stored at the end.
David Srbecky052f8ca2018-04-26 15:42:54 +0100425 for (size_t i = GetNumberOfStackMaps(); i > 0; --i) {
426 StackMap stack_map = GetStackMapAt(i - 1);
Santiago Aboy Solanesab1d5592022-06-24 11:16:35 +0100427 if (UNLIKELY(stack_map.GetKind() != StackMap::Kind::Catch)) {
428 // Early break since we should have catch stack maps only at the end.
429 if (kIsDebugBuild) {
430 for (size_t j = i - 1; j > 0; --j) {
431 DCHECK(GetStackMapAt(j - 1).GetKind() != StackMap::Kind::Catch);
432 }
433 }
434 break;
435 }
436
437 // Both the handler dex_pc and all of the inline dex_pcs have to match i.e. we want dex_pcs to
438 // be [stack_map_dex_pc, inline_dex_pc_1, ..., inline_dex_pc_n].
439 if (stack_map.GetDexPc() != dex_pcs.front()) {
440 continue;
441 }
442
443 const BitTableRange<InlineInfo>& inline_infos = GetInlineInfosOf(stack_map);
444 if (inline_infos.size() == dex_pcs.size() - 1) {
445 bool matching_dex_pcs = true;
446 for (size_t inline_info_index = 0; inline_info_index < inline_infos.size();
447 ++inline_info_index) {
448 if (inline_infos[inline_info_index].GetDexPc() != dex_pcs[inline_info_index + 1]) {
449 matching_dex_pcs = false;
450 break;
451 }
452 }
453 if (matching_dex_pcs) {
454 return stack_map;
455 }
David Brazdil77a48ae2015-09-15 12:34:04 +0000456 }
457 }
David Srbeckya45a85c2018-06-21 16:03:12 +0100458 return stack_maps_.GetInvalidRow();
David Brazdil77a48ae2015-09-15 12:34:04 +0000459 }
460
David Srbecky052f8ca2018-04-26 15:42:54 +0100461 StackMap GetOsrStackMapForDexPc(uint32_t dex_pc) const {
David Srbecky93bd3612018-07-02 19:30:18 +0100462 for (StackMap stack_map : stack_maps_) {
David Srbecky50fac062018-06-13 18:55:35 +0100463 if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() == StackMap::Kind::OSR) {
464 return stack_map;
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000465 }
466 }
David Srbeckya45a85c2018-06-21 16:03:12 +0100467 return stack_maps_.GetInvalidRow();
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000468 }
469
Eric Holkf1e1dd12020-08-21 15:38:12 -0700470 StackMap GetStackMapForNativePcOffset(uintptr_t pc, InstructionSet isa = kRuntimeISA) const;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100471
David Srbecky71ec1cc2018-05-18 15:57:25 +0100472 // Dump this CodeInfo object on `vios`.
473 // `code_offset` is the (absolute) native PC of the compiled method.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100474 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100475 uint32_t code_offset,
David Srbecky71ec1cc2018-05-18 15:57:25 +0100476 bool verbose,
David Srbecky8cd54542018-07-15 23:58:44 +0100477 InstructionSet instruction_set) const;
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000478
David Srbecky86decb62018-06-05 06:41:10 +0100479 // Accumulate code info size statistics into the given Stats tree.
David Srbecky81b1d782021-03-07 21:33:28 +0000480 static void CollectSizeStats(const uint8_t* code_info, /*out*/ Stats& parent);
David Srbecky86decb62018-06-05 06:41:10 +0100481
David Srbeckye42a4b92019-05-26 00:10:25 +0100482 ALWAYS_INLINE static bool HasInlineInfo(const uint8_t* code_info_data) {
483 return (*code_info_data & kHasInlineInfo) != 0;
484 }
485
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +0000486 ALWAYS_INLINE static bool IsBaseline(const uint8_t* code_info_data) {
487 return (*code_info_data & kIsBaseline) != 0;
488 }
489
Mythri Alled9e83772022-07-14 09:38:49 +0000490 ALWAYS_INLINE static bool IsDebuggable(const uint8_t* code_info_data) {
491 return (*code_info_data & kIsDebuggable) != 0;
492 }
493
Santiago Aboy Solanesab1d5592022-06-24 11:16:35 +0100494 uint32_t GetNumberOfDexRegisters() {
495 return number_of_dex_registers_;
496 }
497
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100498 private:
David Srbecky6de88332018-06-03 12:00:11 +0100499 // Scan backward to determine dex register locations at given stack map.
500 void DecodeDexRegisterMap(uint32_t stack_map_index,
501 uint32_t first_dex_register,
502 /*out*/ DexRegisterMap* map) const;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000503
David Srbecky0d4567f2019-05-30 22:45:40 +0100504 template<typename DecodeCallback> // (size_t index, BitTable<...>*, BitMemoryRegion).
505 ALWAYS_INLINE CodeInfo(const uint8_t* data, size_t* num_read_bits, DecodeCallback callback);
David Srbecky052f8ca2018-04-26 15:42:54 +0100506
David Srbecky697c47a2019-06-16 21:53:07 +0100507 // Invokes the callback with index and member pointer of each header field.
David Srbecky42deda82018-08-10 11:23:27 +0100508 template<typename Callback>
509 ALWAYS_INLINE static void ForEachHeaderField(Callback callback) {
David Srbecky697c47a2019-06-16 21:53:07 +0100510 size_t index = 0;
511 callback(index++, &CodeInfo::flags_);
David Srbecky17b4d2b2021-03-02 18:14:31 +0000512 callback(index++, &CodeInfo::code_size_);
David Srbecky697c47a2019-06-16 21:53:07 +0100513 callback(index++, &CodeInfo::packed_frame_size_);
514 callback(index++, &CodeInfo::core_spill_mask_);
515 callback(index++, &CodeInfo::fp_spill_mask_);
516 callback(index++, &CodeInfo::number_of_dex_registers_);
517 callback(index++, &CodeInfo::bit_table_flags_);
518 DCHECK_EQ(index, kNumHeaders);
David Srbecky42deda82018-08-10 11:23:27 +0100519 }
520
David Srbecky697c47a2019-06-16 21:53:07 +0100521 // Invokes the callback with index and member pointer of each BitTable field.
David Srbecky42deda82018-08-10 11:23:27 +0100522 template<typename Callback>
David Srbecky0d4567f2019-05-30 22:45:40 +0100523 ALWAYS_INLINE static void ForEachBitTableField(Callback callback) {
David Srbecky697c47a2019-06-16 21:53:07 +0100524 size_t index = 0;
525 callback(index++, &CodeInfo::stack_maps_);
526 callback(index++, &CodeInfo::register_masks_);
527 callback(index++, &CodeInfo::stack_masks_);
David Srbecky697c47a2019-06-16 21:53:07 +0100528 callback(index++, &CodeInfo::inline_infos_);
529 callback(index++, &CodeInfo::method_infos_);
David Srbecky697c47a2019-06-16 21:53:07 +0100530 callback(index++, &CodeInfo::dex_register_masks_);
531 callback(index++, &CodeInfo::dex_register_maps_);
532 callback(index++, &CodeInfo::dex_register_catalog_);
533 DCHECK_EQ(index, kNumBitTables);
David Srbecky42deda82018-08-10 11:23:27 +0100534 }
535
David Srbecky697c47a2019-06-16 21:53:07 +0100536 bool HasBitTable(size_t i) { return ((bit_table_flags_ >> i) & 1) != 0; }
537 bool IsBitTableDeduped(size_t i) { return ((bit_table_flags_ >> (kNumBitTables + i)) & 1) != 0; }
538 void SetBitTableDeduped(size_t i) { bit_table_flags_ |= 1 << (kNumBitTables + i); }
Vladimir Markoe4ccbb52022-03-15 08:51:33 +0000539 bool HasDedupedBitTables() { return (bit_table_flags_ >> kNumBitTables) != 0u; }
David Srbecky697c47a2019-06-16 21:53:07 +0100540
David Srbeckye42a4b92019-05-26 00:10:25 +0100541 enum Flags {
542 kHasInlineInfo = 1 << 0,
Nicolas Geoffraya59af8a2019-11-27 17:42:32 +0000543 kIsBaseline = 1 << 1,
Mythri Alled9e83772022-07-14 09:38:49 +0000544 kIsDebuggable = 1 << 2,
David Srbeckye42a4b92019-05-26 00:10:25 +0100545 };
546
David Srbecky697c47a2019-06-16 21:53:07 +0100547 // The CodeInfo starts with sequence of variable-length bit-encoded integers.
Mythri Alled9e83772022-07-14 09:38:49 +0000548 // (Please see kVarintMax for more details about encoding).
David Srbecky17b4d2b2021-03-02 18:14:31 +0000549 static constexpr size_t kNumHeaders = 7;
Mythri Alled9e83772022-07-14 09:38:49 +0000550 // Note that the space for flags is limited to three bits. We use a custom encoding where we
551 // encode the value inline if it is less than kVarintMax. We want to access flags without
Mythri Allee1b88772022-10-06 11:01:26 +0000552 // decoding the entire CodeInfo header so the value of flags cannot be more than kVarintMax.
553 // See IsDebuggable / IsBaseline / HasInlineInfo on how we access flags_ without decoding the
554 // header.
Mythri Alled9e83772022-07-14 09:38:49 +0000555 uint32_t flags_ = 0;
David Srbecky17b4d2b2021-03-02 18:14:31 +0000556 uint32_t code_size_ = 0; // The size of native PC range in bytes.
David Srbecky2259f1c2019-01-16 23:18:30 +0000557 uint32_t packed_frame_size_ = 0; // Frame size in kStackAlignment units.
558 uint32_t core_spill_mask_ = 0;
559 uint32_t fp_spill_mask_ = 0;
560 uint32_t number_of_dex_registers_ = 0;
David Srbecky697c47a2019-06-16 21:53:07 +0100561 uint32_t bit_table_flags_ = 0;
562
563 // The encoded bit-tables follow the header. Based on the above flags field,
564 // bit-tables might be omitted or replaced by relative bit-offset if deduped.
565 static constexpr size_t kNumBitTables = 8;
David Srbeckycf7833e2018-06-14 16:45:22 +0100566 BitTable<StackMap> stack_maps_;
567 BitTable<RegisterMask> register_masks_;
David Srbecky42deda82018-08-10 11:23:27 +0100568 BitTable<StackMask> stack_masks_;
David Srbeckya2d29a32018-08-03 11:06:38 +0100569 BitTable<InlineInfo> inline_infos_;
570 BitTable<MethodInfo> method_infos_;
David Srbecky42deda82018-08-10 11:23:27 +0100571 BitTable<DexRegisterMask> dex_register_masks_;
David Srbeckycf7833e2018-06-14 16:45:22 +0100572 BitTable<DexRegisterMapInfo> dex_register_maps_;
573 BitTable<DexRegisterInfo> dex_register_catalog_;
David Srbecky697c47a2019-06-16 21:53:07 +0100574
Vladimir Markoe4ccbb52022-03-15 08:51:33 +0000575 friend class linker::CodeInfoTableDeduper;
David Srbecky67ba8722019-05-23 15:32:18 +0100576 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100577};
578
Roland Levillain1c1da432015-07-16 11:54:44 +0100579#undef ELEMENT_BYTE_OFFSET_AFTER
580#undef ELEMENT_BIT_OFFSET_AFTER
581
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100582} // namespace art
583
584#endif // ART_RUNTIME_STACK_MAP_H_