blob: 64a084f1c22ab902f32fc8c2e0d46c5d1e8e976a [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 Sehr1ce2b3b2018-04-05 11:02:03 -070022#include "base/bit_memory_region.h"
David Srbecky052f8ca2018-04-26 15:42:54 +010023#include "base/bit_table.h"
Vladimir Marko80afd022015-05-19 18:08:00 +010024#include "base/bit_utils.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070025#include "base/bit_vector.h"
David Sehr67bf42e2018-02-26 16:43:04 -080026#include "base/leb128.h"
David Sehr1ce2b3b2018-04-05 11:02:03 -070027#include "base/memory_region.h"
David Sehr9e734c72018-01-04 17:56:19 -080028#include "dex/dex_file_types.h"
David Srbecky71ec1cc2018-05-18 15:57:25 +010029#include "dex_register_location.h"
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -070030#include "method_info.h"
David Srbecky052f8ca2018-04-26 15:42:54 +010031#include "oat_quick_method_header.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010032
33namespace art {
34
Vladimir Marko8f1e08a2015-06-26 12:06:30 +010035class VariableIndentationOutputStream;
36
Roland Levillaina2d8ec62015-03-12 15:25:29 +000037// Size of a frame slot, in bytes. This constant is a signed value,
38// to please the compiler in arithmetic operations involving int32_t
39// (signed) values.
Roland Levillaina552e1c2015-03-26 15:01:03 +000040static constexpr ssize_t kFrameSlotSize = 4;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000041
David Srbecky6de88332018-06-03 12:00:11 +010042// The delta compression of dex register maps means we need to scan the stackmaps backwards.
43// We compress the data in such a way so that there is an upper bound on the search distance.
44// Max distance 0 means each stack map must be fully defined and no scanning back is allowed.
45// If this value is changed, the oat file version should be incremented (for DCHECK to pass).
46static constexpr size_t kMaxDexRegisterMapSearchDistance = 32;
47
Nicolas Geoffray5d37c152017-01-12 13:25:19 +000048class ArtMethod;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000049class CodeInfo;
David Srbecky86decb62018-06-05 06:41:10 +010050class Stats;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000051
David Srbecky71ec1cc2018-05-18 15:57:25 +010052std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010053
David Srbecky71ec1cc2018-05-18 15:57:25 +010054// Information on Dex register locations for a specific PC.
55// Effectively just a convenience wrapper for DexRegisterLocation vector.
56// If the size is small enough, it keeps the data on the stack.
David Srbeckye1402122018-06-13 18:20:45 +010057// TODO: Replace this with generic purpose "small-vector" implementation.
Roland Levillaina552e1c2015-03-26 15:01:03 +000058class DexRegisterMap {
59 public:
David Srbecky6de88332018-06-03 12:00:11 +010060 using iterator = DexRegisterLocation*;
David Srbeckye1402122018-06-13 18:20:45 +010061 using const_iterator = const DexRegisterLocation*;
David Srbecky6de88332018-06-03 12:00:11 +010062
63 // Create map for given number of registers and initialize them to the given value.
64 DexRegisterMap(size_t count, DexRegisterLocation value) : count_(count), regs_small_{} {
David Srbecky71ec1cc2018-05-18 15:57:25 +010065 if (count_ <= kSmallCount) {
David Srbecky6de88332018-06-03 12:00:11 +010066 std::fill_n(regs_small_.begin(), count, value);
David Srbecky71ec1cc2018-05-18 15:57:25 +010067 } else {
David Srbecky6de88332018-06-03 12:00:11 +010068 regs_large_.resize(count, value);
David Srbecky71ec1cc2018-05-18 15:57:25 +010069 }
Roland Levillaina552e1c2015-03-26 15:01:03 +000070 }
71
David Srbecky71ec1cc2018-05-18 15:57:25 +010072 DexRegisterLocation* data() {
73 return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
74 }
David Srbeckye1402122018-06-13 18:20:45 +010075 const DexRegisterLocation* data() const {
76 return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
77 }
Roland Levillaina552e1c2015-03-26 15:01:03 +000078
David Srbecky6de88332018-06-03 12:00:11 +010079 iterator begin() { return data(); }
80 iterator end() { return data() + count_; }
David Srbeckye1402122018-06-13 18:20:45 +010081 const_iterator begin() const { return data(); }
82 const_iterator end() const { return data() + count_; }
David Srbecky71ec1cc2018-05-18 15:57:25 +010083 size_t size() const { return count_; }
David Srbeckyfd89b072018-06-03 12:00:22 +010084 bool empty() const { return count_ == 0; }
David Srbecky71ec1cc2018-05-18 15:57:25 +010085
David Srbeckye1402122018-06-13 18:20:45 +010086 DexRegisterLocation& operator[](size_t index) {
David Srbecky71ec1cc2018-05-18 15:57:25 +010087 DCHECK_LT(index, count_);
David Srbeckye1402122018-06-13 18:20:45 +010088 return data()[index];
David Srbecky71ec1cc2018-05-18 15:57:25 +010089 }
David Srbeckye1402122018-06-13 18:20:45 +010090 const DexRegisterLocation& operator[](size_t index) const {
91 DCHECK_LT(index, count_);
92 return data()[index];
Roland Levillaina552e1c2015-03-26 15:01:03 +000093 }
94
David Srbecky71ec1cc2018-05-18 15:57:25 +010095 size_t GetNumberOfLiveDexRegisters() const {
David Srbeckye1402122018-06-13 18:20:45 +010096 return std::count_if(begin(), end(), [](auto& loc) { return loc.IsLive(); });
Roland Levillaina552e1c2015-03-26 15:01:03 +000097 }
98
David Srbecky71ec1cc2018-05-18 15:57:25 +010099 bool HasAnyLiveDexRegisters() const {
David Srbeckye1402122018-06-13 18:20:45 +0100100 return std::any_of(begin(), end(), [](auto& loc) { return loc.IsLive(); });
David Srbecky21d45b42018-05-30 06:35:05 +0100101 }
102
David Srbeckye1402122018-06-13 18:20:45 +0100103 void Dump(VariableIndentationOutputStream* vios) const;
104
Roland Levillaina552e1c2015-03-26 15:01:03 +0000105 private:
David Srbecky71ec1cc2018-05-18 15:57:25 +0100106 // Store the data inline if the number of registers is small to avoid memory allocations.
107 // If count_ <= kSmallCount, we use the regs_small_ array, and regs_large_ otherwise.
108 static constexpr size_t kSmallCount = 16;
109 size_t count_;
110 std::array<DexRegisterLocation, kSmallCount> regs_small_;
111 dchecked_vector<DexRegisterLocation> regs_large_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000112};
113
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100114/**
115 * A Stack Map holds compilation information for a specific PC necessary for:
116 * - Mapping it to a dex PC,
117 * - Knowing which stack entries are objects,
118 * - Knowing which registers hold objects,
119 * - Knowing the inlining information,
120 * - Knowing the values of dex registers.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100121 */
David Srbeckycf7833e2018-06-14 16:45:22 +0100122class StackMap : public BitTableAccessor<8> {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100123 public:
David Srbecky50fac062018-06-13 18:55:35 +0100124 enum Kind {
125 Default = -1,
126 Catch = 0,
127 OSR = 1,
128 Debug = 2,
129 };
David Srbeckyd97e0822018-06-03 12:00:24 +0100130 BIT_TABLE_HEADER()
David Srbecky50fac062018-06-13 18:55:35 +0100131 BIT_TABLE_COLUMN(0, Kind)
132 BIT_TABLE_COLUMN(1, PackedNativePc)
133 BIT_TABLE_COLUMN(2, DexPc)
134 BIT_TABLE_COLUMN(3, RegisterMaskIndex)
135 BIT_TABLE_COLUMN(4, StackMaskIndex)
136 BIT_TABLE_COLUMN(5, InlineInfoIndex)
137 BIT_TABLE_COLUMN(6, DexRegisterMaskIndex)
138 BIT_TABLE_COLUMN(7, DexRegisterMapIndex)
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100139
David Srbecky052f8ca2018-04-26 15:42:54 +0100140 ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const {
David Srbeckycf7833e2018-06-14 16:45:22 +0100141 return UnpackNativePc(GetPackedNativePc(), instruction_set);
David Brazdilf677ebf2015-05-29 16:29:43 +0100142 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100143
David Srbeckyd97e0822018-06-03 12:00:24 +0100144 ALWAYS_INLINE bool HasInlineInfo() const {
145 return HasInlineInfoIndex();
146 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100147
David Srbeckyd97e0822018-06-03 12:00:24 +0100148 ALWAYS_INLINE bool HasDexRegisterMap() const {
149 return HasDexRegisterMapIndex();
150 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100151
David Srbeckyd02b23f2018-05-29 23:27:22 +0100152 static uint32_t PackNativePc(uint32_t native_pc, InstructionSet isa) {
David Srbeckyd775f962018-05-30 18:12:52 +0100153 DCHECK_ALIGNED_PARAM(native_pc, GetInstructionSetInstructionAlignment(isa));
David Srbeckyd02b23f2018-05-29 23:27:22 +0100154 return native_pc / GetInstructionSetInstructionAlignment(isa);
155 }
156
157 static uint32_t UnpackNativePc(uint32_t packed_native_pc, InstructionSet isa) {
158 uint32_t native_pc = packed_native_pc * GetInstructionSetInstructionAlignment(isa);
159 DCHECK_EQ(native_pc / GetInstructionSetInstructionAlignment(isa), packed_native_pc);
160 return native_pc;
161 }
162
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100163 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100164 const CodeInfo& code_info,
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700165 const MethodInfo& method_info,
Roland Levillainf2650d12015-05-28 14:53:28 +0100166 uint32_t code_offset,
David Srbecky71ec1cc2018-05-18 15:57:25 +0100167 InstructionSet instruction_set) const;
David Srbecky61b28a12016-02-25 21:55:03 +0000168};
169
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100170/**
David Srbecky052f8ca2018-04-26 15:42:54 +0100171 * Inline information for a specific PC.
172 * The row referenced from the StackMap holds information at depth 0.
173 * Following rows hold information for further depths.
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100174 */
David Srbeckycf7833e2018-06-14 16:45:22 +0100175class InlineInfo : public BitTableAccessor<6> {
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100176 public:
David Srbeckyd97e0822018-06-03 12:00:24 +0100177 BIT_TABLE_HEADER()
178 BIT_TABLE_COLUMN(0, IsLast) // Determines if there are further rows for further depths.
179 BIT_TABLE_COLUMN(1, DexPc)
180 BIT_TABLE_COLUMN(2, MethodInfoIndex)
181 BIT_TABLE_COLUMN(3, ArtMethodHi) // High bits of ArtMethod*.
182 BIT_TABLE_COLUMN(4, ArtMethodLo) // Low bits of ArtMethod*.
David Srbecky6de88332018-06-03 12:00:11 +0100183 BIT_TABLE_COLUMN(5, NumberOfDexRegisters) // Includes outer levels and the main method.
David Srbeckyd97e0822018-06-03 12:00:24 +0100184 BIT_TABLE_COLUMN(6, DexRegisterMapIndex)
185
David Srbecky052f8ca2018-04-26 15:42:54 +0100186 static constexpr uint32_t kLast = -1;
187 static constexpr uint32_t kMore = 0;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100188
David Srbecky6e69e522018-06-03 12:00:14 +0100189 uint32_t GetMethodIndex(const MethodInfo& method_info) const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100190 return method_info.GetMethodIndex(GetMethodInfoIndex());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100191 }
192
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 Srbecky6e69e522018-06-03 12:00:14 +0100205 const StackMap& stack_map,
David Srbeckyfd89b072018-06-03 12:00:22 +0100206 const MethodInfo& method_info) const;
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800207};
208
David Srbeckycf7833e2018-06-14 16:45:22 +0100209class InvokeInfo : public BitTableAccessor<3> {
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800210 public:
David Srbeckyd97e0822018-06-03 12:00:24 +0100211 BIT_TABLE_HEADER()
212 BIT_TABLE_COLUMN(0, PackedNativePc)
213 BIT_TABLE_COLUMN(1, InvokeType)
214 BIT_TABLE_COLUMN(2, MethodInfoIndex)
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800215
David Srbecky052f8ca2018-04-26 15:42:54 +0100216 ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const {
David Srbeckycf7833e2018-06-14 16:45:22 +0100217 return StackMap::UnpackNativePc(GetPackedNativePc(), instruction_set);
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800218 }
219
David Srbecky052f8ca2018-04-26 15:42:54 +0100220 uint32_t GetMethodIndex(MethodInfo method_info) const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100221 return method_info.GetMethodIndex(GetMethodInfoIndex());
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800222 }
David Srbecky09ed0982016-02-12 21:58:43 +0000223};
224
David Srbeckycf7833e2018-06-14 16:45:22 +0100225class MaskInfo : public BitTableAccessor<1> {
David Srbecky86decb62018-06-05 06:41:10 +0100226 public:
227 BIT_TABLE_HEADER()
228 BIT_TABLE_COLUMN(0, Mask)
229};
230
David Srbeckycf7833e2018-06-14 16:45:22 +0100231class DexRegisterMapInfo : public BitTableAccessor<1> {
David Srbecky86decb62018-06-05 06:41:10 +0100232 public:
233 BIT_TABLE_HEADER()
234 BIT_TABLE_COLUMN(0, CatalogueIndex)
235};
236
David Srbeckycf7833e2018-06-14 16:45:22 +0100237class DexRegisterInfo : public BitTableAccessor<2> {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100238 public:
David Srbeckyd97e0822018-06-03 12:00:24 +0100239 BIT_TABLE_HEADER()
240 BIT_TABLE_COLUMN(0, Kind)
241 BIT_TABLE_COLUMN(1, PackedValue)
David Srbecky71ec1cc2018-05-18 15:57:25 +0100242
243 ALWAYS_INLINE DexRegisterLocation GetLocation() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100244 DexRegisterLocation::Kind kind = static_cast<DexRegisterLocation::Kind>(GetKind());
245 return DexRegisterLocation(kind, UnpackValue(kind, GetPackedValue()));
David Srbecky71ec1cc2018-05-18 15:57:25 +0100246 }
247
248 static uint32_t PackValue(DexRegisterLocation::Kind kind, uint32_t value) {
249 uint32_t packed_value = value;
250 if (kind == DexRegisterLocation::Kind::kInStack) {
251 DCHECK(IsAligned<kFrameSlotSize>(packed_value));
252 packed_value /= kFrameSlotSize;
253 }
254 return packed_value;
255 }
256
257 static uint32_t UnpackValue(DexRegisterLocation::Kind kind, uint32_t packed_value) {
258 uint32_t value = packed_value;
259 if (kind == DexRegisterLocation::Kind::kInStack) {
260 value *= kFrameSlotSize;
261 }
262 return value;
263 }
264};
265
David Srbecky4b59d102018-05-29 21:46:10 +0000266// Register masks tend to have many trailing zero bits (caller-saves are usually not encoded),
267// therefore it is worth encoding the mask as value+shift.
David Srbeckycf7833e2018-06-14 16:45:22 +0100268class RegisterMask : public BitTableAccessor<2> {
David Srbecky4b59d102018-05-29 21:46:10 +0000269 public:
David Srbeckyd97e0822018-06-03 12:00:24 +0100270 BIT_TABLE_HEADER()
271 BIT_TABLE_COLUMN(0, Value)
272 BIT_TABLE_COLUMN(1, Shift)
David Srbecky4b59d102018-05-29 21:46:10 +0000273
274 ALWAYS_INLINE uint32_t GetMask() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100275 return GetValue() << GetShift();
David Srbecky4b59d102018-05-29 21:46:10 +0000276 }
277};
278
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100279/**
280 * Wrapper around all compiler information collected for a method.
David Srbecky71ec1cc2018-05-18 15:57:25 +0100281 * See the Decode method at the end for the precise binary format.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100282 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100283class CodeInfo {
284 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100285 explicit CodeInfo(const void* data) {
David Srbecky052f8ca2018-04-26 15:42:54 +0100286 Decode(reinterpret_cast<const uint8_t*>(data));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100287 }
288
David Srbecky052f8ca2018-04-26 15:42:54 +0100289 explicit CodeInfo(MemoryRegion region) : CodeInfo(region.begin()) {
290 DCHECK_EQ(size_, region.size());
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100291 }
292
David Srbecky052f8ca2018-04-26 15:42:54 +0100293 explicit CodeInfo(const OatQuickMethodHeader* header)
294 : CodeInfo(header->GetOptimizedCodeInfoPtr()) {
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100295 }
296
David Srbecky052f8ca2018-04-26 15:42:54 +0100297 size_t Size() const {
298 return size_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000299 }
300
David Srbecky052f8ca2018-04-26 15:42:54 +0100301 bool HasInlineInfo() const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100302 return inline_infos_.NumRows() > 0;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100303 }
304
David Srbecky052f8ca2018-04-26 15:42:54 +0100305 ALWAYS_INLINE StackMap GetStackMapAt(size_t index) const {
David Srbeckycf7833e2018-06-14 16:45:22 +0100306 return stack_maps_.GetRow(index);
David Srbecky45aa5982016-03-18 02:15:09 +0000307 }
308
David Srbecky052f8ca2018-04-26 15:42:54 +0100309 BitMemoryRegion GetStackMask(size_t index) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000310 return stack_masks_.GetBitMemoryRegion(index);
Mathieu Chartier1a20b682017-01-31 14:25:16 -0800311 }
312
David Srbecky052f8ca2018-04-26 15:42:54 +0100313 BitMemoryRegion GetStackMaskOf(const StackMap& stack_map) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000314 uint32_t index = stack_map.GetStackMaskIndex();
315 return (index == StackMap::kNoValue) ? BitMemoryRegion() : GetStackMask(index);
Mathieu Chartier1a20b682017-01-31 14:25:16 -0800316 }
317
David Srbecky052f8ca2018-04-26 15:42:54 +0100318 uint32_t GetRegisterMaskOf(const StackMap& stack_map) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000319 uint32_t index = stack_map.GetRegisterMaskIndex();
David Srbeckycf7833e2018-06-14 16:45:22 +0100320 return (index == StackMap::kNoValue) ? 0 : register_masks_.GetRow(index).GetMask();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100321 }
322
David Srbecky052f8ca2018-04-26 15:42:54 +0100323 uint32_t GetNumberOfLocationCatalogEntries() const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100324 return dex_register_catalog_.NumRows();
Roland Levillaina552e1c2015-03-26 15:01:03 +0000325 }
326
David Srbecky71ec1cc2018-05-18 15:57:25 +0100327 ALWAYS_INLINE DexRegisterLocation GetDexRegisterCatalogEntry(size_t index) const {
David Srbecky6de88332018-06-03 12:00:11 +0100328 return (index == StackMap::kNoValue)
329 ? DexRegisterLocation::None()
David Srbeckycf7833e2018-06-14 16:45:22 +0100330 : dex_register_catalog_.GetRow(index).GetLocation();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100331 }
332
David Srbecky052f8ca2018-04-26 15:42:54 +0100333 uint32_t GetNumberOfStackMaps() const {
334 return stack_maps_.NumRows();
Nicolas Geoffray6530baf2015-05-26 15:22:58 +0100335 }
336
David Srbecky052f8ca2018-04-26 15:42:54 +0100337 InvokeInfo GetInvokeInfo(size_t index) const {
David Srbeckycf7833e2018-06-14 16:45:22 +0100338 return invoke_infos_.GetRow(index);
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800339 }
340
David Srbeckyfd89b072018-06-03 12:00:22 +0100341 ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map) const {
David Srbecky6de88332018-06-03 12:00:11 +0100342 if (stack_map.HasDexRegisterMap()) {
343 DexRegisterMap map(number_of_dex_registers_, DexRegisterLocation::Invalid());
344 DecodeDexRegisterMap(stack_map.Row(), /* first_dex_register */ 0, &map);
345 return map;
346 }
347 return DexRegisterMap(0, DexRegisterLocation::None());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100348 }
349
David Srbeckyfd89b072018-06-03 12:00:22 +0100350 ALWAYS_INLINE DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth, StackMap stack_map) const {
David Srbecky6de88332018-06-03 12:00:11 +0100351 if (stack_map.HasDexRegisterMap()) {
352 // The register counts are commutative and include all outer levels.
353 // This allows us to determine the range [first, last) in just two lookups.
354 // If we are at depth 0 (the first inlinee), the count from the main method is used.
355 uint32_t first = (depth == 0) ? number_of_dex_registers_
356 : GetInlineInfoAtDepth(stack_map, depth - 1).GetNumberOfDexRegisters();
357 uint32_t last = GetInlineInfoAtDepth(stack_map, depth).GetNumberOfDexRegisters();
358 DexRegisterMap map(last - first, DexRegisterLocation::Invalid());
359 DecodeDexRegisterMap(stack_map.Row(), first, &map);
360 return map;
361 }
362 return DexRegisterMap(0, DexRegisterLocation::None());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100363 }
364
David Srbecky052f8ca2018-04-26 15:42:54 +0100365 InlineInfo GetInlineInfo(size_t index) const {
David Srbeckycf7833e2018-06-14 16:45:22 +0100366 return inline_infos_.GetRow(index);
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800367 }
368
David Srbecky6e69e522018-06-03 12:00:14 +0100369 uint32_t GetInlineDepthOf(StackMap stack_map) const {
370 uint32_t depth = 0;
David Srbecky052f8ca2018-04-26 15:42:54 +0100371 uint32_t index = stack_map.GetInlineInfoIndex();
David Srbecky6e69e522018-06-03 12:00:14 +0100372 if (index != StackMap::kNoValue) {
373 while (GetInlineInfo(index + depth++).GetIsLast() == InlineInfo::kMore) { }
374 }
375 return depth;
376 }
377
378 InlineInfo GetInlineInfoAtDepth(StackMap stack_map, uint32_t depth) const {
379 DCHECK(stack_map.HasInlineInfo());
380 DCHECK_LT(depth, GetInlineDepthOf(stack_map));
381 return GetInlineInfo(stack_map.GetInlineInfoIndex() + depth);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100382 }
383
David Srbecky052f8ca2018-04-26 15:42:54 +0100384 StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
385 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
386 StackMap stack_map = GetStackMapAt(i);
David Srbecky50fac062018-06-13 18:55:35 +0100387 if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() != StackMap::Kind::Debug) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100388 return stack_map;
389 }
390 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100391 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100392 }
393
David Srbecky50fac062018-06-13 18:55:35 +0100394 // Searches the stack map list backwards because catch stack maps are stored at the end.
David Srbecky052f8ca2018-04-26 15:42:54 +0100395 StackMap GetCatchStackMapForDexPc(uint32_t dex_pc) const {
396 for (size_t i = GetNumberOfStackMaps(); i > 0; --i) {
397 StackMap stack_map = GetStackMapAt(i - 1);
David Srbecky50fac062018-06-13 18:55:35 +0100398 if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() == StackMap::Kind::Catch) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000399 return stack_map;
400 }
401 }
402 return StackMap();
403 }
404
David Srbecky052f8ca2018-04-26 15:42:54 +0100405 StackMap GetOsrStackMapForDexPc(uint32_t dex_pc) const {
David Srbecky50fac062018-06-13 18:55:35 +0100406 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
David Srbecky052f8ca2018-04-26 15:42:54 +0100407 StackMap stack_map = GetStackMapAt(i);
David Srbecky50fac062018-06-13 18:55:35 +0100408 if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() == StackMap::Kind::OSR) {
409 return stack_map;
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000410 }
411 }
412 return StackMap();
413 }
414
David Srbecky50fac062018-06-13 18:55:35 +0100415 StackMap GetStackMapForNativePcOffset(uint32_t pc, InstructionSet isa = kRuntimeISA) const {
David Brazdil77a48ae2015-09-15 12:34:04 +0000416 // TODO: Safepoint stack maps are sorted by native_pc_offset but catch stack
417 // maps are not. If we knew that the method does not have try/catch,
418 // we could do binary search.
David Srbecky052f8ca2018-04-26 15:42:54 +0100419 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
420 StackMap stack_map = GetStackMapAt(i);
David Srbecky50fac062018-06-13 18:55:35 +0100421 if (stack_map.GetNativePcOffset(isa) == pc) {
422 StackMap::Kind kind = static_cast<StackMap::Kind>(stack_map.GetKind());
423 if (kind == StackMap::Kind::Default || kind == StackMap::Kind::OSR) {
424 return stack_map;
425 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100426 }
427 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100428 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100429 }
430
David Srbecky052f8ca2018-04-26 15:42:54 +0100431 InvokeInfo GetInvokeInfoForNativePcOffset(uint32_t native_pc_offset) {
432 for (size_t index = 0; index < invoke_infos_.NumRows(); index++) {
433 InvokeInfo item = GetInvokeInfo(index);
434 if (item.GetNativePcOffset(kRuntimeISA) == native_pc_offset) {
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800435 return item;
436 }
437 }
David Srbeckyd97e0822018-06-03 12:00:24 +0100438 return InvokeInfo();
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800439 }
440
David Srbecky71ec1cc2018-05-18 15:57:25 +0100441 // Dump this CodeInfo object on `vios`.
442 // `code_offset` is the (absolute) native PC of the compiled method.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100443 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100444 uint32_t code_offset,
David Srbecky71ec1cc2018-05-18 15:57:25 +0100445 bool verbose,
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700446 InstructionSet instruction_set,
447 const MethodInfo& method_info) const;
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000448
David Srbecky86decb62018-06-05 06:41:10 +0100449 // Accumulate code info size statistics into the given Stats tree.
450 void AddSizeStats(/*out*/ Stats* parent) const;
451
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100452 private:
David Srbecky6de88332018-06-03 12:00:11 +0100453 // Scan backward to determine dex register locations at given stack map.
454 void DecodeDexRegisterMap(uint32_t stack_map_index,
455 uint32_t first_dex_register,
456 /*out*/ DexRegisterMap* map) const;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000457
David Srbecky052f8ca2018-04-26 15:42:54 +0100458 void Decode(const uint8_t* data) {
459 size_t non_header_size = DecodeUnsignedLeb128(&data);
David Srbecky71ec1cc2018-05-18 15:57:25 +0100460 BitMemoryRegion region(MemoryRegion(const_cast<uint8_t*>(data), non_header_size));
David Srbecky052f8ca2018-04-26 15:42:54 +0100461 size_t bit_offset = 0;
462 size_ = UnsignedLeb128Size(non_header_size) + non_header_size;
David Srbecky71ec1cc2018-05-18 15:57:25 +0100463 stack_maps_.Decode(region, &bit_offset);
464 register_masks_.Decode(region, &bit_offset);
465 stack_masks_.Decode(region, &bit_offset);
466 invoke_infos_.Decode(region, &bit_offset);
467 inline_infos_.Decode(region, &bit_offset);
468 dex_register_masks_.Decode(region, &bit_offset);
469 dex_register_maps_.Decode(region, &bit_offset);
470 dex_register_catalog_.Decode(region, &bit_offset);
David Srbecky6de88332018-06-03 12:00:11 +0100471 number_of_dex_registers_ = DecodeVarintBits(region, &bit_offset);
David Srbecky71ec1cc2018-05-18 15:57:25 +0100472 CHECK_EQ(non_header_size, BitsToBytesRoundUp(bit_offset)) << "Invalid CodeInfo";
David Srbecky052f8ca2018-04-26 15:42:54 +0100473 }
474
475 size_t size_;
David Srbeckycf7833e2018-06-14 16:45:22 +0100476 BitTable<StackMap> stack_maps_;
477 BitTable<RegisterMask> register_masks_;
478 BitTable<MaskInfo> stack_masks_;
479 BitTable<InvokeInfo> invoke_infos_;
480 BitTable<InlineInfo> inline_infos_;
481 BitTable<MaskInfo> dex_register_masks_;
482 BitTable<DexRegisterMapInfo> dex_register_maps_;
483 BitTable<DexRegisterInfo> dex_register_catalog_;
David Srbecky6de88332018-06-03 12:00:11 +0100484 uint32_t number_of_dex_registers_; // Excludes any inlined methods.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100485};
486
Roland Levillain1c1da432015-07-16 11:54:44 +0100487#undef ELEMENT_BYTE_OFFSET_AFTER
488#undef ELEMENT_BIT_OFFSET_AFTER
489
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100490} // namespace art
491
492#endif // ART_RUNTIME_STACK_MAP_H_