blob: ea358c630dafc41b2d1d350184b5478c182859a6 [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.
Roland Levillaina552e1c2015-03-26 15:01:03 +000057class DexRegisterMap {
58 public:
David Srbecky6de88332018-06-03 12:00:11 +010059 using iterator = DexRegisterLocation*;
60
61 // Create map for given number of registers and initialize them to the given value.
62 DexRegisterMap(size_t count, DexRegisterLocation value) : count_(count), regs_small_{} {
David Srbecky71ec1cc2018-05-18 15:57:25 +010063 if (count_ <= kSmallCount) {
David Srbecky6de88332018-06-03 12:00:11 +010064 std::fill_n(regs_small_.begin(), count, value);
David Srbecky71ec1cc2018-05-18 15:57:25 +010065 } else {
David Srbecky6de88332018-06-03 12:00:11 +010066 regs_large_.resize(count, value);
David Srbecky71ec1cc2018-05-18 15:57:25 +010067 }
Roland Levillaina552e1c2015-03-26 15:01:03 +000068 }
69
David Srbecky71ec1cc2018-05-18 15:57:25 +010070 DexRegisterLocation* data() {
71 return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
72 }
Roland Levillaina552e1c2015-03-26 15:01:03 +000073
David Srbecky6de88332018-06-03 12:00:11 +010074 iterator begin() { return data(); }
75 iterator end() { return data() + count_; }
76
David Srbecky71ec1cc2018-05-18 15:57:25 +010077 size_t size() const { return count_; }
78
David Srbeckyfd89b072018-06-03 12:00:22 +010079 bool empty() const { return count_ == 0; }
David Srbecky71ec1cc2018-05-18 15:57:25 +010080
81 DexRegisterLocation Get(size_t index) const {
82 DCHECK_LT(index, count_);
83 return count_ <= kSmallCount ? regs_small_[index] : regs_large_[index];
84 }
85
86 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number) const {
87 return Get(dex_register_number).GetKind();
88 }
89
90 // TODO: Remove.
91 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number) const {
92 return Get(dex_register_number).GetKind();
93 }
94
95 DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number) const {
96 return Get(dex_register_number);
97 }
Roland Levillaina552e1c2015-03-26 15:01:03 +000098
David Srbecky21d45b42018-05-30 06:35:05 +010099 int32_t GetStackOffsetInBytes(uint16_t dex_register_number) const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100100 DexRegisterLocation location = Get(dex_register_number);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000101 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000102 return location.GetValue();
103 }
104
David Srbecky21d45b42018-05-30 06:35:05 +0100105 int32_t GetConstant(uint16_t dex_register_number) const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100106 DexRegisterLocation location = Get(dex_register_number);
107 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000108 return location.GetValue();
109 }
110
David Srbecky21d45b42018-05-30 06:35:05 +0100111 int32_t GetMachineRegister(uint16_t dex_register_number) const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100112 DexRegisterLocation location = Get(dex_register_number);
113 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInRegister ||
114 location.GetKind() == DexRegisterLocation::Kind::kInRegisterHigh ||
115 location.GetKind() == DexRegisterLocation::Kind::kInFpuRegister ||
116 location.GetKind() == DexRegisterLocation::Kind::kInFpuRegisterHigh);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000117 return location.GetValue();
118 }
119
Mingyao Yang01b47b02017-02-03 12:09:57 -0800120 ALWAYS_INLINE bool IsDexRegisterLive(uint16_t dex_register_number) const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100121 return Get(dex_register_number).IsLive();
Roland Levillaina552e1c2015-03-26 15:01:03 +0000122 }
123
David Srbecky71ec1cc2018-05-18 15:57:25 +0100124 size_t GetNumberOfLiveDexRegisters() const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000125 size_t number_of_live_dex_registers = 0;
David Srbecky71ec1cc2018-05-18 15:57:25 +0100126 for (size_t i = 0; i < count_; ++i) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000127 if (IsDexRegisterLive(i)) {
128 ++number_of_live_dex_registers;
129 }
130 }
131 return number_of_live_dex_registers;
132 }
133
David Srbecky71ec1cc2018-05-18 15:57:25 +0100134 bool HasAnyLiveDexRegisters() const {
135 for (size_t i = 0; i < count_; ++i) {
136 if (IsDexRegisterLive(i)) {
137 return true;
138 }
139 }
140 return false;
David Srbecky21d45b42018-05-30 06:35:05 +0100141 }
142
Roland Levillaina552e1c2015-03-26 15:01:03 +0000143 private:
David Srbecky71ec1cc2018-05-18 15:57:25 +0100144 // Store the data inline if the number of registers is small to avoid memory allocations.
145 // If count_ <= kSmallCount, we use the regs_small_ array, and regs_large_ otherwise.
146 static constexpr size_t kSmallCount = 16;
147 size_t count_;
148 std::array<DexRegisterLocation, kSmallCount> regs_small_;
149 dchecked_vector<DexRegisterLocation> regs_large_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000150};
151
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100152/**
153 * A Stack Map holds compilation information for a specific PC necessary for:
154 * - Mapping it to a dex PC,
155 * - Knowing which stack entries are objects,
156 * - Knowing which registers hold objects,
157 * - Knowing the inlining information,
158 * - Knowing the values of dex registers.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100159 */
David Srbecky71ec1cc2018-05-18 15:57:25 +0100160class StackMap : public BitTable<7>::Accessor {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100161 public:
David Srbeckyd97e0822018-06-03 12:00:24 +0100162 BIT_TABLE_HEADER()
163 BIT_TABLE_COLUMN(0, PackedNativePc)
164 BIT_TABLE_COLUMN(1, DexPc)
165 BIT_TABLE_COLUMN(2, RegisterMaskIndex)
166 BIT_TABLE_COLUMN(3, StackMaskIndex)
167 BIT_TABLE_COLUMN(4, InlineInfoIndex)
168 BIT_TABLE_COLUMN(5, DexRegisterMaskIndex)
169 BIT_TABLE_COLUMN(6, DexRegisterMapIndex)
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100170
David Srbecky052f8ca2018-04-26 15:42:54 +0100171 ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const {
David Srbeckyd02b23f2018-05-29 23:27:22 +0100172 return UnpackNativePc(Get<kPackedNativePc>(), instruction_set);
David Brazdilf677ebf2015-05-29 16:29:43 +0100173 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100174
David Srbeckyd97e0822018-06-03 12:00:24 +0100175 ALWAYS_INLINE bool HasInlineInfo() const {
176 return HasInlineInfoIndex();
177 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100178
David Srbeckyd97e0822018-06-03 12:00:24 +0100179 ALWAYS_INLINE bool HasDexRegisterMap() const {
180 return HasDexRegisterMapIndex();
181 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100182
David Srbeckyd02b23f2018-05-29 23:27:22 +0100183 static uint32_t PackNativePc(uint32_t native_pc, InstructionSet isa) {
David Srbeckyd775f962018-05-30 18:12:52 +0100184 DCHECK_ALIGNED_PARAM(native_pc, GetInstructionSetInstructionAlignment(isa));
David Srbeckyd02b23f2018-05-29 23:27:22 +0100185 return native_pc / GetInstructionSetInstructionAlignment(isa);
186 }
187
188 static uint32_t UnpackNativePc(uint32_t packed_native_pc, InstructionSet isa) {
189 uint32_t native_pc = packed_native_pc * GetInstructionSetInstructionAlignment(isa);
190 DCHECK_EQ(native_pc / GetInstructionSetInstructionAlignment(isa), packed_native_pc);
191 return native_pc;
192 }
193
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100194 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100195 const CodeInfo& code_info,
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700196 const MethodInfo& method_info,
Roland Levillainf2650d12015-05-28 14:53:28 +0100197 uint32_t code_offset,
David Srbecky71ec1cc2018-05-18 15:57:25 +0100198 InstructionSet instruction_set) const;
David Srbecky61b28a12016-02-25 21:55:03 +0000199};
200
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100201/**
David Srbecky052f8ca2018-04-26 15:42:54 +0100202 * Inline information for a specific PC.
203 * The row referenced from the StackMap holds information at depth 0.
204 * Following rows hold information for further depths.
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100205 */
David Srbecky6de88332018-06-03 12:00:11 +0100206class InlineInfo : public BitTable<6>::Accessor {
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100207 public:
David Srbeckyd97e0822018-06-03 12:00:24 +0100208 BIT_TABLE_HEADER()
209 BIT_TABLE_COLUMN(0, IsLast) // Determines if there are further rows for further depths.
210 BIT_TABLE_COLUMN(1, DexPc)
211 BIT_TABLE_COLUMN(2, MethodInfoIndex)
212 BIT_TABLE_COLUMN(3, ArtMethodHi) // High bits of ArtMethod*.
213 BIT_TABLE_COLUMN(4, ArtMethodLo) // Low bits of ArtMethod*.
David Srbecky6de88332018-06-03 12:00:11 +0100214 BIT_TABLE_COLUMN(5, NumberOfDexRegisters) // Includes outer levels and the main method.
David Srbeckyd97e0822018-06-03 12:00:24 +0100215 BIT_TABLE_COLUMN(6, DexRegisterMapIndex)
216
David Srbecky052f8ca2018-04-26 15:42:54 +0100217 static constexpr uint32_t kLast = -1;
218 static constexpr uint32_t kMore = 0;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100219
David Srbecky6e69e522018-06-03 12:00:14 +0100220 uint32_t GetMethodIndex(const MethodInfo& method_info) const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100221 return method_info.GetMethodIndex(GetMethodInfoIndex());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100222 }
223
David Srbecky6e69e522018-06-03 12:00:14 +0100224 bool EncodesArtMethod() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100225 return HasArtMethodLo();
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100226 }
227
David Srbecky6e69e522018-06-03 12:00:14 +0100228 ArtMethod* GetArtMethod() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100229 uint64_t lo = GetArtMethodLo();
230 uint64_t hi = GetArtMethodHi();
David Srbecky71ec1cc2018-05-18 15:57:25 +0100231 return reinterpret_cast<ArtMethod*>((hi << 32) | lo);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100232 }
233
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100234 void Dump(VariableIndentationOutputStream* vios,
David Srbecky61b28a12016-02-25 21:55:03 +0000235 const CodeInfo& info,
David Srbecky6e69e522018-06-03 12:00:14 +0100236 const StackMap& stack_map,
David Srbeckyfd89b072018-06-03 12:00:22 +0100237 const MethodInfo& method_info) const;
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800238};
239
David Srbecky052f8ca2018-04-26 15:42:54 +0100240class InvokeInfo : public BitTable<3>::Accessor {
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800241 public:
David Srbeckyd97e0822018-06-03 12:00:24 +0100242 BIT_TABLE_HEADER()
243 BIT_TABLE_COLUMN(0, PackedNativePc)
244 BIT_TABLE_COLUMN(1, InvokeType)
245 BIT_TABLE_COLUMN(2, MethodInfoIndex)
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800246
David Srbecky052f8ca2018-04-26 15:42:54 +0100247 ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const {
David Srbeckyd02b23f2018-05-29 23:27:22 +0100248 return StackMap::UnpackNativePc(Get<kPackedNativePc>(), instruction_set);
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800249 }
250
David Srbecky052f8ca2018-04-26 15:42:54 +0100251 uint32_t GetMethodIndex(MethodInfo method_info) const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100252 return method_info.GetMethodIndex(GetMethodInfoIndex());
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800253 }
David Srbecky09ed0982016-02-12 21:58:43 +0000254};
255
David Srbecky86decb62018-06-05 06:41:10 +0100256class MaskInfo : public BitTable<1>::Accessor {
257 public:
258 BIT_TABLE_HEADER()
259 BIT_TABLE_COLUMN(0, Mask)
260};
261
262class DexRegisterMapInfo : public BitTable<1>::Accessor {
263 public:
264 BIT_TABLE_HEADER()
265 BIT_TABLE_COLUMN(0, CatalogueIndex)
266};
267
David Srbecky71ec1cc2018-05-18 15:57:25 +0100268class DexRegisterInfo : public BitTable<2>::Accessor {
269 public:
David Srbeckyd97e0822018-06-03 12:00:24 +0100270 BIT_TABLE_HEADER()
271 BIT_TABLE_COLUMN(0, Kind)
272 BIT_TABLE_COLUMN(1, PackedValue)
David Srbecky71ec1cc2018-05-18 15:57:25 +0100273
274 ALWAYS_INLINE DexRegisterLocation GetLocation() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100275 DexRegisterLocation::Kind kind = static_cast<DexRegisterLocation::Kind>(GetKind());
276 return DexRegisterLocation(kind, UnpackValue(kind, GetPackedValue()));
David Srbecky71ec1cc2018-05-18 15:57:25 +0100277 }
278
279 static uint32_t PackValue(DexRegisterLocation::Kind kind, uint32_t value) {
280 uint32_t packed_value = value;
281 if (kind == DexRegisterLocation::Kind::kInStack) {
282 DCHECK(IsAligned<kFrameSlotSize>(packed_value));
283 packed_value /= kFrameSlotSize;
284 }
285 return packed_value;
286 }
287
288 static uint32_t UnpackValue(DexRegisterLocation::Kind kind, uint32_t packed_value) {
289 uint32_t value = packed_value;
290 if (kind == DexRegisterLocation::Kind::kInStack) {
291 value *= kFrameSlotSize;
292 }
293 return value;
294 }
295};
296
David Srbecky4b59d102018-05-29 21:46:10 +0000297// Register masks tend to have many trailing zero bits (caller-saves are usually not encoded),
298// therefore it is worth encoding the mask as value+shift.
299class RegisterMask : public BitTable<2>::Accessor {
300 public:
David Srbeckyd97e0822018-06-03 12:00:24 +0100301 BIT_TABLE_HEADER()
302 BIT_TABLE_COLUMN(0, Value)
303 BIT_TABLE_COLUMN(1, Shift)
David Srbecky4b59d102018-05-29 21:46:10 +0000304
305 ALWAYS_INLINE uint32_t GetMask() const {
David Srbeckyd97e0822018-06-03 12:00:24 +0100306 return GetValue() << GetShift();
David Srbecky4b59d102018-05-29 21:46:10 +0000307 }
308};
309
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100310/**
311 * Wrapper around all compiler information collected for a method.
David Srbecky71ec1cc2018-05-18 15:57:25 +0100312 * See the Decode method at the end for the precise binary format.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100313 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100314class CodeInfo {
315 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100316 explicit CodeInfo(const void* data) {
David Srbecky052f8ca2018-04-26 15:42:54 +0100317 Decode(reinterpret_cast<const uint8_t*>(data));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100318 }
319
David Srbecky052f8ca2018-04-26 15:42:54 +0100320 explicit CodeInfo(MemoryRegion region) : CodeInfo(region.begin()) {
321 DCHECK_EQ(size_, region.size());
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100322 }
323
David Srbecky052f8ca2018-04-26 15:42:54 +0100324 explicit CodeInfo(const OatQuickMethodHeader* header)
325 : CodeInfo(header->GetOptimizedCodeInfoPtr()) {
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100326 }
327
David Srbecky052f8ca2018-04-26 15:42:54 +0100328 size_t Size() const {
329 return size_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000330 }
331
David Srbecky052f8ca2018-04-26 15:42:54 +0100332 bool HasInlineInfo() const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100333 return inline_infos_.NumRows() > 0;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100334 }
335
David Srbecky052f8ca2018-04-26 15:42:54 +0100336 ALWAYS_INLINE StackMap GetStackMapAt(size_t index) const {
337 return StackMap(&stack_maps_, index);
David Srbecky45aa5982016-03-18 02:15:09 +0000338 }
339
David Srbecky052f8ca2018-04-26 15:42:54 +0100340 BitMemoryRegion GetStackMask(size_t index) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000341 return stack_masks_.GetBitMemoryRegion(index);
Mathieu Chartier1a20b682017-01-31 14:25:16 -0800342 }
343
David Srbecky052f8ca2018-04-26 15:42:54 +0100344 BitMemoryRegion GetStackMaskOf(const StackMap& stack_map) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000345 uint32_t index = stack_map.GetStackMaskIndex();
346 return (index == StackMap::kNoValue) ? BitMemoryRegion() : GetStackMask(index);
Mathieu Chartier1a20b682017-01-31 14:25:16 -0800347 }
348
David Srbecky052f8ca2018-04-26 15:42:54 +0100349 uint32_t GetRegisterMaskOf(const StackMap& stack_map) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000350 uint32_t index = stack_map.GetRegisterMaskIndex();
351 return (index == StackMap::kNoValue) ? 0 : RegisterMask(&register_masks_, index).GetMask();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100352 }
353
David Srbecky052f8ca2018-04-26 15:42:54 +0100354 uint32_t GetNumberOfLocationCatalogEntries() const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100355 return dex_register_catalog_.NumRows();
Roland Levillaina552e1c2015-03-26 15:01:03 +0000356 }
357
David Srbecky71ec1cc2018-05-18 15:57:25 +0100358 ALWAYS_INLINE DexRegisterLocation GetDexRegisterCatalogEntry(size_t index) const {
David Srbecky6de88332018-06-03 12:00:11 +0100359 return (index == StackMap::kNoValue)
360 ? DexRegisterLocation::None()
361 : DexRegisterInfo(&dex_register_catalog_, index).GetLocation();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100362 }
363
David Srbecky052f8ca2018-04-26 15:42:54 +0100364 uint32_t GetNumberOfStackMaps() const {
365 return stack_maps_.NumRows();
Nicolas Geoffray6530baf2015-05-26 15:22:58 +0100366 }
367
David Srbecky052f8ca2018-04-26 15:42:54 +0100368 InvokeInfo GetInvokeInfo(size_t index) const {
369 return InvokeInfo(&invoke_infos_, index);
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800370 }
371
David Srbeckyfd89b072018-06-03 12:00:22 +0100372 ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map) const {
David Srbecky6de88332018-06-03 12:00:11 +0100373 if (stack_map.HasDexRegisterMap()) {
374 DexRegisterMap map(number_of_dex_registers_, DexRegisterLocation::Invalid());
375 DecodeDexRegisterMap(stack_map.Row(), /* first_dex_register */ 0, &map);
376 return map;
377 }
378 return DexRegisterMap(0, DexRegisterLocation::None());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100379 }
380
David Srbeckyfd89b072018-06-03 12:00:22 +0100381 ALWAYS_INLINE DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth, StackMap stack_map) const {
David Srbecky6de88332018-06-03 12:00:11 +0100382 if (stack_map.HasDexRegisterMap()) {
383 // The register counts are commutative and include all outer levels.
384 // This allows us to determine the range [first, last) in just two lookups.
385 // If we are at depth 0 (the first inlinee), the count from the main method is used.
386 uint32_t first = (depth == 0) ? number_of_dex_registers_
387 : GetInlineInfoAtDepth(stack_map, depth - 1).GetNumberOfDexRegisters();
388 uint32_t last = GetInlineInfoAtDepth(stack_map, depth).GetNumberOfDexRegisters();
389 DexRegisterMap map(last - first, DexRegisterLocation::Invalid());
390 DecodeDexRegisterMap(stack_map.Row(), first, &map);
391 return map;
392 }
393 return DexRegisterMap(0, DexRegisterLocation::None());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100394 }
395
David Srbecky052f8ca2018-04-26 15:42:54 +0100396 InlineInfo GetInlineInfo(size_t index) const {
397 return InlineInfo(&inline_infos_, index);
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800398 }
399
David Srbecky6e69e522018-06-03 12:00:14 +0100400 uint32_t GetInlineDepthOf(StackMap stack_map) const {
401 uint32_t depth = 0;
David Srbecky052f8ca2018-04-26 15:42:54 +0100402 uint32_t index = stack_map.GetInlineInfoIndex();
David Srbecky6e69e522018-06-03 12:00:14 +0100403 if (index != StackMap::kNoValue) {
404 while (GetInlineInfo(index + depth++).GetIsLast() == InlineInfo::kMore) { }
405 }
406 return depth;
407 }
408
409 InlineInfo GetInlineInfoAtDepth(StackMap stack_map, uint32_t depth) const {
410 DCHECK(stack_map.HasInlineInfo());
411 DCHECK_LT(depth, GetInlineDepthOf(stack_map));
412 return GetInlineInfo(stack_map.GetInlineInfoIndex() + depth);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100413 }
414
David Srbecky052f8ca2018-04-26 15:42:54 +0100415 StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
416 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
417 StackMap stack_map = GetStackMapAt(i);
418 if (stack_map.GetDexPc() == dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100419 return stack_map;
420 }
421 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100422 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100423 }
424
David Brazdil77a48ae2015-09-15 12:34:04 +0000425 // Searches the stack map list backwards because catch stack maps are stored
426 // at the end.
David Srbecky052f8ca2018-04-26 15:42:54 +0100427 StackMap GetCatchStackMapForDexPc(uint32_t dex_pc) const {
428 for (size_t i = GetNumberOfStackMaps(); i > 0; --i) {
429 StackMap stack_map = GetStackMapAt(i - 1);
430 if (stack_map.GetDexPc() == dex_pc) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000431 return stack_map;
432 }
433 }
434 return StackMap();
435 }
436
David Srbecky052f8ca2018-04-26 15:42:54 +0100437 StackMap GetOsrStackMapForDexPc(uint32_t dex_pc) const {
438 size_t e = GetNumberOfStackMaps();
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000439 if (e == 0) {
440 // There cannot be OSR stack map if there is no stack map.
441 return StackMap();
442 }
443 // Walk over all stack maps. If two consecutive stack maps are identical, then we
444 // have found a stack map suitable for OSR.
445 for (size_t i = 0; i < e - 1; ++i) {
David Srbecky052f8ca2018-04-26 15:42:54 +0100446 StackMap stack_map = GetStackMapAt(i);
447 if (stack_map.GetDexPc() == dex_pc) {
448 StackMap other = GetStackMapAt(i + 1);
449 if (other.GetDexPc() == dex_pc &&
450 other.GetNativePcOffset(kRuntimeISA) ==
451 stack_map.GetNativePcOffset(kRuntimeISA)) {
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000452 if (i < e - 2) {
453 // Make sure there are not three identical stack maps following each other.
Mathieu Chartiera2f526f2017-01-19 14:48:48 -0800454 DCHECK_NE(
David Srbecky052f8ca2018-04-26 15:42:54 +0100455 stack_map.GetNativePcOffset(kRuntimeISA),
456 GetStackMapAt(i + 2).GetNativePcOffset(kRuntimeISA));
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000457 }
458 return stack_map;
459 }
460 }
461 }
462 return StackMap();
463 }
464
David Srbecky052f8ca2018-04-26 15:42:54 +0100465 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const {
David Brazdil77a48ae2015-09-15 12:34:04 +0000466 // TODO: Safepoint stack maps are sorted by native_pc_offset but catch stack
467 // maps are not. If we knew that the method does not have try/catch,
468 // we could do binary search.
David Srbecky052f8ca2018-04-26 15:42:54 +0100469 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
470 StackMap stack_map = GetStackMapAt(i);
471 if (stack_map.GetNativePcOffset(kRuntimeISA) == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100472 return stack_map;
473 }
474 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100475 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100476 }
477
David Srbecky052f8ca2018-04-26 15:42:54 +0100478 InvokeInfo GetInvokeInfoForNativePcOffset(uint32_t native_pc_offset) {
479 for (size_t index = 0; index < invoke_infos_.NumRows(); index++) {
480 InvokeInfo item = GetInvokeInfo(index);
481 if (item.GetNativePcOffset(kRuntimeISA) == native_pc_offset) {
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800482 return item;
483 }
484 }
David Srbeckyd97e0822018-06-03 12:00:24 +0100485 return InvokeInfo();
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800486 }
487
David Srbecky71ec1cc2018-05-18 15:57:25 +0100488 // Dump this CodeInfo object on `vios`.
489 // `code_offset` is the (absolute) native PC of the compiled method.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100490 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100491 uint32_t code_offset,
David Srbecky71ec1cc2018-05-18 15:57:25 +0100492 bool verbose,
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700493 InstructionSet instruction_set,
494 const MethodInfo& method_info) const;
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000495
David Srbecky86decb62018-06-05 06:41:10 +0100496 // Accumulate code info size statistics into the given Stats tree.
497 void AddSizeStats(/*out*/ Stats* parent) const;
498
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100499 private:
David Srbecky6de88332018-06-03 12:00:11 +0100500 // Scan backward to determine dex register locations at given stack map.
501 void DecodeDexRegisterMap(uint32_t stack_map_index,
502 uint32_t first_dex_register,
503 /*out*/ DexRegisterMap* map) const;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000504
David Srbecky052f8ca2018-04-26 15:42:54 +0100505 void Decode(const uint8_t* data) {
506 size_t non_header_size = DecodeUnsignedLeb128(&data);
David Srbecky71ec1cc2018-05-18 15:57:25 +0100507 BitMemoryRegion region(MemoryRegion(const_cast<uint8_t*>(data), non_header_size));
David Srbecky052f8ca2018-04-26 15:42:54 +0100508 size_t bit_offset = 0;
509 size_ = UnsignedLeb128Size(non_header_size) + non_header_size;
David Srbecky71ec1cc2018-05-18 15:57:25 +0100510 stack_maps_.Decode(region, &bit_offset);
511 register_masks_.Decode(region, &bit_offset);
512 stack_masks_.Decode(region, &bit_offset);
513 invoke_infos_.Decode(region, &bit_offset);
514 inline_infos_.Decode(region, &bit_offset);
515 dex_register_masks_.Decode(region, &bit_offset);
516 dex_register_maps_.Decode(region, &bit_offset);
517 dex_register_catalog_.Decode(region, &bit_offset);
David Srbecky6de88332018-06-03 12:00:11 +0100518 number_of_dex_registers_ = DecodeVarintBits(region, &bit_offset);
David Srbecky71ec1cc2018-05-18 15:57:25 +0100519 CHECK_EQ(non_header_size, BitsToBytesRoundUp(bit_offset)) << "Invalid CodeInfo";
David Srbecky052f8ca2018-04-26 15:42:54 +0100520 }
521
522 size_t size_;
David Srbeckyd97e0822018-06-03 12:00:24 +0100523 BitTable<StackMap::kCount> stack_maps_;
524 BitTable<RegisterMask::kCount> register_masks_;
David Srbecky86decb62018-06-05 06:41:10 +0100525 BitTable<MaskInfo::kCount> stack_masks_;
David Srbeckyd97e0822018-06-03 12:00:24 +0100526 BitTable<InvokeInfo::kCount> invoke_infos_;
527 BitTable<InlineInfo::kCount> inline_infos_;
David Srbecky86decb62018-06-05 06:41:10 +0100528 BitTable<MaskInfo::kCount> dex_register_masks_;
529 BitTable<DexRegisterMapInfo::kCount> dex_register_maps_;
David Srbeckyd97e0822018-06-03 12:00:24 +0100530 BitTable<DexRegisterInfo::kCount> dex_register_catalog_;
David Srbecky6de88332018-06-03 12:00:11 +0100531 uint32_t number_of_dex_registers_; // Excludes any inlined methods.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100532};
533
Roland Levillain1c1da432015-07-16 11:54:44 +0100534#undef ELEMENT_BYTE_OFFSET_AFTER
535#undef ELEMENT_BIT_OFFSET_AFTER
536
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100537} // namespace art
538
539#endif // ART_RUNTIME_STACK_MAP_H_