blob: 909aaa5576b1189b04c89cd401d10d657d1d4c8e [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"
David Sehr1ce2b3b2018-04-05 11:02:03 -070023#include "base/bit_memory_region.h"
David Srbecky052f8ca2018-04-26 15:42:54 +010024#include "base/bit_table.h"
Vladimir Marko80afd022015-05-19 18:08:00 +010025#include "base/bit_utils.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070026#include "base/bit_vector.h"
David Sehr67bf42e2018-02-26 16:43:04 -080027#include "base/leb128.h"
David Sehr1ce2b3b2018-04-05 11:02:03 -070028#include "base/memory_region.h"
David Sehr9e734c72018-01-04 17:56:19 -080029#include "dex/dex_file_types.h"
David Srbecky71ec1cc2018-05-18 15:57:25 +010030#include "dex_register_location.h"
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -070031#include "method_info.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
David Srbeckyf6ba5b32018-06-23 22:05:49 +010036class OatQuickMethodHeader;
Vladimir Marko8f1e08a2015-06-26 12:06:30 +010037class VariableIndentationOutputStream;
38
Roland Levillaina2d8ec62015-03-12 15:25:29 +000039// Size of a frame slot, in bytes. This constant is a signed value,
40// to please the compiler in arithmetic operations involving int32_t
41// (signed) values.
Roland Levillaina552e1c2015-03-26 15:01:03 +000042static constexpr ssize_t kFrameSlotSize = 4;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000043
David Srbecky6de88332018-06-03 12:00:11 +010044// The delta compression of dex register maps means we need to scan the stackmaps backwards.
45// We compress the data in such a way so that there is an upper bound on the search distance.
46// Max distance 0 means each stack map must be fully defined and no scanning back is allowed.
47// If this value is changed, the oat file version should be incremented (for DCHECK to pass).
48static constexpr size_t kMaxDexRegisterMapSearchDistance = 32;
49
Nicolas Geoffray5d37c152017-01-12 13:25:19 +000050class ArtMethod;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000051class CodeInfo;
David Srbecky86decb62018-06-05 06:41:10 +010052class Stats;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000053
David Srbecky71ec1cc2018-05-18 15:57:25 +010054std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010055
David Srbecky71ec1cc2018-05-18 15:57:25 +010056// Information on Dex register locations for a specific PC.
57// Effectively just a convenience wrapper for DexRegisterLocation vector.
58// If the size is small enough, it keeps the data on the stack.
David Srbeckye1402122018-06-13 18:20:45 +010059// TODO: Replace this with generic purpose "small-vector" implementation.
Roland Levillaina552e1c2015-03-26 15:01:03 +000060class DexRegisterMap {
61 public:
David Srbecky6de88332018-06-03 12:00:11 +010062 using iterator = DexRegisterLocation*;
David Srbeckye1402122018-06-13 18:20:45 +010063 using const_iterator = const DexRegisterLocation*;
David Srbecky6de88332018-06-03 12:00:11 +010064
65 // Create map for given number of registers and initialize them to the given value.
66 DexRegisterMap(size_t count, DexRegisterLocation value) : count_(count), regs_small_{} {
David Srbecky71ec1cc2018-05-18 15:57:25 +010067 if (count_ <= kSmallCount) {
David Srbecky6de88332018-06-03 12:00:11 +010068 std::fill_n(regs_small_.begin(), count, value);
David Srbecky71ec1cc2018-05-18 15:57:25 +010069 } else {
David Srbecky6de88332018-06-03 12:00:11 +010070 regs_large_.resize(count, value);
David Srbecky71ec1cc2018-05-18 15:57:25 +010071 }
Roland Levillaina552e1c2015-03-26 15:01:03 +000072 }
73
David Srbecky71ec1cc2018-05-18 15:57:25 +010074 DexRegisterLocation* data() {
75 return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
76 }
David Srbeckye1402122018-06-13 18:20:45 +010077 const DexRegisterLocation* data() const {
78 return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
79 }
Roland Levillaina552e1c2015-03-26 15:01:03 +000080
David Srbecky6de88332018-06-03 12:00:11 +010081 iterator begin() { return data(); }
82 iterator end() { return data() + count_; }
David Srbeckye1402122018-06-13 18:20:45 +010083 const_iterator begin() const { return data(); }
84 const_iterator end() const { return data() + count_; }
David Srbecky71ec1cc2018-05-18 15:57:25 +010085 size_t size() const { return count_; }
David Srbeckyfd89b072018-06-03 12:00:22 +010086 bool empty() const { return count_ == 0; }
David Srbecky71ec1cc2018-05-18 15:57:25 +010087
David Srbeckye1402122018-06-13 18:20:45 +010088 DexRegisterLocation& operator[](size_t index) {
David Srbecky71ec1cc2018-05-18 15:57:25 +010089 DCHECK_LT(index, count_);
David Srbeckye1402122018-06-13 18:20:45 +010090 return data()[index];
David Srbecky71ec1cc2018-05-18 15:57:25 +010091 }
David Srbeckye1402122018-06-13 18:20:45 +010092 const DexRegisterLocation& operator[](size_t index) const {
93 DCHECK_LT(index, count_);
94 return data()[index];
Roland Levillaina552e1c2015-03-26 15:01:03 +000095 }
96
David Srbecky71ec1cc2018-05-18 15:57:25 +010097 size_t GetNumberOfLiveDexRegisters() const {
David Srbeckye1402122018-06-13 18:20:45 +010098 return std::count_if(begin(), end(), [](auto& loc) { return loc.IsLive(); });
Roland Levillaina552e1c2015-03-26 15:01:03 +000099 }
100
David Srbecky71ec1cc2018-05-18 15:57:25 +0100101 bool HasAnyLiveDexRegisters() const {
David Srbeckye1402122018-06-13 18:20:45 +0100102 return std::any_of(begin(), end(), [](auto& loc) { return loc.IsLive(); });
David Srbecky21d45b42018-05-30 06:35:05 +0100103 }
104
David Srbeckye1402122018-06-13 18:20:45 +0100105 void Dump(VariableIndentationOutputStream* vios) const;
106
Roland Levillaina552e1c2015-03-26 15:01:03 +0000107 private:
David Srbecky71ec1cc2018-05-18 15:57:25 +0100108 // Store the data inline if the number of registers is small to avoid memory allocations.
109 // If count_ <= kSmallCount, we use the regs_small_ array, and regs_large_ otherwise.
110 static constexpr size_t kSmallCount = 16;
111 size_t count_;
112 std::array<DexRegisterLocation, kSmallCount> regs_small_;
113 dchecked_vector<DexRegisterLocation> regs_large_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000114};
115
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100116/**
117 * A Stack Map holds compilation information for a specific PC necessary for:
118 * - Mapping it to a dex PC,
119 * - Knowing which stack entries are objects,
120 * - Knowing which registers hold objects,
121 * - Knowing the inlining information,
122 * - Knowing the values of dex registers.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100123 */
David Srbeckycf7833e2018-06-14 16:45:22 +0100124class StackMap : public BitTableAccessor<8> {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100125 public:
David Srbecky50fac062018-06-13 18:55:35 +0100126 enum Kind {
127 Default = -1,
128 Catch = 0,
129 OSR = 1,
130 Debug = 2,
131 };
David Srbeckyd97e0822018-06-03 12:00:24 +0100132 BIT_TABLE_HEADER()
David Srbecky50fac062018-06-13 18:55:35 +0100133 BIT_TABLE_COLUMN(0, Kind)
134 BIT_TABLE_COLUMN(1, PackedNativePc)
135 BIT_TABLE_COLUMN(2, DexPc)
136 BIT_TABLE_COLUMN(3, RegisterMaskIndex)
137 BIT_TABLE_COLUMN(4, StackMaskIndex)
138 BIT_TABLE_COLUMN(5, InlineInfoIndex)
139 BIT_TABLE_COLUMN(6, DexRegisterMaskIndex)
140 BIT_TABLE_COLUMN(7, DexRegisterMapIndex)
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100141
David Srbecky052f8ca2018-04-26 15:42:54 +0100142 ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const {
David Srbeckycf7833e2018-06-14 16:45:22 +0100143 return UnpackNativePc(GetPackedNativePc(), instruction_set);
David Brazdilf677ebf2015-05-29 16:29:43 +0100144 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100145
David Srbeckyd97e0822018-06-03 12:00:24 +0100146 ALWAYS_INLINE bool HasInlineInfo() const {
147 return HasInlineInfoIndex();
148 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100149
David Srbeckyd97e0822018-06-03 12:00:24 +0100150 ALWAYS_INLINE bool HasDexRegisterMap() const {
151 return HasDexRegisterMapIndex();
152 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100153
David Srbeckyd02b23f2018-05-29 23:27:22 +0100154 static uint32_t PackNativePc(uint32_t native_pc, InstructionSet isa) {
David Srbeckyd775f962018-05-30 18:12:52 +0100155 DCHECK_ALIGNED_PARAM(native_pc, GetInstructionSetInstructionAlignment(isa));
David Srbeckyd02b23f2018-05-29 23:27:22 +0100156 return native_pc / GetInstructionSetInstructionAlignment(isa);
157 }
158
159 static uint32_t UnpackNativePc(uint32_t packed_native_pc, InstructionSet isa) {
160 uint32_t native_pc = packed_native_pc * GetInstructionSetInstructionAlignment(isa);
161 DCHECK_EQ(native_pc / GetInstructionSetInstructionAlignment(isa), packed_native_pc);
162 return native_pc;
163 }
164
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100165 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100166 const CodeInfo& code_info,
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700167 const MethodInfo& method_info,
Roland Levillainf2650d12015-05-28 14:53:28 +0100168 uint32_t code_offset,
David Srbecky71ec1cc2018-05-18 15:57:25 +0100169 InstructionSet instruction_set) const;
David Srbecky61b28a12016-02-25 21:55:03 +0000170};
171
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100172/**
David Srbecky052f8ca2018-04-26 15:42:54 +0100173 * Inline information for a specific PC.
174 * The row referenced from the StackMap holds information at depth 0.
175 * Following rows hold information for further depths.
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100176 */
David Srbeckycf7833e2018-06-14 16:45:22 +0100177class InlineInfo : public BitTableAccessor<6> {
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100178 public:
David Srbeckyd97e0822018-06-03 12:00:24 +0100179 BIT_TABLE_HEADER()
180 BIT_TABLE_COLUMN(0, IsLast) // Determines if there are further rows for further depths.
181 BIT_TABLE_COLUMN(1, DexPc)
182 BIT_TABLE_COLUMN(2, MethodInfoIndex)
183 BIT_TABLE_COLUMN(3, ArtMethodHi) // High bits of ArtMethod*.
184 BIT_TABLE_COLUMN(4, ArtMethodLo) // Low bits of ArtMethod*.
David Srbecky6de88332018-06-03 12:00:11 +0100185 BIT_TABLE_COLUMN(5, NumberOfDexRegisters) // Includes outer levels and the main method.
David Srbeckyd97e0822018-06-03 12:00:24 +0100186 BIT_TABLE_COLUMN(6, DexRegisterMapIndex)
187
David Srbecky052f8ca2018-04-26 15:42:54 +0100188 static constexpr uint32_t kLast = -1;
189 static constexpr uint32_t kMore = 0;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100190
David Srbecky6e69e522018-06-03 12:00:14 +0100191 uint32_t GetMethodIndex(const MethodInfo& method_info) const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100192 return method_info.GetMethodIndex(GetMethodInfoIndex());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100193 }
194
David Srbecky6e69e522018-06-03 12:00:14 +0100195 bool EncodesArtMethod() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100196 return HasArtMethodLo();
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100197 }
198
David Srbecky6e69e522018-06-03 12:00:14 +0100199 ArtMethod* GetArtMethod() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100200 uint64_t lo = GetArtMethodLo();
201 uint64_t hi = GetArtMethodHi();
David Srbecky71ec1cc2018-05-18 15:57:25 +0100202 return reinterpret_cast<ArtMethod*>((hi << 32) | lo);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100203 }
204
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100205 void Dump(VariableIndentationOutputStream* vios,
David Srbecky61b28a12016-02-25 21:55:03 +0000206 const CodeInfo& info,
David Srbecky6e69e522018-06-03 12:00:14 +0100207 const StackMap& stack_map,
David Srbeckyfd89b072018-06-03 12:00:22 +0100208 const MethodInfo& method_info) const;
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800209};
210
David Srbeckycf7833e2018-06-14 16:45:22 +0100211class MaskInfo : public BitTableAccessor<1> {
David Srbecky86decb62018-06-05 06:41:10 +0100212 public:
213 BIT_TABLE_HEADER()
214 BIT_TABLE_COLUMN(0, Mask)
215};
216
David Srbeckycf7833e2018-06-14 16:45:22 +0100217class DexRegisterMapInfo : public BitTableAccessor<1> {
David Srbecky86decb62018-06-05 06:41:10 +0100218 public:
219 BIT_TABLE_HEADER()
220 BIT_TABLE_COLUMN(0, CatalogueIndex)
221};
222
David Srbeckycf7833e2018-06-14 16:45:22 +0100223class DexRegisterInfo : public BitTableAccessor<2> {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100224 public:
David Srbeckyd97e0822018-06-03 12:00:24 +0100225 BIT_TABLE_HEADER()
226 BIT_TABLE_COLUMN(0, Kind)
227 BIT_TABLE_COLUMN(1, PackedValue)
David Srbecky71ec1cc2018-05-18 15:57:25 +0100228
229 ALWAYS_INLINE DexRegisterLocation GetLocation() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100230 DexRegisterLocation::Kind kind = static_cast<DexRegisterLocation::Kind>(GetKind());
231 return DexRegisterLocation(kind, UnpackValue(kind, GetPackedValue()));
David Srbecky71ec1cc2018-05-18 15:57:25 +0100232 }
233
234 static uint32_t PackValue(DexRegisterLocation::Kind kind, uint32_t value) {
235 uint32_t packed_value = value;
236 if (kind == DexRegisterLocation::Kind::kInStack) {
237 DCHECK(IsAligned<kFrameSlotSize>(packed_value));
238 packed_value /= kFrameSlotSize;
239 }
240 return packed_value;
241 }
242
243 static uint32_t UnpackValue(DexRegisterLocation::Kind kind, uint32_t packed_value) {
244 uint32_t value = packed_value;
245 if (kind == DexRegisterLocation::Kind::kInStack) {
246 value *= kFrameSlotSize;
247 }
248 return value;
249 }
250};
251
David Srbecky4b59d102018-05-29 21:46:10 +0000252// Register masks tend to have many trailing zero bits (caller-saves are usually not encoded),
253// therefore it is worth encoding the mask as value+shift.
David Srbeckycf7833e2018-06-14 16:45:22 +0100254class RegisterMask : public BitTableAccessor<2> {
David Srbecky4b59d102018-05-29 21:46:10 +0000255 public:
David Srbeckyd97e0822018-06-03 12:00:24 +0100256 BIT_TABLE_HEADER()
257 BIT_TABLE_COLUMN(0, Value)
258 BIT_TABLE_COLUMN(1, Shift)
David Srbecky4b59d102018-05-29 21:46:10 +0000259
260 ALWAYS_INLINE uint32_t GetMask() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100261 return GetValue() << GetShift();
David Srbecky4b59d102018-05-29 21:46:10 +0000262 }
263};
264
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100265/**
266 * Wrapper around all compiler information collected for a method.
David Srbecky71ec1cc2018-05-18 15:57:25 +0100267 * See the Decode method at the end for the precise binary format.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100268 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100269class CodeInfo {
270 public:
David Srbecky6ee06e92018-07-25 21:45:54 +0100271 enum DecodeFlags {
272 Default = 0,
273 // Limits the decoding only to the main stack map table and inline info table.
274 // This is sufficient for many use cases and makes the header decoding faster.
275 InlineInfoOnly = 1,
276 };
277
278 explicit CodeInfo(const uint8_t* data, DecodeFlags flags = DecodeFlags::Default) {
279 Decode(reinterpret_cast<const uint8_t*>(data), flags);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100280 }
281
David Srbecky052f8ca2018-04-26 15:42:54 +0100282 explicit CodeInfo(MemoryRegion region) : CodeInfo(region.begin()) {
David Srbeckya38e6cf2018-06-26 18:13:49 +0100283 DCHECK_EQ(Size(), region.size());
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100284 }
285
David Srbecky6ee06e92018-07-25 21:45:54 +0100286 explicit CodeInfo(const OatQuickMethodHeader* header, DecodeFlags flags = DecodeFlags::Default);
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100287
David Srbecky052f8ca2018-04-26 15:42:54 +0100288 size_t Size() const {
David Srbeckya38e6cf2018-06-26 18:13:49 +0100289 return BitsToBytesRoundUp(size_in_bits_);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000290 }
291
David Srbecky93bd3612018-07-02 19:30:18 +0100292 ALWAYS_INLINE const BitTable<StackMap>& GetStackMaps() const {
293 return stack_maps_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100294 }
295
David Srbecky052f8ca2018-04-26 15:42:54 +0100296 ALWAYS_INLINE StackMap GetStackMapAt(size_t index) const {
David Srbeckycf7833e2018-06-14 16:45:22 +0100297 return stack_maps_.GetRow(index);
David Srbecky45aa5982016-03-18 02:15:09 +0000298 }
299
David Srbecky052f8ca2018-04-26 15:42:54 +0100300 BitMemoryRegion GetStackMask(size_t index) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000301 return stack_masks_.GetBitMemoryRegion(index);
Mathieu Chartier1a20b682017-01-31 14:25:16 -0800302 }
303
David Srbecky052f8ca2018-04-26 15:42:54 +0100304 BitMemoryRegion GetStackMaskOf(const StackMap& stack_map) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000305 uint32_t index = stack_map.GetStackMaskIndex();
306 return (index == StackMap::kNoValue) ? BitMemoryRegion() : GetStackMask(index);
Mathieu Chartier1a20b682017-01-31 14:25:16 -0800307 }
308
David Srbecky052f8ca2018-04-26 15:42:54 +0100309 uint32_t GetRegisterMaskOf(const StackMap& stack_map) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000310 uint32_t index = stack_map.GetRegisterMaskIndex();
David Srbeckycf7833e2018-06-14 16:45:22 +0100311 return (index == StackMap::kNoValue) ? 0 : register_masks_.GetRow(index).GetMask();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100312 }
313
David Srbecky052f8ca2018-04-26 15:42:54 +0100314 uint32_t GetNumberOfLocationCatalogEntries() const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100315 return dex_register_catalog_.NumRows();
Roland Levillaina552e1c2015-03-26 15:01:03 +0000316 }
317
David Srbecky71ec1cc2018-05-18 15:57:25 +0100318 ALWAYS_INLINE DexRegisterLocation GetDexRegisterCatalogEntry(size_t index) const {
David Srbecky6de88332018-06-03 12:00:11 +0100319 return (index == StackMap::kNoValue)
320 ? DexRegisterLocation::None()
David Srbeckycf7833e2018-06-14 16:45:22 +0100321 : dex_register_catalog_.GetRow(index).GetLocation();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100322 }
323
David Srbecky93bd3612018-07-02 19:30:18 +0100324 bool HasInlineInfo() const {
325 return inline_infos_.NumRows() > 0;
326 }
327
David Srbecky052f8ca2018-04-26 15:42:54 +0100328 uint32_t GetNumberOfStackMaps() const {
329 return stack_maps_.NumRows();
Nicolas Geoffray6530baf2015-05-26 15:22:58 +0100330 }
331
David Srbeckyfd89b072018-06-03 12:00:22 +0100332 ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map) const {
David Srbecky6de88332018-06-03 12:00:11 +0100333 if (stack_map.HasDexRegisterMap()) {
334 DexRegisterMap map(number_of_dex_registers_, DexRegisterLocation::Invalid());
335 DecodeDexRegisterMap(stack_map.Row(), /* first_dex_register */ 0, &map);
336 return map;
337 }
338 return DexRegisterMap(0, DexRegisterLocation::None());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100339 }
340
David Srbecky93bd3612018-07-02 19:30:18 +0100341 ALWAYS_INLINE DexRegisterMap GetInlineDexRegisterMapOf(StackMap stack_map,
342 InlineInfo inline_info) const {
David Srbecky6de88332018-06-03 12:00:11 +0100343 if (stack_map.HasDexRegisterMap()) {
David Srbecky93bd3612018-07-02 19:30:18 +0100344 DCHECK(stack_map.HasInlineInfoIndex());
345 uint32_t depth = inline_info.Row() - stack_map.GetInlineInfoIndex();
David Srbecky6de88332018-06-03 12:00:11 +0100346 // The register counts are commutative and include all outer levels.
347 // This allows us to determine the range [first, last) in just two lookups.
348 // If we are at depth 0 (the first inlinee), the count from the main method is used.
David Srbecky93bd3612018-07-02 19:30:18 +0100349 uint32_t first = (depth == 0)
350 ? number_of_dex_registers_
351 : inline_infos_.GetRow(inline_info.Row() - 1).GetNumberOfDexRegisters();
352 uint32_t last = inline_info.GetNumberOfDexRegisters();
David Srbecky6de88332018-06-03 12:00:11 +0100353 DexRegisterMap map(last - first, DexRegisterLocation::Invalid());
354 DecodeDexRegisterMap(stack_map.Row(), first, &map);
355 return map;
356 }
357 return DexRegisterMap(0, DexRegisterLocation::None());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100358 }
359
David Srbecky93bd3612018-07-02 19:30:18 +0100360 BitTableRange<InlineInfo> GetInlineInfosOf(StackMap stack_map) const {
David Srbecky052f8ca2018-04-26 15:42:54 +0100361 uint32_t index = stack_map.GetInlineInfoIndex();
David Srbecky6e69e522018-06-03 12:00:14 +0100362 if (index != StackMap::kNoValue) {
David Srbecky93bd3612018-07-02 19:30:18 +0100363 auto begin = inline_infos_.begin() + index;
364 auto end = begin;
365 while ((*end++).GetIsLast() == InlineInfo::kMore) { }
366 return BitTableRange<InlineInfo>(begin, end);
367 } else {
368 return BitTableRange<InlineInfo>();
David Srbecky6e69e522018-06-03 12:00:14 +0100369 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100370 }
371
David Srbecky052f8ca2018-04-26 15:42:54 +0100372 StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
David Srbecky93bd3612018-07-02 19:30:18 +0100373 for (StackMap stack_map : stack_maps_) {
David Srbecky50fac062018-06-13 18:55:35 +0100374 if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() != StackMap::Kind::Debug) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100375 return stack_map;
376 }
377 }
David Srbeckya45a85c2018-06-21 16:03:12 +0100378 return stack_maps_.GetInvalidRow();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100379 }
380
David Srbecky50fac062018-06-13 18:55:35 +0100381 // Searches the stack map list backwards because catch stack maps are stored at the end.
David Srbecky052f8ca2018-04-26 15:42:54 +0100382 StackMap GetCatchStackMapForDexPc(uint32_t dex_pc) const {
383 for (size_t i = GetNumberOfStackMaps(); i > 0; --i) {
384 StackMap stack_map = GetStackMapAt(i - 1);
David Srbecky50fac062018-06-13 18:55:35 +0100385 if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() == StackMap::Kind::Catch) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000386 return stack_map;
387 }
388 }
David Srbeckya45a85c2018-06-21 16:03:12 +0100389 return stack_maps_.GetInvalidRow();
David Brazdil77a48ae2015-09-15 12:34:04 +0000390 }
391
David Srbecky052f8ca2018-04-26 15:42:54 +0100392 StackMap GetOsrStackMapForDexPc(uint32_t dex_pc) const {
David Srbecky93bd3612018-07-02 19:30:18 +0100393 for (StackMap stack_map : stack_maps_) {
David Srbecky50fac062018-06-13 18:55:35 +0100394 if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() == StackMap::Kind::OSR) {
395 return stack_map;
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000396 }
397 }
David Srbeckya45a85c2018-06-21 16:03:12 +0100398 return stack_maps_.GetInvalidRow();
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000399 }
400
David Srbecky0b4e5a32018-06-11 16:25:29 +0100401 StackMap GetStackMapForNativePcOffset(uint32_t pc, InstructionSet isa = kRuntimeISA) const;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100402
David Srbecky71ec1cc2018-05-18 15:57:25 +0100403 // Dump this CodeInfo object on `vios`.
404 // `code_offset` is the (absolute) native PC of the compiled method.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100405 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100406 uint32_t code_offset,
David Srbecky71ec1cc2018-05-18 15:57:25 +0100407 bool verbose,
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700408 InstructionSet instruction_set,
409 const MethodInfo& method_info) const;
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000410
David Srbecky86decb62018-06-05 06:41:10 +0100411 // Accumulate code info size statistics into the given Stats tree.
412 void AddSizeStats(/*out*/ Stats* parent) const;
413
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100414 ALWAYS_INLINE static QuickMethodFrameInfo DecodeFrameInfo(const uint8_t* data) {
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100415 return QuickMethodFrameInfo(
416 DecodeUnsignedLeb128(&data),
417 DecodeUnsignedLeb128(&data),
418 DecodeUnsignedLeb128(&data));
419 }
420
David Srbeckyb73323c2018-07-15 23:58:44 +0100421 typedef std::map<BitMemoryRegion, uint32_t, BitMemoryRegion::Less> DedupeMap;
422
423 // Copy CodeInfo data while de-duplicating the internal bit tables.
424 // The 'out' vector must be reused between Dedupe calls (it does not have to be empty).
425 // The 'dedupe_map' stores the bit offsets of bit tables within the 'out' vector.
426 // It returns the byte offset of the copied CodeInfo within the 'out' vector.
427 static size_t Dedupe(std::vector<uint8_t>* out,
428 const uint8_t* in,
429 /*inout*/ DedupeMap* dedupe_map);
430
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100431 private:
David Srbecky0b4e5a32018-06-11 16:25:29 +0100432 // Returns lower bound (fist stack map which has pc greater or equal than the desired one).
433 // It ignores catch stack maps at the end (it is the same as if they had maximum pc value).
434 BitTable<StackMap>::const_iterator BinarySearchNativePc(uint32_t packed_pc) const;
435
David Srbecky6de88332018-06-03 12:00:11 +0100436 // Scan backward to determine dex register locations at given stack map.
437 void DecodeDexRegisterMap(uint32_t stack_map_index,
438 uint32_t first_dex_register,
439 /*out*/ DexRegisterMap* map) const;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000440
David Srbecky6ee06e92018-07-25 21:45:54 +0100441 void Decode(const uint8_t* data, DecodeFlags flags);
David Srbecky052f8ca2018-04-26 15:42:54 +0100442
David Srbeckyf6ba5b32018-06-23 22:05:49 +0100443 uint32_t frame_size_in_bytes_;
444 uint32_t core_spill_mask_;
445 uint32_t fp_spill_mask_;
446 uint32_t number_of_dex_registers_;
David Srbeckycf7833e2018-06-14 16:45:22 +0100447 BitTable<StackMap> stack_maps_;
David Srbecky6ee06e92018-07-25 21:45:54 +0100448 BitTable<InlineInfo> inline_infos_;
David Srbeckycf7833e2018-06-14 16:45:22 +0100449 BitTable<RegisterMask> register_masks_;
450 BitTable<MaskInfo> stack_masks_;
David Srbeckycf7833e2018-06-14 16:45:22 +0100451 BitTable<MaskInfo> dex_register_masks_;
452 BitTable<DexRegisterMapInfo> dex_register_maps_;
453 BitTable<DexRegisterInfo> dex_register_catalog_;
David Srbecky6ee06e92018-07-25 21:45:54 +0100454 uint32_t size_in_bits_ = 0;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100455};
456
Roland Levillain1c1da432015-07-16 11:54:44 +0100457#undef ELEMENT_BYTE_OFFSET_AFTER
458#undef ELEMENT_BIT_OFFSET_AFTER
459
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100460} // namespace art
461
462#endif // ART_RUNTIME_STACK_MAP_H_