xref: /aosp_15_r20/art/runtime/oat/stack_map.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_RUNTIME_OAT_STACK_MAP_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_RUNTIME_OAT_STACK_MAP_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <limits>
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/array_ref.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/bit_memory_region.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/bit_table.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/globals.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/logging.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
30*795d594fSAndroid Build Coastguard Worker #include "base/memory_region.h"
31*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_types.h"
32*795d594fSAndroid Build Coastguard Worker #include "dex_register_location.h"
33*795d594fSAndroid Build Coastguard Worker #include "quick/quick_method_frame_info.h"
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker namespace linker {
38*795d594fSAndroid Build Coastguard Worker class CodeInfoTableDeduper;
39*795d594fSAndroid Build Coastguard Worker }  //  namespace linker
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker class OatQuickMethodHeader;
42*795d594fSAndroid Build Coastguard Worker class VariableIndentationOutputStream;
43*795d594fSAndroid Build Coastguard Worker 
44*795d594fSAndroid Build Coastguard Worker // Size of a frame slot, in bytes.  This constant is a signed value,
45*795d594fSAndroid Build Coastguard Worker // to please the compiler in arithmetic operations involving int32_t
46*795d594fSAndroid Build Coastguard Worker // (signed) values.
47*795d594fSAndroid Build Coastguard Worker static constexpr ssize_t kFrameSlotSize = 4;
48*795d594fSAndroid Build Coastguard Worker 
49*795d594fSAndroid Build Coastguard Worker // The delta compression of dex register maps means we need to scan the stackmaps backwards.
50*795d594fSAndroid Build Coastguard Worker // We compress the data in such a way so that there is an upper bound on the search distance.
51*795d594fSAndroid Build Coastguard Worker // Max distance 0 means each stack map must be fully defined and no scanning back is allowed.
52*795d594fSAndroid Build Coastguard Worker // If this value is changed, the oat file version should be incremented (for DCHECK to pass).
53*795d594fSAndroid Build Coastguard Worker static constexpr size_t kMaxDexRegisterMapSearchDistance = 32;
54*795d594fSAndroid Build Coastguard Worker 
55*795d594fSAndroid Build Coastguard Worker class ArtMethod;
56*795d594fSAndroid Build Coastguard Worker class CodeInfo;
57*795d594fSAndroid Build Coastguard Worker class Stats;
58*795d594fSAndroid Build Coastguard Worker 
59*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg);
60*795d594fSAndroid Build Coastguard Worker 
61*795d594fSAndroid Build Coastguard Worker // Information on Dex register locations for a specific PC.
62*795d594fSAndroid Build Coastguard Worker // Effectively just a convenience wrapper for DexRegisterLocation vector.
63*795d594fSAndroid Build Coastguard Worker // If the size is small enough, it keeps the data on the stack.
64*795d594fSAndroid Build Coastguard Worker // TODO: Replace this with generic purpose "small-vector" implementation.
65*795d594fSAndroid Build Coastguard Worker class DexRegisterMap {
66*795d594fSAndroid Build Coastguard Worker  public:
67*795d594fSAndroid Build Coastguard Worker   using iterator = DexRegisterLocation*;
68*795d594fSAndroid Build Coastguard Worker   using const_iterator = const DexRegisterLocation*;
69*795d594fSAndroid Build Coastguard Worker 
70*795d594fSAndroid Build Coastguard Worker   // Create map for given number of registers and initialize them to the given value.
DexRegisterMap(size_t count,DexRegisterLocation value)71*795d594fSAndroid Build Coastguard Worker   DexRegisterMap(size_t count, DexRegisterLocation value) : count_(count), regs_small_{} {
72*795d594fSAndroid Build Coastguard Worker     if (count_ <= kSmallCount) {
73*795d594fSAndroid Build Coastguard Worker       std::fill_n(regs_small_.begin(), count, value);
74*795d594fSAndroid Build Coastguard Worker     } else {
75*795d594fSAndroid Build Coastguard Worker       regs_large_.resize(count, value);
76*795d594fSAndroid Build Coastguard Worker     }
77*795d594fSAndroid Build Coastguard Worker   }
78*795d594fSAndroid Build Coastguard Worker 
data()79*795d594fSAndroid Build Coastguard Worker   DexRegisterLocation* data() {
80*795d594fSAndroid Build Coastguard Worker     return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
81*795d594fSAndroid Build Coastguard Worker   }
data()82*795d594fSAndroid Build Coastguard Worker   const DexRegisterLocation* data() const {
83*795d594fSAndroid Build Coastguard Worker     return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
84*795d594fSAndroid Build Coastguard Worker   }
85*795d594fSAndroid Build Coastguard Worker 
begin()86*795d594fSAndroid Build Coastguard Worker   iterator begin() { return data(); }
end()87*795d594fSAndroid Build Coastguard Worker   iterator end() { return data() + count_; }
begin()88*795d594fSAndroid Build Coastguard Worker   const_iterator begin() const { return data(); }
end()89*795d594fSAndroid Build Coastguard Worker   const_iterator end() const { return data() + count_; }
size()90*795d594fSAndroid Build Coastguard Worker   size_t size() const { return count_; }
empty()91*795d594fSAndroid Build Coastguard Worker   bool empty() const { return count_ == 0; }
92*795d594fSAndroid Build Coastguard Worker 
93*795d594fSAndroid Build Coastguard Worker   DexRegisterLocation& operator[](size_t index) {
94*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(index, count_);
95*795d594fSAndroid Build Coastguard Worker     return data()[index];
96*795d594fSAndroid Build Coastguard Worker   }
97*795d594fSAndroid Build Coastguard Worker   const DexRegisterLocation& operator[](size_t index) const {
98*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(index, count_);
99*795d594fSAndroid Build Coastguard Worker     return data()[index];
100*795d594fSAndroid Build Coastguard Worker   }
101*795d594fSAndroid Build Coastguard Worker 
GetNumberOfLiveDexRegisters()102*795d594fSAndroid Build Coastguard Worker   size_t GetNumberOfLiveDexRegisters() const {
103*795d594fSAndroid Build Coastguard Worker     return std::count_if(begin(), end(), [](auto& loc) { return loc.IsLive(); });
104*795d594fSAndroid Build Coastguard Worker   }
105*795d594fSAndroid Build Coastguard Worker 
HasAnyLiveDexRegisters()106*795d594fSAndroid Build Coastguard Worker   bool HasAnyLiveDexRegisters() const {
107*795d594fSAndroid Build Coastguard Worker     return std::any_of(begin(), end(), [](auto& loc) { return loc.IsLive(); });
108*795d594fSAndroid Build Coastguard Worker   }
109*795d594fSAndroid Build Coastguard Worker 
110*795d594fSAndroid Build Coastguard Worker   void Dump(VariableIndentationOutputStream* vios) const;
111*795d594fSAndroid Build Coastguard Worker 
112*795d594fSAndroid Build Coastguard Worker  private:
113*795d594fSAndroid Build Coastguard Worker   // Store the data inline if the number of registers is small to avoid memory allocations.
114*795d594fSAndroid Build Coastguard Worker   // If count_ <= kSmallCount, we use the regs_small_ array, and regs_large_ otherwise.
115*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kSmallCount = 16;
116*795d594fSAndroid Build Coastguard Worker   size_t count_;
117*795d594fSAndroid Build Coastguard Worker   std::array<DexRegisterLocation, kSmallCount> regs_small_;
118*795d594fSAndroid Build Coastguard Worker   dchecked_vector<DexRegisterLocation> regs_large_;
119*795d594fSAndroid Build Coastguard Worker };
120*795d594fSAndroid Build Coastguard Worker 
121*795d594fSAndroid Build Coastguard Worker /**
122*795d594fSAndroid Build Coastguard Worker  * A Stack Map holds compilation information for a specific PC necessary for:
123*795d594fSAndroid Build Coastguard Worker  * - Mapping it to a dex PC,
124*795d594fSAndroid Build Coastguard Worker  * - Knowing which stack entries are objects,
125*795d594fSAndroid Build Coastguard Worker  * - Knowing which registers hold objects,
126*795d594fSAndroid Build Coastguard Worker  * - Knowing the inlining information,
127*795d594fSAndroid Build Coastguard Worker  * - Knowing the values of dex registers.
128*795d594fSAndroid Build Coastguard Worker  */
129*795d594fSAndroid Build Coastguard Worker class StackMap : public BitTableAccessor<8> {
130*795d594fSAndroid Build Coastguard Worker  public:
131*795d594fSAndroid Build Coastguard Worker   enum Kind {
132*795d594fSAndroid Build Coastguard Worker     Default = -1,
133*795d594fSAndroid Build Coastguard Worker     Catch = 0,
134*795d594fSAndroid Build Coastguard Worker     OSR = 1,
135*795d594fSAndroid Build Coastguard Worker     Debug = 2,
136*795d594fSAndroid Build Coastguard Worker   };
137*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_HEADER(StackMap)
138*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(0, Kind)
139*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(1, PackedNativePc)
140*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(2, DexPc)
141*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(3, RegisterMaskIndex)
142*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(4, StackMaskIndex)
143*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(5, InlineInfoIndex)
144*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(6, DexRegisterMaskIndex)
145*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(7, DexRegisterMapIndex)
146*795d594fSAndroid Build Coastguard Worker 
GetNativePcOffset(InstructionSet instruction_set)147*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const {
148*795d594fSAndroid Build Coastguard Worker     return UnpackNativePc(GetPackedNativePc(), instruction_set);
149*795d594fSAndroid Build Coastguard Worker   }
150*795d594fSAndroid Build Coastguard Worker 
HasInlineInfo()151*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE bool HasInlineInfo() const {
152*795d594fSAndroid Build Coastguard Worker     return HasInlineInfoIndex();
153*795d594fSAndroid Build Coastguard Worker   }
154*795d594fSAndroid Build Coastguard Worker 
HasDexRegisterMap()155*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE bool HasDexRegisterMap() const {
156*795d594fSAndroid Build Coastguard Worker     return HasDexRegisterMapIndex();
157*795d594fSAndroid Build Coastguard Worker   }
158*795d594fSAndroid Build Coastguard Worker 
PackNativePc(uint32_t native_pc,InstructionSet isa)159*795d594fSAndroid Build Coastguard Worker   static uint32_t PackNativePc(uint32_t native_pc, InstructionSet isa) {
160*795d594fSAndroid Build Coastguard Worker     DCHECK_ALIGNED_PARAM(native_pc, GetInstructionSetInstructionAlignment(isa));
161*795d594fSAndroid Build Coastguard Worker     return native_pc / GetInstructionSetInstructionAlignment(isa);
162*795d594fSAndroid Build Coastguard Worker   }
163*795d594fSAndroid Build Coastguard Worker 
UnpackNativePc(uint32_t packed_native_pc,InstructionSet isa)164*795d594fSAndroid Build Coastguard Worker   static uint32_t UnpackNativePc(uint32_t packed_native_pc, InstructionSet isa) {
165*795d594fSAndroid Build Coastguard Worker     uint32_t native_pc = packed_native_pc * GetInstructionSetInstructionAlignment(isa);
166*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(native_pc / GetInstructionSetInstructionAlignment(isa), packed_native_pc);
167*795d594fSAndroid Build Coastguard Worker     return native_pc;
168*795d594fSAndroid Build Coastguard Worker   }
169*795d594fSAndroid Build Coastguard Worker 
170*795d594fSAndroid Build Coastguard Worker   EXPORT void Dump(VariableIndentationOutputStream* vios,
171*795d594fSAndroid Build Coastguard Worker                    const CodeInfo& code_info,
172*795d594fSAndroid Build Coastguard Worker                    uint32_t code_offset,
173*795d594fSAndroid Build Coastguard Worker                    InstructionSet instruction_set) const;
174*795d594fSAndroid Build Coastguard Worker };
175*795d594fSAndroid Build Coastguard Worker 
176*795d594fSAndroid Build Coastguard Worker /**
177*795d594fSAndroid Build Coastguard Worker  * Inline information for a specific PC.
178*795d594fSAndroid Build Coastguard Worker  * The row referenced from the StackMap holds information at depth 0.
179*795d594fSAndroid Build Coastguard Worker  * Following rows hold information for further depths.
180*795d594fSAndroid Build Coastguard Worker  */
181*795d594fSAndroid Build Coastguard Worker class InlineInfo : public BitTableAccessor<6> {
182*795d594fSAndroid Build Coastguard Worker  public:
183*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_HEADER(InlineInfo)
184*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(0, IsLast)  // Determines if there are further rows for further depths.
185*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(1, DexPc)
186*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(2, MethodInfoIndex)
187*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(3, ArtMethodHi)  // High bits of ArtMethod*.
188*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(4, ArtMethodLo)  // Low bits of ArtMethod*.
189*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(5, NumberOfDexRegisters)  // Includes outer levels and the main method.
190*795d594fSAndroid Build Coastguard Worker 
191*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kLast = -1;
192*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kMore = 0;
193*795d594fSAndroid Build Coastguard Worker 
EncodesArtMethod()194*795d594fSAndroid Build Coastguard Worker   bool EncodesArtMethod() const {
195*795d594fSAndroid Build Coastguard Worker     return HasArtMethodLo();
196*795d594fSAndroid Build Coastguard Worker   }
197*795d594fSAndroid Build Coastguard Worker 
GetArtMethod()198*795d594fSAndroid Build Coastguard Worker   ArtMethod* GetArtMethod() const {
199*795d594fSAndroid Build Coastguard Worker     uint64_t lo = GetArtMethodLo();
200*795d594fSAndroid Build Coastguard Worker     uint64_t hi = GetArtMethodHi();
201*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<ArtMethod*>((hi << 32) | lo);
202*795d594fSAndroid Build Coastguard Worker   }
203*795d594fSAndroid Build Coastguard Worker 
204*795d594fSAndroid Build Coastguard Worker   void Dump(VariableIndentationOutputStream* vios,
205*795d594fSAndroid Build Coastguard Worker             const CodeInfo& info,
206*795d594fSAndroid Build Coastguard Worker             const StackMap& stack_map) const;
207*795d594fSAndroid Build Coastguard Worker };
208*795d594fSAndroid Build Coastguard Worker 
209*795d594fSAndroid Build Coastguard Worker class StackMask : public BitTableAccessor<1> {
210*795d594fSAndroid Build Coastguard Worker  public:
211*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_HEADER(StackMask)
212*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(0, Mask)
213*795d594fSAndroid Build Coastguard Worker };
214*795d594fSAndroid Build Coastguard Worker 
215*795d594fSAndroid Build Coastguard Worker class DexRegisterMask : public BitTableAccessor<1> {
216*795d594fSAndroid Build Coastguard Worker  public:
217*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_HEADER(DexRegisterMask)
218*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(0, Mask)
219*795d594fSAndroid Build Coastguard Worker };
220*795d594fSAndroid Build Coastguard Worker 
221*795d594fSAndroid Build Coastguard Worker class DexRegisterMapInfo : public BitTableAccessor<1> {
222*795d594fSAndroid Build Coastguard Worker  public:
223*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_HEADER(DexRegisterMapInfo)
224*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(0, CatalogueIndex)
225*795d594fSAndroid Build Coastguard Worker };
226*795d594fSAndroid Build Coastguard Worker 
227*795d594fSAndroid Build Coastguard Worker class DexRegisterInfo : public BitTableAccessor<2> {
228*795d594fSAndroid Build Coastguard Worker  public:
BIT_TABLE_HEADER(DexRegisterInfo)229*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_HEADER(DexRegisterInfo)
230*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(0, Kind)
231*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(1, PackedValue)
232*795d594fSAndroid Build Coastguard Worker 
233*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE DexRegisterLocation GetLocation() const {
234*795d594fSAndroid Build Coastguard Worker     DexRegisterLocation::Kind kind = static_cast<DexRegisterLocation::Kind>(GetKind());
235*795d594fSAndroid Build Coastguard Worker     return DexRegisterLocation(kind, UnpackValue(kind, GetPackedValue()));
236*795d594fSAndroid Build Coastguard Worker   }
237*795d594fSAndroid Build Coastguard Worker 
PackValue(DexRegisterLocation::Kind kind,uint32_t value)238*795d594fSAndroid Build Coastguard Worker   static uint32_t PackValue(DexRegisterLocation::Kind kind, uint32_t value) {
239*795d594fSAndroid Build Coastguard Worker     uint32_t packed_value = value;
240*795d594fSAndroid Build Coastguard Worker     if (kind == DexRegisterLocation::Kind::kInStack) {
241*795d594fSAndroid Build Coastguard Worker       DCHECK(IsAligned<kFrameSlotSize>(packed_value));
242*795d594fSAndroid Build Coastguard Worker       packed_value /= kFrameSlotSize;
243*795d594fSAndroid Build Coastguard Worker     }
244*795d594fSAndroid Build Coastguard Worker     return packed_value;
245*795d594fSAndroid Build Coastguard Worker   }
246*795d594fSAndroid Build Coastguard Worker 
UnpackValue(DexRegisterLocation::Kind kind,uint32_t packed_value)247*795d594fSAndroid Build Coastguard Worker   static uint32_t UnpackValue(DexRegisterLocation::Kind kind, uint32_t packed_value) {
248*795d594fSAndroid Build Coastguard Worker     uint32_t value = packed_value;
249*795d594fSAndroid Build Coastguard Worker     if (kind == DexRegisterLocation::Kind::kInStack) {
250*795d594fSAndroid Build Coastguard Worker       value *= kFrameSlotSize;
251*795d594fSAndroid Build Coastguard Worker     }
252*795d594fSAndroid Build Coastguard Worker     return value;
253*795d594fSAndroid Build Coastguard Worker   }
254*795d594fSAndroid Build Coastguard Worker };
255*795d594fSAndroid Build Coastguard Worker 
256*795d594fSAndroid Build Coastguard Worker // Register masks tend to have many trailing zero bits (caller-saves are usually not encoded),
257*795d594fSAndroid Build Coastguard Worker // therefore it is worth encoding the mask as value+shift.
258*795d594fSAndroid Build Coastguard Worker class RegisterMask : public BitTableAccessor<2> {
259*795d594fSAndroid Build Coastguard Worker  public:
BIT_TABLE_HEADER(RegisterMask)260*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_HEADER(RegisterMask)
261*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(0, Value)
262*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(1, Shift)
263*795d594fSAndroid Build Coastguard Worker 
264*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE uint32_t GetMask() const {
265*795d594fSAndroid Build Coastguard Worker     return GetValue() << GetShift();
266*795d594fSAndroid Build Coastguard Worker   }
267*795d594fSAndroid Build Coastguard Worker };
268*795d594fSAndroid Build Coastguard Worker 
269*795d594fSAndroid Build Coastguard Worker // Method indices are not very dedup friendly.
270*795d594fSAndroid Build Coastguard Worker // Separating them greatly improves dedup efficiency of the other tables.
271*795d594fSAndroid Build Coastguard Worker class MethodInfo : public BitTableAccessor<3> {
272*795d594fSAndroid Build Coastguard Worker  public:
273*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_HEADER(MethodInfo)
274*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(0, MethodIndex)
275*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(1, DexFileIndexKind)
276*795d594fSAndroid Build Coastguard Worker   BIT_TABLE_COLUMN(2, DexFileIndex)
277*795d594fSAndroid Build Coastguard Worker 
278*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kKindNonBCP = -1;
279*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kKindBCP = 0;
280*795d594fSAndroid Build Coastguard Worker 
281*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kSameDexFile = -1;
282*795d594fSAndroid Build Coastguard Worker };
283*795d594fSAndroid Build Coastguard Worker 
284*795d594fSAndroid Build Coastguard Worker /**
285*795d594fSAndroid Build Coastguard Worker  * Wrapper around all compiler information collected for a method.
286*795d594fSAndroid Build Coastguard Worker  * See the Decode method at the end for the precise binary format.
287*795d594fSAndroid Build Coastguard Worker  */
288*795d594fSAndroid Build Coastguard Worker class CodeInfo {
289*795d594fSAndroid Build Coastguard Worker  public:
CodeInfo()290*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE CodeInfo() {}
291*795d594fSAndroid Build Coastguard Worker   EXPORT ALWAYS_INLINE explicit CodeInfo(const uint8_t* data, size_t* num_read_bits = nullptr);
292*795d594fSAndroid Build Coastguard Worker   EXPORT ALWAYS_INLINE explicit CodeInfo(const OatQuickMethodHeader* header);
293*795d594fSAndroid Build Coastguard Worker 
294*795d594fSAndroid Build Coastguard Worker   // The following methods decode only part of the data.
295*795d594fSAndroid Build Coastguard Worker   static CodeInfo DecodeGcMasksOnly(const OatQuickMethodHeader* header);
296*795d594fSAndroid Build Coastguard Worker   static CodeInfo DecodeInlineInfoOnly(const OatQuickMethodHeader* header);
297*795d594fSAndroid Build Coastguard Worker 
DecodeCodeSize(const uint8_t * code_info_data)298*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static uint32_t DecodeCodeSize(const uint8_t* code_info_data) {
299*795d594fSAndroid Build Coastguard Worker     return DecodeHeaderOnly(code_info_data).code_size_;
300*795d594fSAndroid Build Coastguard Worker   }
301*795d594fSAndroid Build Coastguard Worker 
DecodeFrameInfo(const uint8_t * code_info_data)302*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static QuickMethodFrameInfo DecodeFrameInfo(const uint8_t* code_info_data) {
303*795d594fSAndroid Build Coastguard Worker     CodeInfo code_info = DecodeHeaderOnly(code_info_data);
304*795d594fSAndroid Build Coastguard Worker     return QuickMethodFrameInfo(code_info.packed_frame_size_ * kStackAlignment,
305*795d594fSAndroid Build Coastguard Worker                                 code_info.core_spill_mask_,
306*795d594fSAndroid Build Coastguard Worker                                 code_info.fp_spill_mask_);
307*795d594fSAndroid Build Coastguard Worker   }
308*795d594fSAndroid Build Coastguard Worker 
DecodeHeaderOnly(const uint8_t * code_info_data)309*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static CodeInfo DecodeHeaderOnly(const uint8_t* code_info_data) {
310*795d594fSAndroid Build Coastguard Worker     CodeInfo code_info;
311*795d594fSAndroid Build Coastguard Worker     BitMemoryReader reader(code_info_data);
312*795d594fSAndroid Build Coastguard Worker     std::array<uint32_t, kNumHeaders> header = reader.ReadInterleavedVarints<kNumHeaders>();
313*795d594fSAndroid Build Coastguard Worker     ForEachHeaderField([&code_info, &header](size_t i, auto member_pointer) {
314*795d594fSAndroid Build Coastguard Worker       code_info.*member_pointer = header[i];
315*795d594fSAndroid Build Coastguard Worker     });
316*795d594fSAndroid Build Coastguard Worker     return code_info;
317*795d594fSAndroid Build Coastguard Worker   }
318*795d594fSAndroid Build Coastguard Worker 
GetStackMaps()319*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE const BitTable<StackMap>& GetStackMaps() const {
320*795d594fSAndroid Build Coastguard Worker     return stack_maps_;
321*795d594fSAndroid Build Coastguard Worker   }
322*795d594fSAndroid Build Coastguard Worker 
GetStackMapAt(size_t index)323*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE StackMap GetStackMapAt(size_t index) const {
324*795d594fSAndroid Build Coastguard Worker     return stack_maps_.GetRow(index);
325*795d594fSAndroid Build Coastguard Worker   }
326*795d594fSAndroid Build Coastguard Worker 
GetStackMask(size_t index)327*795d594fSAndroid Build Coastguard Worker   BitMemoryRegion GetStackMask(size_t index) const {
328*795d594fSAndroid Build Coastguard Worker     return stack_masks_.GetBitMemoryRegion(index);
329*795d594fSAndroid Build Coastguard Worker   }
330*795d594fSAndroid Build Coastguard Worker 
GetStackMaskOf(const StackMap & stack_map)331*795d594fSAndroid Build Coastguard Worker   BitMemoryRegion GetStackMaskOf(const StackMap& stack_map) const {
332*795d594fSAndroid Build Coastguard Worker     uint32_t index = stack_map.GetStackMaskIndex();
333*795d594fSAndroid Build Coastguard Worker     return (index == StackMap::kNoValue) ? BitMemoryRegion() : GetStackMask(index);
334*795d594fSAndroid Build Coastguard Worker   }
335*795d594fSAndroid Build Coastguard Worker 
GetRegisterMaskOf(const StackMap & stack_map)336*795d594fSAndroid Build Coastguard Worker   uint32_t GetRegisterMaskOf(const StackMap& stack_map) const {
337*795d594fSAndroid Build Coastguard Worker     uint32_t index = stack_map.GetRegisterMaskIndex();
338*795d594fSAndroid Build Coastguard Worker     return (index == StackMap::kNoValue) ? 0 : register_masks_.GetRow(index).GetMask();
339*795d594fSAndroid Build Coastguard Worker   }
340*795d594fSAndroid Build Coastguard Worker 
GetNumberOfLocationCatalogEntries()341*795d594fSAndroid Build Coastguard Worker   uint32_t GetNumberOfLocationCatalogEntries() const {
342*795d594fSAndroid Build Coastguard Worker     return dex_register_catalog_.NumRows();
343*795d594fSAndroid Build Coastguard Worker   }
344*795d594fSAndroid Build Coastguard Worker 
GetDexRegisterCatalogEntry(size_t index)345*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE DexRegisterLocation GetDexRegisterCatalogEntry(size_t index) const {
346*795d594fSAndroid Build Coastguard Worker     return (index == StackMap::kNoValue)
347*795d594fSAndroid Build Coastguard Worker       ? DexRegisterLocation::None()
348*795d594fSAndroid Build Coastguard Worker       : dex_register_catalog_.GetRow(index).GetLocation();
349*795d594fSAndroid Build Coastguard Worker   }
350*795d594fSAndroid Build Coastguard Worker 
HasInlineInfo()351*795d594fSAndroid Build Coastguard Worker   bool HasInlineInfo() const {
352*795d594fSAndroid Build Coastguard Worker     return inline_infos_.NumRows() > 0;
353*795d594fSAndroid Build Coastguard Worker   }
354*795d594fSAndroid Build Coastguard Worker 
GetNumberOfStackMaps()355*795d594fSAndroid Build Coastguard Worker   uint32_t GetNumberOfStackMaps() const {
356*795d594fSAndroid Build Coastguard Worker     return stack_maps_.NumRows();
357*795d594fSAndroid Build Coastguard Worker   }
358*795d594fSAndroid Build Coastguard Worker 
GetMethodInfoOf(InlineInfo inline_info)359*795d594fSAndroid Build Coastguard Worker   MethodInfo GetMethodInfoOf(InlineInfo inline_info) const {
360*795d594fSAndroid Build Coastguard Worker     return method_infos_.GetRow(inline_info.GetMethodInfoIndex());
361*795d594fSAndroid Build Coastguard Worker   }
362*795d594fSAndroid Build Coastguard Worker 
GetMethodIndexOf(InlineInfo inline_info)363*795d594fSAndroid Build Coastguard Worker   uint32_t GetMethodIndexOf(InlineInfo inline_info) const {
364*795d594fSAndroid Build Coastguard Worker     return GetMethodInfoOf(inline_info).GetMethodIndex();
365*795d594fSAndroid Build Coastguard Worker   }
366*795d594fSAndroid Build Coastguard Worker 
367*795d594fSAndroid Build Coastguard Worker   // Returns the dex registers for `stack_map`, ignoring any inlined dex registers.
GetDexRegisterMapOf(StackMap stack_map)368*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map) const {
369*795d594fSAndroid Build Coastguard Worker     return GetDexRegisterMapOf(stack_map, /* first= */ 0, number_of_dex_registers_);
370*795d594fSAndroid Build Coastguard Worker   }
371*795d594fSAndroid Build Coastguard Worker 
372*795d594fSAndroid Build Coastguard Worker   // Returns the dex register map of `inline_info`, and just those registers.
GetInlineDexRegisterMapOf(StackMap stack_map,InlineInfo inline_info)373*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE DexRegisterMap GetInlineDexRegisterMapOf(StackMap stack_map,
374*795d594fSAndroid Build Coastguard Worker                                                          InlineInfo inline_info) const {
375*795d594fSAndroid Build Coastguard Worker     if (stack_map.HasDexRegisterMap()) {
376*795d594fSAndroid Build Coastguard Worker       DCHECK(stack_map.HasInlineInfoIndex());
377*795d594fSAndroid Build Coastguard Worker       uint32_t depth = inline_info.Row() - stack_map.GetInlineInfoIndex();
378*795d594fSAndroid Build Coastguard Worker       // The register counts are commutative and include all outer levels.
379*795d594fSAndroid Build Coastguard Worker       // This allows us to determine the range [first, last) in just two lookups.
380*795d594fSAndroid Build Coastguard Worker       // If we are at depth 0 (the first inlinee), the count from the main method is used.
381*795d594fSAndroid Build Coastguard Worker       uint32_t first = (depth == 0)
382*795d594fSAndroid Build Coastguard Worker           ? number_of_dex_registers_
383*795d594fSAndroid Build Coastguard Worker           : inline_infos_.GetRow(inline_info.Row() - 1).GetNumberOfDexRegisters();
384*795d594fSAndroid Build Coastguard Worker       uint32_t last = inline_info.GetNumberOfDexRegisters();
385*795d594fSAndroid Build Coastguard Worker       return GetDexRegisterMapOf(stack_map, first, last);
386*795d594fSAndroid Build Coastguard Worker     }
387*795d594fSAndroid Build Coastguard Worker     return DexRegisterMap(0, DexRegisterLocation::None());
388*795d594fSAndroid Build Coastguard Worker   }
389*795d594fSAndroid Build Coastguard Worker 
390*795d594fSAndroid Build Coastguard Worker   // Returns the dex register map of `stack_map` in the range the range [first, last).
GetDexRegisterMapOf(StackMap stack_map,uint32_t first,uint32_t last)391*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
392*795d594fSAndroid Build Coastguard Worker                                                    uint32_t first,
393*795d594fSAndroid Build Coastguard Worker                                                    uint32_t last) const {
394*795d594fSAndroid Build Coastguard Worker     if (stack_map.HasDexRegisterMap()) {
395*795d594fSAndroid Build Coastguard Worker       DCHECK_LE(first, last);
396*795d594fSAndroid Build Coastguard Worker       DexRegisterMap map(last - first, DexRegisterLocation::Invalid());
397*795d594fSAndroid Build Coastguard Worker       DecodeDexRegisterMap(stack_map.Row(), first, &map);
398*795d594fSAndroid Build Coastguard Worker       return map;
399*795d594fSAndroid Build Coastguard Worker     }
400*795d594fSAndroid Build Coastguard Worker     return DexRegisterMap(0, DexRegisterLocation::None());
401*795d594fSAndroid Build Coastguard Worker   }
402*795d594fSAndroid Build Coastguard Worker 
GetInlineInfosOf(StackMap stack_map)403*795d594fSAndroid Build Coastguard Worker   BitTableRange<InlineInfo> GetInlineInfosOf(StackMap stack_map) const {
404*795d594fSAndroid Build Coastguard Worker     uint32_t index = stack_map.GetInlineInfoIndex();
405*795d594fSAndroid Build Coastguard Worker     if (index != StackMap::kNoValue) {
406*795d594fSAndroid Build Coastguard Worker       auto begin = inline_infos_.begin() + index;
407*795d594fSAndroid Build Coastguard Worker       auto end = begin;
408*795d594fSAndroid Build Coastguard Worker       while ((*end++).GetIsLast() == InlineInfo::kMore) { }
409*795d594fSAndroid Build Coastguard Worker       return BitTableRange<InlineInfo>(begin, end);
410*795d594fSAndroid Build Coastguard Worker     } else {
411*795d594fSAndroid Build Coastguard Worker       return BitTableRange<InlineInfo>();
412*795d594fSAndroid Build Coastguard Worker     }
413*795d594fSAndroid Build Coastguard Worker   }
414*795d594fSAndroid Build Coastguard Worker 
GetStackMapForDexPc(uint32_t dex_pc)415*795d594fSAndroid Build Coastguard Worker   StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
416*795d594fSAndroid Build Coastguard Worker     for (StackMap stack_map : stack_maps_) {
417*795d594fSAndroid Build Coastguard Worker       if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() != StackMap::Kind::Debug) {
418*795d594fSAndroid Build Coastguard Worker         return stack_map;
419*795d594fSAndroid Build Coastguard Worker       }
420*795d594fSAndroid Build Coastguard Worker     }
421*795d594fSAndroid Build Coastguard Worker     return stack_maps_.GetInvalidRow();
422*795d594fSAndroid Build Coastguard Worker   }
423*795d594fSAndroid Build Coastguard Worker 
GetCatchStackMapForDexPc(ArrayRef<const uint32_t> dex_pcs)424*795d594fSAndroid Build Coastguard Worker   StackMap GetCatchStackMapForDexPc(ArrayRef<const uint32_t> dex_pcs) const {
425*795d594fSAndroid Build Coastguard Worker     // Searches the stack map list backwards because catch stack maps are stored at the end.
426*795d594fSAndroid Build Coastguard Worker     for (size_t i = GetNumberOfStackMaps(); i > 0; --i) {
427*795d594fSAndroid Build Coastguard Worker       StackMap stack_map = GetStackMapAt(i - 1);
428*795d594fSAndroid Build Coastguard Worker       if (UNLIKELY(stack_map.GetKind() != StackMap::Kind::Catch)) {
429*795d594fSAndroid Build Coastguard Worker         // Early break since we should have catch stack maps only at the end.
430*795d594fSAndroid Build Coastguard Worker         if (kIsDebugBuild) {
431*795d594fSAndroid Build Coastguard Worker           for (size_t j = i - 1; j > 0; --j) {
432*795d594fSAndroid Build Coastguard Worker             DCHECK(GetStackMapAt(j - 1).GetKind() != StackMap::Kind::Catch);
433*795d594fSAndroid Build Coastguard Worker           }
434*795d594fSAndroid Build Coastguard Worker         }
435*795d594fSAndroid Build Coastguard Worker         break;
436*795d594fSAndroid Build Coastguard Worker       }
437*795d594fSAndroid Build Coastguard Worker 
438*795d594fSAndroid Build Coastguard Worker       // Both the handler dex_pc and all of the inline dex_pcs have to match i.e. we want dex_pcs to
439*795d594fSAndroid Build Coastguard Worker       // be [stack_map_dex_pc, inline_dex_pc_1, ..., inline_dex_pc_n].
440*795d594fSAndroid Build Coastguard Worker       if (stack_map.GetDexPc() != dex_pcs.front()) {
441*795d594fSAndroid Build Coastguard Worker         continue;
442*795d594fSAndroid Build Coastguard Worker       }
443*795d594fSAndroid Build Coastguard Worker 
444*795d594fSAndroid Build Coastguard Worker       const BitTableRange<InlineInfo>& inline_infos = GetInlineInfosOf(stack_map);
445*795d594fSAndroid Build Coastguard Worker       if (inline_infos.size() == dex_pcs.size() - 1) {
446*795d594fSAndroid Build Coastguard Worker         bool matching_dex_pcs = true;
447*795d594fSAndroid Build Coastguard Worker         for (size_t inline_info_index = 0; inline_info_index < inline_infos.size();
448*795d594fSAndroid Build Coastguard Worker              ++inline_info_index) {
449*795d594fSAndroid Build Coastguard Worker           if (inline_infos[inline_info_index].GetDexPc() != dex_pcs[inline_info_index + 1]) {
450*795d594fSAndroid Build Coastguard Worker             matching_dex_pcs = false;
451*795d594fSAndroid Build Coastguard Worker             break;
452*795d594fSAndroid Build Coastguard Worker           }
453*795d594fSAndroid Build Coastguard Worker         }
454*795d594fSAndroid Build Coastguard Worker         if (matching_dex_pcs) {
455*795d594fSAndroid Build Coastguard Worker           return stack_map;
456*795d594fSAndroid Build Coastguard Worker         }
457*795d594fSAndroid Build Coastguard Worker       }
458*795d594fSAndroid Build Coastguard Worker     }
459*795d594fSAndroid Build Coastguard Worker     return stack_maps_.GetInvalidRow();
460*795d594fSAndroid Build Coastguard Worker   }
461*795d594fSAndroid Build Coastguard Worker 
GetOsrStackMapForDexPc(uint32_t dex_pc)462*795d594fSAndroid Build Coastguard Worker   StackMap GetOsrStackMapForDexPc(uint32_t dex_pc) const {
463*795d594fSAndroid Build Coastguard Worker     for (StackMap stack_map : stack_maps_) {
464*795d594fSAndroid Build Coastguard Worker       if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() == StackMap::Kind::OSR) {
465*795d594fSAndroid Build Coastguard Worker         return stack_map;
466*795d594fSAndroid Build Coastguard Worker       }
467*795d594fSAndroid Build Coastguard Worker     }
468*795d594fSAndroid Build Coastguard Worker     return stack_maps_.GetInvalidRow();
469*795d594fSAndroid Build Coastguard Worker   }
470*795d594fSAndroid Build Coastguard Worker 
471*795d594fSAndroid Build Coastguard Worker   EXPORT StackMap GetStackMapForNativePcOffset(uintptr_t pc,
472*795d594fSAndroid Build Coastguard Worker                                                InstructionSet isa = kRuntimeQuickCodeISA) const;
473*795d594fSAndroid Build Coastguard Worker 
474*795d594fSAndroid Build Coastguard Worker   // Dump this CodeInfo object on `vios`.
475*795d594fSAndroid Build Coastguard Worker   // `code_offset` is the (absolute) native PC of the compiled method.
476*795d594fSAndroid Build Coastguard Worker   EXPORT void Dump(VariableIndentationOutputStream* vios,
477*795d594fSAndroid Build Coastguard Worker                    uint32_t code_offset,
478*795d594fSAndroid Build Coastguard Worker                    bool verbose,
479*795d594fSAndroid Build Coastguard Worker                    InstructionSet instruction_set) const;
480*795d594fSAndroid Build Coastguard Worker 
481*795d594fSAndroid Build Coastguard Worker   // Accumulate code info size statistics into the given Stats tree.
482*795d594fSAndroid Build Coastguard Worker   EXPORT static void CollectSizeStats(const uint8_t* code_info, /*out*/ Stats& parent);
483*795d594fSAndroid Build Coastguard Worker 
484*795d594fSAndroid Build Coastguard Worker   template <uint32_t kFlag>
HasFlag(const uint8_t * code_info_data)485*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static bool HasFlag(const uint8_t* code_info_data) {
486*795d594fSAndroid Build Coastguard Worker     // Fast path - read just the one specific bit from the header.
487*795d594fSAndroid Build Coastguard Worker     bool result;
488*795d594fSAndroid Build Coastguard Worker     uint8_t varint = (*code_info_data) & MaxInt<uint8_t>(kVarintBits);
489*795d594fSAndroid Build Coastguard Worker     if (LIKELY(varint <= kVarintMax)) {
490*795d594fSAndroid Build Coastguard Worker       result = (varint & kFlag) != 0;
491*795d594fSAndroid Build Coastguard Worker     } else {
492*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(varint, kVarintMax + 1);  // Only up to 8 flags are supported for now.
493*795d594fSAndroid Build Coastguard Worker       constexpr uint32_t bit_offset = kNumHeaders * kVarintBits + WhichPowerOf2(kFlag);
494*795d594fSAndroid Build Coastguard Worker       result = (code_info_data[bit_offset / kBitsPerByte] & (1 << bit_offset % kBitsPerByte)) != 0;
495*795d594fSAndroid Build Coastguard Worker     }
496*795d594fSAndroid Build Coastguard Worker     // Slow path - dcheck that we got the correct result against the naive implementation.
497*795d594fSAndroid Build Coastguard Worker     BitMemoryReader reader(code_info_data);
498*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(result, (reader.ReadInterleavedVarints<kNumHeaders>()[0] & kFlag) != 0);
499*795d594fSAndroid Build Coastguard Worker     return result;
500*795d594fSAndroid Build Coastguard Worker   }
501*795d594fSAndroid Build Coastguard Worker 
HasInlineInfo(const uint8_t * code_info_data)502*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static bool HasInlineInfo(const uint8_t* code_info_data) {
503*795d594fSAndroid Build Coastguard Worker     return HasFlag<kHasInlineInfo>(code_info_data);
504*795d594fSAndroid Build Coastguard Worker   }
505*795d594fSAndroid Build Coastguard Worker 
HasShouldDeoptimizeFlag(const uint8_t * code_info_data)506*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static bool HasShouldDeoptimizeFlag(const uint8_t* code_info_data) {
507*795d594fSAndroid Build Coastguard Worker     return HasFlag<kHasShouldDeoptimizeFlag>(code_info_data);
508*795d594fSAndroid Build Coastguard Worker   }
509*795d594fSAndroid Build Coastguard Worker 
IsBaseline(const uint8_t * code_info_data)510*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static bool IsBaseline(const uint8_t* code_info_data) {
511*795d594fSAndroid Build Coastguard Worker     return HasFlag<kIsBaseline>(code_info_data);
512*795d594fSAndroid Build Coastguard Worker   }
513*795d594fSAndroid Build Coastguard Worker 
IsDebuggable(const uint8_t * code_info_data)514*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static bool IsDebuggable(const uint8_t* code_info_data) {
515*795d594fSAndroid Build Coastguard Worker     return HasFlag<kIsDebuggable>(code_info_data);
516*795d594fSAndroid Build Coastguard Worker   }
517*795d594fSAndroid Build Coastguard Worker 
GetNumberOfDexRegisters()518*795d594fSAndroid Build Coastguard Worker   uint32_t GetNumberOfDexRegisters() {
519*795d594fSAndroid Build Coastguard Worker     return number_of_dex_registers_;
520*795d594fSAndroid Build Coastguard Worker   }
521*795d594fSAndroid Build Coastguard Worker 
522*795d594fSAndroid Build Coastguard Worker  private:
523*795d594fSAndroid Build Coastguard Worker   // Scan backward to determine dex register locations at given stack map.
524*795d594fSAndroid Build Coastguard Worker   EXPORT void DecodeDexRegisterMap(uint32_t stack_map_index,
525*795d594fSAndroid Build Coastguard Worker                                    uint32_t first_dex_register,
526*795d594fSAndroid Build Coastguard Worker                                    /*out*/ DexRegisterMap* map) const;
527*795d594fSAndroid Build Coastguard Worker 
528*795d594fSAndroid Build Coastguard Worker   template<typename DecodeCallback>  // (size_t index, BitTable<...>*, BitMemoryRegion).
529*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE CodeInfo(const uint8_t* data, size_t* num_read_bits, DecodeCallback callback);
530*795d594fSAndroid Build Coastguard Worker 
531*795d594fSAndroid Build Coastguard Worker   // Invokes the callback with index and member pointer of each header field.
532*795d594fSAndroid Build Coastguard Worker   template<typename Callback>
ForEachHeaderField(Callback callback)533*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static void ForEachHeaderField(Callback callback) {
534*795d594fSAndroid Build Coastguard Worker     size_t index = 0;
535*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::flags_);
536*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::code_size_);
537*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::packed_frame_size_);
538*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::core_spill_mask_);
539*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::fp_spill_mask_);
540*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::number_of_dex_registers_);
541*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::bit_table_flags_);
542*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(index, kNumHeaders);
543*795d594fSAndroid Build Coastguard Worker   }
544*795d594fSAndroid Build Coastguard Worker 
545*795d594fSAndroid Build Coastguard Worker   // Invokes the callback with index and member pointer of each BitTable field.
546*795d594fSAndroid Build Coastguard Worker   template<typename Callback>
ForEachBitTableField(Callback callback)547*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static void ForEachBitTableField(Callback callback) {
548*795d594fSAndroid Build Coastguard Worker     size_t index = 0;
549*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::stack_maps_);
550*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::register_masks_);
551*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::stack_masks_);
552*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::inline_infos_);
553*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::method_infos_);
554*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::dex_register_masks_);
555*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::dex_register_maps_);
556*795d594fSAndroid Build Coastguard Worker     callback(index++, &CodeInfo::dex_register_catalog_);
557*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(index, kNumBitTables);
558*795d594fSAndroid Build Coastguard Worker   }
559*795d594fSAndroid Build Coastguard Worker 
HasBitTable(size_t i)560*795d594fSAndroid Build Coastguard Worker   bool HasBitTable(size_t i) { return ((bit_table_flags_ >> i) & 1) != 0; }
IsBitTableDeduped(size_t i)561*795d594fSAndroid Build Coastguard Worker   bool IsBitTableDeduped(size_t i) { return ((bit_table_flags_ >> (kNumBitTables + i)) & 1) != 0; }
SetBitTableDeduped(size_t i)562*795d594fSAndroid Build Coastguard Worker   void SetBitTableDeduped(size_t i) { bit_table_flags_ |= 1 << (kNumBitTables + i); }
HasDedupedBitTables()563*795d594fSAndroid Build Coastguard Worker   bool HasDedupedBitTables() { return (bit_table_flags_ >> kNumBitTables) != 0u; }
564*795d594fSAndroid Build Coastguard Worker 
565*795d594fSAndroid Build Coastguard Worker   // NB: The first three flags should be the most common ones.
566*795d594fSAndroid Build Coastguard Worker   //     Maximum of 8 flags is supported right now (see the HasFlag method).
567*795d594fSAndroid Build Coastguard Worker   enum Flags {
568*795d594fSAndroid Build Coastguard Worker     kHasInlineInfo = 1 << 0,
569*795d594fSAndroid Build Coastguard Worker     kHasShouldDeoptimizeFlag = 1 << 1,
570*795d594fSAndroid Build Coastguard Worker     kIsBaseline = 1 << 2,
571*795d594fSAndroid Build Coastguard Worker     kIsDebuggable = 1 << 3,
572*795d594fSAndroid Build Coastguard Worker   };
573*795d594fSAndroid Build Coastguard Worker 
574*795d594fSAndroid Build Coastguard Worker   // The CodeInfo starts with sequence of variable-length bit-encoded integers.
575*795d594fSAndroid Build Coastguard Worker   // (Please see kVarintMax for more details about encoding).
576*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kNumHeaders = 7;
577*795d594fSAndroid Build Coastguard Worker   uint32_t flags_ = 0;
578*795d594fSAndroid Build Coastguard Worker   uint32_t code_size_ = 0;  // The size of native PC range in bytes.
579*795d594fSAndroid Build Coastguard Worker   uint32_t packed_frame_size_ = 0;  // Frame size in kStackAlignment units.
580*795d594fSAndroid Build Coastguard Worker   uint32_t core_spill_mask_ = 0;
581*795d594fSAndroid Build Coastguard Worker   uint32_t fp_spill_mask_ = 0;
582*795d594fSAndroid Build Coastguard Worker   uint32_t number_of_dex_registers_ = 0;
583*795d594fSAndroid Build Coastguard Worker   uint32_t bit_table_flags_ = 0;
584*795d594fSAndroid Build Coastguard Worker 
585*795d594fSAndroid Build Coastguard Worker   // The encoded bit-tables follow the header.  Based on the above flags field,
586*795d594fSAndroid Build Coastguard Worker   // bit-tables might be omitted or replaced by relative bit-offset if deduped.
587*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kNumBitTables = 8;
588*795d594fSAndroid Build Coastguard Worker   BitTable<StackMap> stack_maps_;
589*795d594fSAndroid Build Coastguard Worker   BitTable<RegisterMask> register_masks_;
590*795d594fSAndroid Build Coastguard Worker   BitTable<StackMask> stack_masks_;
591*795d594fSAndroid Build Coastguard Worker   BitTable<InlineInfo> inline_infos_;
592*795d594fSAndroid Build Coastguard Worker   BitTable<MethodInfo> method_infos_;
593*795d594fSAndroid Build Coastguard Worker   BitTable<DexRegisterMask> dex_register_masks_;
594*795d594fSAndroid Build Coastguard Worker   BitTable<DexRegisterMapInfo> dex_register_maps_;
595*795d594fSAndroid Build Coastguard Worker   BitTable<DexRegisterInfo> dex_register_catalog_;
596*795d594fSAndroid Build Coastguard Worker 
597*795d594fSAndroid Build Coastguard Worker   friend class linker::CodeInfoTableDeduper;
598*795d594fSAndroid Build Coastguard Worker   friend class StackMapStream;
599*795d594fSAndroid Build Coastguard Worker };
600*795d594fSAndroid Build Coastguard Worker 
601*795d594fSAndroid Build Coastguard Worker #undef ELEMENT_BYTE_OFFSET_AFTER
602*795d594fSAndroid Build Coastguard Worker #undef ELEMENT_BIT_OFFSET_AFTER
603*795d594fSAndroid Build Coastguard Worker 
604*795d594fSAndroid Build Coastguard Worker }  // namespace art
605*795d594fSAndroid Build Coastguard Worker 
606*795d594fSAndroid Build Coastguard Worker #endif  // ART_RUNTIME_OAT_STACK_MAP_H_
607