blob: 9aac204e70be36d937b21759916e17f76e897421 [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
Nicolas Geoffray5d37c152017-01-12 13:25:19 +000042class ArtMethod;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000043class CodeInfo;
44
David Srbecky71ec1cc2018-05-18 15:57:25 +010045std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010046
David Srbecky71ec1cc2018-05-18 15:57:25 +010047// Information on Dex register locations for a specific PC.
48// Effectively just a convenience wrapper for DexRegisterLocation vector.
49// If the size is small enough, it keeps the data on the stack.
Roland Levillaina552e1c2015-03-26 15:01:03 +000050class DexRegisterMap {
51 public:
David Srbecky71ec1cc2018-05-18 15:57:25 +010052 // Create map for given number of registers and initialize all locations to None.
53 explicit DexRegisterMap(size_t count) : count_(count), regs_small_{} {
54 if (count_ <= kSmallCount) {
55 std::fill_n(regs_small_.begin(), count, DexRegisterLocation::None());
56 } else {
57 regs_large_.resize(count, DexRegisterLocation::None());
58 }
Roland Levillaina552e1c2015-03-26 15:01:03 +000059 }
60
David Srbecky71ec1cc2018-05-18 15:57:25 +010061 DexRegisterLocation* data() {
62 return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
63 }
Roland Levillaina552e1c2015-03-26 15:01:03 +000064
David Srbecky71ec1cc2018-05-18 15:57:25 +010065 size_t size() const { return count_; }
66
67 bool IsValid() const { return count_ != 0; }
68
69 DexRegisterLocation Get(size_t index) const {
70 DCHECK_LT(index, count_);
71 return count_ <= kSmallCount ? regs_small_[index] : regs_large_[index];
72 }
73
74 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number) const {
75 return Get(dex_register_number).GetKind();
76 }
77
78 // TODO: Remove.
79 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number) const {
80 return Get(dex_register_number).GetKind();
81 }
82
83 DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number) const {
84 return Get(dex_register_number);
85 }
Roland Levillaina552e1c2015-03-26 15:01:03 +000086
David Srbecky21d45b42018-05-30 06:35:05 +010087 int32_t GetStackOffsetInBytes(uint16_t dex_register_number) const {
David Srbecky71ec1cc2018-05-18 15:57:25 +010088 DexRegisterLocation location = Get(dex_register_number);
Roland Levillaina552e1c2015-03-26 15:01:03 +000089 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
Roland Levillaina552e1c2015-03-26 15:01:03 +000090 return location.GetValue();
91 }
92
David Srbecky21d45b42018-05-30 06:35:05 +010093 int32_t GetConstant(uint16_t dex_register_number) const {
David Srbecky71ec1cc2018-05-18 15:57:25 +010094 DexRegisterLocation location = Get(dex_register_number);
95 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant);
Roland Levillaina552e1c2015-03-26 15:01:03 +000096 return location.GetValue();
97 }
98
David Srbecky21d45b42018-05-30 06:35:05 +010099 int32_t GetMachineRegister(uint16_t dex_register_number) const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100100 DexRegisterLocation location = Get(dex_register_number);
101 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInRegister ||
102 location.GetKind() == DexRegisterLocation::Kind::kInRegisterHigh ||
103 location.GetKind() == DexRegisterLocation::Kind::kInFpuRegister ||
104 location.GetKind() == DexRegisterLocation::Kind::kInFpuRegisterHigh);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000105 return location.GetValue();
106 }
107
Mingyao Yang01b47b02017-02-03 12:09:57 -0800108 ALWAYS_INLINE bool IsDexRegisterLive(uint16_t dex_register_number) const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100109 return Get(dex_register_number).IsLive();
Roland Levillaina552e1c2015-03-26 15:01:03 +0000110 }
111
David Srbecky71ec1cc2018-05-18 15:57:25 +0100112 size_t GetNumberOfLiveDexRegisters() const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000113 size_t number_of_live_dex_registers = 0;
David Srbecky71ec1cc2018-05-18 15:57:25 +0100114 for (size_t i = 0; i < count_; ++i) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000115 if (IsDexRegisterLive(i)) {
116 ++number_of_live_dex_registers;
117 }
118 }
119 return number_of_live_dex_registers;
120 }
121
David Srbecky71ec1cc2018-05-18 15:57:25 +0100122 bool HasAnyLiveDexRegisters() const {
123 for (size_t i = 0; i < count_; ++i) {
124 if (IsDexRegisterLive(i)) {
125 return true;
126 }
127 }
128 return false;
David Srbecky21d45b42018-05-30 06:35:05 +0100129 }
130
Roland Levillaina552e1c2015-03-26 15:01:03 +0000131 private:
David Srbecky71ec1cc2018-05-18 15:57:25 +0100132 // Store the data inline if the number of registers is small to avoid memory allocations.
133 // If count_ <= kSmallCount, we use the regs_small_ array, and regs_large_ otherwise.
134 static constexpr size_t kSmallCount = 16;
135 size_t count_;
136 std::array<DexRegisterLocation, kSmallCount> regs_small_;
137 dchecked_vector<DexRegisterLocation> regs_large_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000138};
139
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100140/**
141 * A Stack Map holds compilation information for a specific PC necessary for:
142 * - Mapping it to a dex PC,
143 * - Knowing which stack entries are objects,
144 * - Knowing which registers hold objects,
145 * - Knowing the inlining information,
146 * - Knowing the values of dex registers.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100147 */
David Srbecky71ec1cc2018-05-18 15:57:25 +0100148class StackMap : public BitTable<7>::Accessor {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100149 public:
David Srbecky052f8ca2018-04-26 15:42:54 +0100150 enum Field {
David Srbeckyd02b23f2018-05-29 23:27:22 +0100151 kPackedNativePc,
David Srbecky052f8ca2018-04-26 15:42:54 +0100152 kDexPc,
David Srbecky052f8ca2018-04-26 15:42:54 +0100153 kRegisterMaskIndex,
154 kStackMaskIndex,
David Srbecky71ec1cc2018-05-18 15:57:25 +0100155 kInlineInfoIndex,
156 kDexRegisterMaskIndex,
157 kDexRegisterMapIndex,
David Srbecky052f8ca2018-04-26 15:42:54 +0100158 kCount,
159 };
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100160
David Srbecky052f8ca2018-04-26 15:42:54 +0100161 StackMap() : BitTable<kCount>::Accessor(nullptr, -1) {}
162 StackMap(const BitTable<kCount>* table, uint32_t row)
163 : BitTable<kCount>::Accessor(table, row) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100164
David Srbecky052f8ca2018-04-26 15:42:54 +0100165 ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const {
David Srbeckyd02b23f2018-05-29 23:27:22 +0100166 return UnpackNativePc(Get<kPackedNativePc>(), instruction_set);
David Brazdilf677ebf2015-05-29 16:29:43 +0100167 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100168
David Srbecky052f8ca2018-04-26 15:42:54 +0100169 uint32_t GetDexPc() const { return Get<kDexPc>(); }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100170
David Srbecky71ec1cc2018-05-18 15:57:25 +0100171 uint32_t GetDexRegisterMaskIndex() const { return Get<kDexRegisterMaskIndex>(); }
172
173 uint32_t GetDexRegisterMapIndex() const { return Get<kDexRegisterMapIndex>(); }
174 bool HasDexRegisterMap() const { return GetDexRegisterMapIndex() != kNoValue; }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100175
David Srbecky052f8ca2018-04-26 15:42:54 +0100176 uint32_t GetInlineInfoIndex() const { return Get<kInlineInfoIndex>(); }
177 bool HasInlineInfo() const { return GetInlineInfoIndex() != kNoValue; }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100178
David Srbecky052f8ca2018-04-26 15:42:54 +0100179 uint32_t GetRegisterMaskIndex() const { return Get<kRegisterMaskIndex>(); }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100180
David Srbecky052f8ca2018-04-26 15:42:54 +0100181 uint32_t GetStackMaskIndex() const { return Get<kStackMaskIndex>(); }
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,
198 uint16_t number_of_dex_registers,
David Srbecky71ec1cc2018-05-18 15:57:25 +0100199 InstructionSet instruction_set) const;
David Srbecky61b28a12016-02-25 21:55:03 +0000200};
201
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100202/**
David Srbecky052f8ca2018-04-26 15:42:54 +0100203 * Inline information for a specific PC.
204 * The row referenced from the StackMap holds information at depth 0.
205 * Following rows hold information for further depths.
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100206 */
David Srbecky71ec1cc2018-05-18 15:57:25 +0100207class InlineInfo : public BitTable<7>::Accessor {
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100208 public:
David Srbecky052f8ca2018-04-26 15:42:54 +0100209 enum Field {
210 kIsLast, // Determines if there are further rows for further depths.
David Srbecky052f8ca2018-04-26 15:42:54 +0100211 kDexPc,
David Srbecky71ec1cc2018-05-18 15:57:25 +0100212 kMethodIndexIdx,
213 kArtMethodHi, // High bits of ArtMethod*.
214 kArtMethodLo, // Low bits of ArtMethod*.
215 kDexRegisterMaskIndex,
216 kDexRegisterMapIndex,
David Srbecky052f8ca2018-04-26 15:42:54 +0100217 kCount,
218 };
219 static constexpr uint32_t kLast = -1;
220 static constexpr uint32_t kMore = 0;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100221
David Srbecky052f8ca2018-04-26 15:42:54 +0100222 InlineInfo(const BitTable<kCount>* table, uint32_t row)
223 : BitTable<kCount>::Accessor(table, row) {}
224
225 ALWAYS_INLINE InlineInfo AtDepth(uint32_t depth) const {
226 return InlineInfo(table_, this->row_ + depth);
227 }
228
229 uint32_t GetDepth() const {
David Srbecky61b28a12016-02-25 21:55:03 +0000230 size_t depth = 0;
David Srbecky052f8ca2018-04-26 15:42:54 +0100231 while (AtDepth(depth++).Get<kIsLast>() == kMore) { }
David Srbecky61b28a12016-02-25 21:55:03 +0000232 return depth;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100233 }
234
David Srbecky052f8ca2018-04-26 15:42:54 +0100235 uint32_t GetMethodIndexIdxAtDepth(uint32_t depth) const {
236 DCHECK(!EncodesArtMethodAtDepth(depth));
237 return AtDepth(depth).Get<kMethodIndexIdx>();
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100238 }
239
David Srbecky052f8ca2018-04-26 15:42:54 +0100240 uint32_t GetMethodIndexAtDepth(const MethodInfo& method_info, uint32_t depth) const {
241 return method_info.GetMethodIndex(GetMethodIndexIdxAtDepth(depth));
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100242 }
243
David Srbecky052f8ca2018-04-26 15:42:54 +0100244 uint32_t GetDexPcAtDepth(uint32_t depth) const {
245 return AtDepth(depth).Get<kDexPc>();
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700246 }
247
David Srbecky052f8ca2018-04-26 15:42:54 +0100248 bool EncodesArtMethodAtDepth(uint32_t depth) const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100249 return AtDepth(depth).Get<kArtMethodLo>() != kNoValue;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100250 }
251
David Srbecky052f8ca2018-04-26 15:42:54 +0100252 ArtMethod* GetArtMethodAtDepth(uint32_t depth) const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100253 uint64_t lo = AtDepth(depth).Get<kArtMethodLo>();
254 uint64_t hi = AtDepth(depth).Get<kArtMethodHi>();
255 return reinterpret_cast<ArtMethod*>((hi << 32) | lo);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100256 }
257
David Srbecky71ec1cc2018-05-18 15:57:25 +0100258 uint32_t GetDexRegisterMaskIndexAtDepth(uint32_t depth) const {
259 return AtDepth(depth).Get<kDexRegisterMaskIndex>();
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100260 }
261
David Srbecky71ec1cc2018-05-18 15:57:25 +0100262 uint32_t GetDexRegisterMapIndexAtDepth(uint32_t depth) const {
263 return AtDepth(depth).Get<kDexRegisterMapIndex>();
264 }
David Srbecky052f8ca2018-04-26 15:42:54 +0100265 bool HasDexRegisterMapAtDepth(uint32_t depth) const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100266 return GetDexRegisterMapIndexAtDepth(depth) != kNoValue;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100267 }
268
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100269 void Dump(VariableIndentationOutputStream* vios,
David Srbecky61b28a12016-02-25 21:55:03 +0000270 const CodeInfo& info,
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700271 const MethodInfo& method_info,
David Srbecky61b28a12016-02-25 21:55:03 +0000272 uint16_t* number_of_dex_registers) const;
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800273};
274
David Srbecky052f8ca2018-04-26 15:42:54 +0100275class InvokeInfo : public BitTable<3>::Accessor {
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800276 public:
David Srbecky052f8ca2018-04-26 15:42:54 +0100277 enum Field {
David Srbeckyd02b23f2018-05-29 23:27:22 +0100278 kPackedNativePc,
David Srbecky052f8ca2018-04-26 15:42:54 +0100279 kInvokeType,
280 kMethodIndexIdx,
281 kCount,
282 };
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800283
David Srbecky052f8ca2018-04-26 15:42:54 +0100284 InvokeInfo(const BitTable<kCount>* table, uint32_t row)
285 : BitTable<kCount>::Accessor(table, row) {}
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800286
David Srbecky052f8ca2018-04-26 15:42:54 +0100287 ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const {
David Srbeckyd02b23f2018-05-29 23:27:22 +0100288 return StackMap::UnpackNativePc(Get<kPackedNativePc>(), instruction_set);
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800289 }
290
David Srbecky052f8ca2018-04-26 15:42:54 +0100291 uint32_t GetInvokeType() const { return Get<kInvokeType>(); }
292
293 uint32_t GetMethodIndexIdx() const { return Get<kMethodIndexIdx>(); }
294
295 uint32_t GetMethodIndex(MethodInfo method_info) const {
296 return method_info.GetMethodIndex(GetMethodIndexIdx());
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800297 }
David Srbecky09ed0982016-02-12 21:58:43 +0000298};
299
David Srbecky71ec1cc2018-05-18 15:57:25 +0100300class DexRegisterInfo : public BitTable<2>::Accessor {
301 public:
302 enum Field {
303 kKind,
304 kPackedValue,
305 kCount,
306 };
307
308 DexRegisterInfo(const BitTable<kCount>* table, uint32_t row)
309 : BitTable<kCount>::Accessor(table, row) {}
310
311 ALWAYS_INLINE DexRegisterLocation GetLocation() const {
312 DexRegisterLocation::Kind kind = static_cast<DexRegisterLocation::Kind>(Get<kKind>());
313 return DexRegisterLocation(kind, UnpackValue(kind, Get<kPackedValue>()));
314 }
315
316 static uint32_t PackValue(DexRegisterLocation::Kind kind, uint32_t value) {
317 uint32_t packed_value = value;
318 if (kind == DexRegisterLocation::Kind::kInStack) {
319 DCHECK(IsAligned<kFrameSlotSize>(packed_value));
320 packed_value /= kFrameSlotSize;
321 }
322 return packed_value;
323 }
324
325 static uint32_t UnpackValue(DexRegisterLocation::Kind kind, uint32_t packed_value) {
326 uint32_t value = packed_value;
327 if (kind == DexRegisterLocation::Kind::kInStack) {
328 value *= kFrameSlotSize;
329 }
330 return value;
331 }
332};
333
David Srbecky4b59d102018-05-29 21:46:10 +0000334// Register masks tend to have many trailing zero bits (caller-saves are usually not encoded),
335// therefore it is worth encoding the mask as value+shift.
336class RegisterMask : public BitTable<2>::Accessor {
337 public:
338 enum Field {
339 kValue,
340 kShift,
341 kCount,
342 };
343
344 RegisterMask(const BitTable<kCount>* table, uint32_t row)
345 : BitTable<kCount>::Accessor(table, row) {}
346
347 ALWAYS_INLINE uint32_t GetMask() const {
348 return Get<kValue>() << Get<kShift>();
349 }
350};
351
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100352/**
353 * Wrapper around all compiler information collected for a method.
David Srbecky71ec1cc2018-05-18 15:57:25 +0100354 * See the Decode method at the end for the precise binary format.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100355 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100356class CodeInfo {
357 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100358 explicit CodeInfo(const void* data) {
David Srbecky052f8ca2018-04-26 15:42:54 +0100359 Decode(reinterpret_cast<const uint8_t*>(data));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100360 }
361
David Srbecky052f8ca2018-04-26 15:42:54 +0100362 explicit CodeInfo(MemoryRegion region) : CodeInfo(region.begin()) {
363 DCHECK_EQ(size_, region.size());
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100364 }
365
David Srbecky052f8ca2018-04-26 15:42:54 +0100366 explicit CodeInfo(const OatQuickMethodHeader* header)
367 : CodeInfo(header->GetOptimizedCodeInfoPtr()) {
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100368 }
369
David Srbecky052f8ca2018-04-26 15:42:54 +0100370 size_t Size() const {
371 return size_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000372 }
373
David Srbecky052f8ca2018-04-26 15:42:54 +0100374 bool HasInlineInfo() const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100375 return inline_infos_.NumRows() > 0;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100376 }
377
David Srbecky052f8ca2018-04-26 15:42:54 +0100378 ALWAYS_INLINE StackMap GetStackMapAt(size_t index) const {
379 return StackMap(&stack_maps_, index);
David Srbecky45aa5982016-03-18 02:15:09 +0000380 }
381
David Srbecky052f8ca2018-04-26 15:42:54 +0100382 BitMemoryRegion GetStackMask(size_t index) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000383 return stack_masks_.GetBitMemoryRegion(index);
Mathieu Chartier1a20b682017-01-31 14:25:16 -0800384 }
385
David Srbecky052f8ca2018-04-26 15:42:54 +0100386 BitMemoryRegion GetStackMaskOf(const StackMap& stack_map) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000387 uint32_t index = stack_map.GetStackMaskIndex();
388 return (index == StackMap::kNoValue) ? BitMemoryRegion() : GetStackMask(index);
Mathieu Chartier1a20b682017-01-31 14:25:16 -0800389 }
390
David Srbecky052f8ca2018-04-26 15:42:54 +0100391 uint32_t GetRegisterMaskOf(const StackMap& stack_map) const {
David Srbecky4b59d102018-05-29 21:46:10 +0000392 uint32_t index = stack_map.GetRegisterMaskIndex();
393 return (index == StackMap::kNoValue) ? 0 : RegisterMask(&register_masks_, index).GetMask();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100394 }
395
David Srbecky052f8ca2018-04-26 15:42:54 +0100396 uint32_t GetNumberOfLocationCatalogEntries() const {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100397 return dex_register_catalog_.NumRows();
Roland Levillaina552e1c2015-03-26 15:01:03 +0000398 }
399
David Srbecky71ec1cc2018-05-18 15:57:25 +0100400 ALWAYS_INLINE DexRegisterLocation GetDexRegisterCatalogEntry(size_t index) const {
401 return DexRegisterInfo(&dex_register_catalog_, index).GetLocation();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100402 }
403
David Srbecky052f8ca2018-04-26 15:42:54 +0100404 uint32_t GetNumberOfStackMaps() const {
405 return stack_maps_.NumRows();
Nicolas Geoffray6530baf2015-05-26 15:22:58 +0100406 }
407
David Srbecky052f8ca2018-04-26 15:42:54 +0100408 InvokeInfo GetInvokeInfo(size_t index) const {
409 return InvokeInfo(&invoke_infos_, index);
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800410 }
411
David Srbecky71ec1cc2018-05-18 15:57:25 +0100412 ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
413 size_t num_dex_registers) const {
414 return DecodeDexRegisterMap(stack_map.GetDexRegisterMaskIndex(),
415 stack_map.GetDexRegisterMapIndex(),
416 num_dex_registers);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100417 }
418
David Srbecky71ec1cc2018-05-18 15:57:25 +0100419 ALWAYS_INLINE DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
420 InlineInfo inline_info,
421 size_t num_dex_registers) const {
422 return DecodeDexRegisterMap(inline_info.GetDexRegisterMaskIndexAtDepth(depth),
423 inline_info.GetDexRegisterMapIndexAtDepth(depth),
424 num_dex_registers);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100425 }
426
David Srbecky052f8ca2018-04-26 15:42:54 +0100427 InlineInfo GetInlineInfo(size_t index) const {
428 return InlineInfo(&inline_infos_, index);
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800429 }
430
David Srbecky052f8ca2018-04-26 15:42:54 +0100431 InlineInfo GetInlineInfoOf(StackMap stack_map) const {
432 DCHECK(stack_map.HasInlineInfo());
433 uint32_t index = stack_map.GetInlineInfoIndex();
434 return GetInlineInfo(index);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100435 }
436
David Srbecky052f8ca2018-04-26 15:42:54 +0100437 StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
438 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
439 StackMap stack_map = GetStackMapAt(i);
440 if (stack_map.GetDexPc() == dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100441 return stack_map;
442 }
443 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100444 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100445 }
446
David Brazdil77a48ae2015-09-15 12:34:04 +0000447 // Searches the stack map list backwards because catch stack maps are stored
448 // at the end.
David Srbecky052f8ca2018-04-26 15:42:54 +0100449 StackMap GetCatchStackMapForDexPc(uint32_t dex_pc) const {
450 for (size_t i = GetNumberOfStackMaps(); i > 0; --i) {
451 StackMap stack_map = GetStackMapAt(i - 1);
452 if (stack_map.GetDexPc() == dex_pc) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000453 return stack_map;
454 }
455 }
456 return StackMap();
457 }
458
David Srbecky052f8ca2018-04-26 15:42:54 +0100459 StackMap GetOsrStackMapForDexPc(uint32_t dex_pc) const {
460 size_t e = GetNumberOfStackMaps();
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000461 if (e == 0) {
462 // There cannot be OSR stack map if there is no stack map.
463 return StackMap();
464 }
465 // Walk over all stack maps. If two consecutive stack maps are identical, then we
466 // have found a stack map suitable for OSR.
467 for (size_t i = 0; i < e - 1; ++i) {
David Srbecky052f8ca2018-04-26 15:42:54 +0100468 StackMap stack_map = GetStackMapAt(i);
469 if (stack_map.GetDexPc() == dex_pc) {
470 StackMap other = GetStackMapAt(i + 1);
471 if (other.GetDexPc() == dex_pc &&
472 other.GetNativePcOffset(kRuntimeISA) ==
473 stack_map.GetNativePcOffset(kRuntimeISA)) {
David Srbecky71ec1cc2018-05-18 15:57:25 +0100474 DCHECK_EQ(other.GetDexRegisterMapIndex(),
475 stack_map.GetDexRegisterMapIndex());
David Srbecky052f8ca2018-04-26 15:42:54 +0100476 DCHECK(!stack_map.HasInlineInfo());
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000477 if (i < e - 2) {
478 // Make sure there are not three identical stack maps following each other.
Mathieu Chartiera2f526f2017-01-19 14:48:48 -0800479 DCHECK_NE(
David Srbecky052f8ca2018-04-26 15:42:54 +0100480 stack_map.GetNativePcOffset(kRuntimeISA),
481 GetStackMapAt(i + 2).GetNativePcOffset(kRuntimeISA));
Nicolas Geoffrayb331feb2016-02-05 16:51:53 +0000482 }
483 return stack_map;
484 }
485 }
486 }
487 return StackMap();
488 }
489
David Srbecky052f8ca2018-04-26 15:42:54 +0100490 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const {
David Brazdil77a48ae2015-09-15 12:34:04 +0000491 // TODO: Safepoint stack maps are sorted by native_pc_offset but catch stack
492 // maps are not. If we knew that the method does not have try/catch,
493 // we could do binary search.
David Srbecky052f8ca2018-04-26 15:42:54 +0100494 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
495 StackMap stack_map = GetStackMapAt(i);
496 if (stack_map.GetNativePcOffset(kRuntimeISA) == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100497 return stack_map;
498 }
499 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100500 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100501 }
502
David Srbecky052f8ca2018-04-26 15:42:54 +0100503 InvokeInfo GetInvokeInfoForNativePcOffset(uint32_t native_pc_offset) {
504 for (size_t index = 0; index < invoke_infos_.NumRows(); index++) {
505 InvokeInfo item = GetInvokeInfo(index);
506 if (item.GetNativePcOffset(kRuntimeISA) == native_pc_offset) {
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800507 return item;
508 }
509 }
David Srbecky052f8ca2018-04-26 15:42:54 +0100510 return InvokeInfo(&invoke_infos_, -1);
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800511 }
512
David Srbecky71ec1cc2018-05-18 15:57:25 +0100513 // Dump this CodeInfo object on `vios`.
514 // `code_offset` is the (absolute) native PC of the compiled method.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100515 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100516 uint32_t code_offset,
517 uint16_t number_of_dex_registers,
David Srbecky71ec1cc2018-05-18 15:57:25 +0100518 bool verbose,
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700519 InstructionSet instruction_set,
520 const MethodInfo& method_info) const;
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000521
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100522 private:
David Srbecky71ec1cc2018-05-18 15:57:25 +0100523 ALWAYS_INLINE DexRegisterMap DecodeDexRegisterMap(uint32_t mask_index,
524 uint32_t map_index,
525 uint32_t num_dex_registers) const {
526 DexRegisterMap map(map_index == StackMap::kNoValue ? 0 : num_dex_registers);
527 if (mask_index != StackMap::kNoValue) {
528 BitMemoryRegion mask = dex_register_masks_.GetBitMemoryRegion(mask_index);
529 num_dex_registers = std::min<uint32_t>(num_dex_registers, mask.size_in_bits());
530 DexRegisterLocation* regs = map.data();
531 for (uint32_t r = 0; r < mask.size_in_bits(); r++) {
532 if (mask.LoadBit(r) /* is_live */) {
533 DCHECK_LT(r, map.size());
534 regs[r] = GetDexRegisterCatalogEntry(dex_register_maps_.Get(map_index++));
535 }
536 }
537 }
538 return map;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000539 }
540
David Srbecky052f8ca2018-04-26 15:42:54 +0100541 void Decode(const uint8_t* data) {
542 size_t non_header_size = DecodeUnsignedLeb128(&data);
David Srbecky71ec1cc2018-05-18 15:57:25 +0100543 BitMemoryRegion region(MemoryRegion(const_cast<uint8_t*>(data), non_header_size));
David Srbecky052f8ca2018-04-26 15:42:54 +0100544 size_t bit_offset = 0;
545 size_ = UnsignedLeb128Size(non_header_size) + non_header_size;
David Srbecky71ec1cc2018-05-18 15:57:25 +0100546 stack_maps_.Decode(region, &bit_offset);
547 register_masks_.Decode(region, &bit_offset);
548 stack_masks_.Decode(region, &bit_offset);
549 invoke_infos_.Decode(region, &bit_offset);
550 inline_infos_.Decode(region, &bit_offset);
551 dex_register_masks_.Decode(region, &bit_offset);
552 dex_register_maps_.Decode(region, &bit_offset);
553 dex_register_catalog_.Decode(region, &bit_offset);
554 CHECK_EQ(non_header_size, BitsToBytesRoundUp(bit_offset)) << "Invalid CodeInfo";
David Srbecky052f8ca2018-04-26 15:42:54 +0100555 }
556
557 size_t size_;
David Srbecky052f8ca2018-04-26 15:42:54 +0100558 BitTable<StackMap::Field::kCount> stack_maps_;
David Srbecky4b59d102018-05-29 21:46:10 +0000559 BitTable<RegisterMask::Field::kCount> register_masks_;
560 BitTable<1> stack_masks_;
David Srbecky71ec1cc2018-05-18 15:57:25 +0100561 BitTable<InvokeInfo::Field::kCount> invoke_infos_;
562 BitTable<InlineInfo::Field::kCount> inline_infos_;
563 BitTable<1> dex_register_masks_;
564 BitTable<1> dex_register_maps_;
565 BitTable<DexRegisterInfo::Field::kCount> dex_register_catalog_;
David Srbecky052f8ca2018-04-26 15:42:54 +0100566
567 friend class OatDumper;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100568};
569
Roland Levillain1c1da432015-07-16 11:54:44 +0100570#undef ELEMENT_BYTE_OFFSET_AFTER
571#undef ELEMENT_BIT_OFFSET_AFTER
572
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100573} // namespace art
574
575#endif // ART_RUNTIME_STACK_MAP_H_