blob: 30934360ace8626f29ef934cb6cc46828b08addc [file] [log] [blame]
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001/*
2 * Copyright (C) 2015 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#include "stack_map.h"
18
Nicolas Geoffray896f8f72015-03-30 15:44:25 +010019#include <stdint.h>
20
Roland Levillain0396ed72015-05-27 15:12:19 +010021#include "indenter.h"
Nicolas Geoffray12bdb722015-06-17 09:44:43 +010022#include "invoke_type.h"
Roland Levillain0396ed72015-05-27 15:12:19 +010023
Nicolas Geoffray004c2302015-03-20 10:06:38 +000024namespace art {
25
Roland Levillaina552e1c2015-03-26 15:01:03 +000026constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000027constexpr uint32_t StackMap::kNoDexRegisterMap;
28constexpr uint32_t StackMap::kNoInlineInfo;
29
David Srbecky7dc11782016-02-25 13:23:56 +000030std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind) {
31 using Kind = DexRegisterLocation::Kind;
32 switch (kind) {
33 case Kind::kNone:
34 return stream << "none";
35 case Kind::kInStack:
36 return stream << "in stack";
37 case Kind::kInRegister:
38 return stream << "in register";
39 case Kind::kInRegisterHigh:
40 return stream << "in register high";
41 case Kind::kInFpuRegister:
42 return stream << "in fpu register";
43 case Kind::kInFpuRegisterHigh:
44 return stream << "in fpu register high";
45 case Kind::kConstant:
46 return stream << "as constant";
47 case Kind::kInStackLargeOffset:
48 return stream << "in stack (large offset)";
49 case Kind::kConstantLargeValue:
50 return stream << "as constant (large value)";
51 }
52 return stream << "Kind<" << static_cast<uint32_t>(kind) << ">";
53}
54
Roland Levillain1c1da432015-07-16 11:54:44 +010055DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind(
56 uint16_t dex_register_number,
57 uint16_t number_of_dex_registers,
58 const CodeInfo& code_info,
59 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +000060 DexRegisterLocationCatalog dex_register_location_catalog =
David Brazdilf677ebf2015-05-29 16:29:43 +010061 code_info.GetDexRegisterLocationCatalog(enc);
Roland Levillaina552e1c2015-03-26 15:01:03 +000062 size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
63 dex_register_number,
64 number_of_dex_registers,
Roland Levillain1c1da432015-07-16 11:54:44 +010065 code_info.GetNumberOfLocationCatalogEntries());
Roland Levillaina552e1c2015-03-26 15:01:03 +000066 return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index);
67}
68
69DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number,
70 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +010071 const CodeInfo& code_info,
72 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +000073 DexRegisterLocationCatalog dex_register_location_catalog =
David Brazdilf677ebf2015-05-29 16:29:43 +010074 code_info.GetDexRegisterLocationCatalog(enc);
Roland Levillaina552e1c2015-03-26 15:01:03 +000075 size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
76 dex_register_number,
77 number_of_dex_registers,
Roland Levillain1c1da432015-07-16 11:54:44 +010078 code_info.GetNumberOfLocationCatalogEntries());
Roland Levillaina552e1c2015-03-26 15:01:03 +000079 return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index);
80}
81
David Brazdilf677ebf2015-05-29 16:29:43 +010082uint32_t StackMap::LoadAt(size_t number_of_bytes, size_t offset, bool check_max) const {
Nicolas Geoffray896f8f72015-03-30 15:44:25 +010083 if (number_of_bytes == 0u) {
84 DCHECK(!check_max);
85 return 0;
86 } else if (number_of_bytes == 1u) {
David Brazdilf677ebf2015-05-29 16:29:43 +010087 uint8_t value = region_.LoadUnaligned<uint8_t>(offset);
88 return (check_max && value == 0xFF) ? -1 : value;
Nicolas Geoffray896f8f72015-03-30 15:44:25 +010089 } else if (number_of_bytes == 2u) {
David Brazdilf677ebf2015-05-29 16:29:43 +010090 uint16_t value = region_.LoadUnaligned<uint16_t>(offset);
91 return (check_max && value == 0xFFFF) ? -1 : value;
Nicolas Geoffray896f8f72015-03-30 15:44:25 +010092 } else if (number_of_bytes == 3u) {
David Brazdilf677ebf2015-05-29 16:29:43 +010093 uint16_t low = region_.LoadUnaligned<uint16_t>(offset);
94 uint16_t high = region_.LoadUnaligned<uint8_t>(offset + sizeof(uint16_t));
Nicolas Geoffray896f8f72015-03-30 15:44:25 +010095 uint32_t value = (high << 16) + low;
David Brazdilf677ebf2015-05-29 16:29:43 +010096 return (check_max && value == 0xFFFFFF) ? -1 : value;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000097 } else {
Nicolas Geoffray896f8f72015-03-30 15:44:25 +010098 DCHECK_EQ(number_of_bytes, 4u);
David Brazdilf677ebf2015-05-29 16:29:43 +010099 return region_.LoadUnaligned<uint32_t>(offset);
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000100 }
101}
102
David Brazdilf677ebf2015-05-29 16:29:43 +0100103void StackMap::StoreAt(size_t number_of_bytes, size_t offset, uint32_t value) const {
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100104 if (number_of_bytes == 0u) {
105 DCHECK_EQ(value, 0u);
106 } else if (number_of_bytes == 1u) {
David Brazdilf677ebf2015-05-29 16:29:43 +0100107 region_.StoreUnaligned<uint8_t>(offset, value);
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100108 } else if (number_of_bytes == 2u) {
David Brazdilf677ebf2015-05-29 16:29:43 +0100109 region_.StoreUnaligned<uint16_t>(offset, value);
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100110 } else if (number_of_bytes == 3u) {
David Brazdilf677ebf2015-05-29 16:29:43 +0100111 region_.StoreUnaligned<uint16_t>(offset, Low16Bits(value));
112 region_.StoreUnaligned<uint8_t>(offset + sizeof(uint16_t), High16Bits(value));
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100113 } else {
David Brazdilf677ebf2015-05-29 16:29:43 +0100114 region_.StoreUnaligned<uint32_t>(offset, value);
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100115 DCHECK_EQ(number_of_bytes, 4u);
116 }
117}
118
Roland Levillaina552e1c2015-03-26 15:01:03 +0000119static void DumpRegisterMapping(std::ostream& os,
120 size_t dex_register_num,
121 DexRegisterLocation location,
122 const std::string& prefix = "v",
123 const std::string& suffix = "") {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100124 os << prefix << dex_register_num << ": "
David Srbecky7dc11782016-02-25 13:23:56 +0000125 << location.GetInternalKind()
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100126 << " (" << location.GetValue() << ")" << suffix << '\n';
Roland Levillain0396ed72015-05-27 15:12:19 +0100127}
128
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100129void CodeInfo::Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100130 uint32_t code_offset,
Roland Levillain0396ed72015-05-27 15:12:19 +0100131 uint16_t number_of_dex_registers,
132 bool dump_stack_maps) const {
David Brazdilf677ebf2015-05-29 16:29:43 +0100133 StackMapEncoding encoding = ExtractEncoding();
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000134 uint32_t code_info_size = GetOverallSize();
135 size_t number_of_stack_maps = GetNumberOfStackMaps();
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100136 vios->Stream()
137 << "Optimized CodeInfo (size=" << code_info_size
138 << ", number_of_dex_registers=" << number_of_dex_registers
139 << ", number_of_stack_maps=" << number_of_stack_maps
140 << ", has_inline_info=" << encoding.HasInlineInfo()
141 << ", number_of_bytes_for_inline_info=" << encoding.NumberOfBytesForInlineInfo()
142 << ", number_of_bytes_for_dex_register_map=" << encoding.NumberOfBytesForDexRegisterMap()
143 << ", number_of_bytes_for_dex_pc=" << encoding.NumberOfBytesForDexPc()
144 << ", number_of_bytes_for_native_pc=" << encoding.NumberOfBytesForNativePc()
145 << ", number_of_bytes_for_register_mask=" << encoding.NumberOfBytesForRegisterMask()
146 << ")\n";
147 ScopedIndentation indent1(vios);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000148 // Display the Dex register location catalog.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100149 GetDexRegisterLocationCatalog(encoding).Dump(vios, *this);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000150 // Display stack maps along with (live) Dex register maps.
Roland Levillain0396ed72015-05-27 15:12:19 +0100151 if (dump_stack_maps) {
152 for (size_t i = 0; i < number_of_stack_maps; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +0100153 StackMap stack_map = GetStackMapAt(i, encoding);
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100154 stack_map.Dump(vios,
David Brazdilf677ebf2015-05-29 16:29:43 +0100155 *this,
156 encoding,
157 code_offset,
158 number_of_dex_registers,
159 " " + std::to_string(i));
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000160 }
161 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100162 // TODO: Dump the stack map's inline information? We need to know more from the caller:
163 // we need to know the number of dex registers for each inlined method.
164}
165
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100166void DexRegisterLocationCatalog::Dump(VariableIndentationOutputStream* vios,
167 const CodeInfo& code_info) {
David Brazdilf677ebf2015-05-29 16:29:43 +0100168 StackMapEncoding encoding = code_info.ExtractEncoding();
Roland Levillain1c1da432015-07-16 11:54:44 +0100169 size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
David Brazdilf677ebf2015-05-29 16:29:43 +0100170 size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize(encoding);
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100171 vios->Stream()
Roland Levillain0396ed72015-05-27 15:12:19 +0100172 << "DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
173 << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n";
174 for (size_t i = 0; i < number_of_location_catalog_entries; ++i) {
175 DexRegisterLocation location = GetDexRegisterLocation(i);
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100176 ScopedIndentation indent1(vios);
177 DumpRegisterMapping(vios->Stream(), i, location, "entry ");
Roland Levillain0396ed72015-05-27 15:12:19 +0100178 }
179}
180
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100181void DexRegisterMap::Dump(VariableIndentationOutputStream* vios,
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100182 const CodeInfo& code_info,
183 uint16_t number_of_dex_registers) const {
David Brazdilf677ebf2015-05-29 16:29:43 +0100184 StackMapEncoding encoding = code_info.ExtractEncoding();
Roland Levillain1c1da432015-07-16 11:54:44 +0100185 size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100186 // TODO: Display the bit mask of live Dex registers.
187 for (size_t j = 0; j < number_of_dex_registers; ++j) {
188 if (IsDexRegisterLive(j)) {
189 size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
190 j, number_of_dex_registers, number_of_location_catalog_entries);
David Brazdilf677ebf2015-05-29 16:29:43 +0100191 DexRegisterLocation location = GetDexRegisterLocation(j,
192 number_of_dex_registers,
193 code_info,
194 encoding);
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100195 ScopedIndentation indent1(vios);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100196 DumpRegisterMapping(
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100197 vios->Stream(), j, location, "v",
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100198 "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
199 }
200 }
201}
202
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100203void StackMap::Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100204 const CodeInfo& code_info,
David Brazdilf677ebf2015-05-29 16:29:43 +0100205 const StackMapEncoding& encoding,
Roland Levillainf2650d12015-05-28 14:53:28 +0100206 uint32_t code_offset,
207 uint16_t number_of_dex_registers,
208 const std::string& header_suffix) const {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100209 vios->Stream()
210 << "StackMap" << header_suffix
211 << std::hex
212 << " [native_pc=0x" << code_offset + GetNativePcOffset(encoding) << "]"
213 << " (dex_pc=0x" << GetDexPc(encoding)
214 << ", native_pc_offset=0x" << GetNativePcOffset(encoding)
215 << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(encoding)
216 << ", inline_info_offset=0x" << GetInlineDescriptorOffset(encoding)
217 << ", register_mask=0x" << GetRegisterMask(encoding)
218 << std::dec
219 << ", stack_mask=0b";
David Brazdilf677ebf2015-05-29 16:29:43 +0100220 MemoryRegion stack_mask = GetStackMask(encoding);
Roland Levillainf2650d12015-05-28 14:53:28 +0100221 for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100222 vios->Stream() << stack_mask.LoadBit(e - i - 1);
Roland Levillainf2650d12015-05-28 14:53:28 +0100223 }
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100224 vios->Stream() << ")\n";
David Brazdilf677ebf2015-05-29 16:29:43 +0100225 if (HasDexRegisterMap(encoding)) {
226 DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
227 *this, encoding, number_of_dex_registers);
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100228 dex_register_map.Dump(vios, code_info, number_of_dex_registers);
Roland Levillainf2650d12015-05-28 14:53:28 +0100229 }
Nicolas Geoffray12bdb722015-06-17 09:44:43 +0100230 if (HasInlineInfo(encoding)) {
231 InlineInfo inline_info = code_info.GetInlineInfoOf(*this, encoding);
232 // We do not know the length of the dex register maps of inlined frames
233 // at this level, so we just pass null to `InlineInfo::Dump` to tell
234 // it not to look at these maps.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100235 inline_info.Dump(vios, code_info, nullptr);
Nicolas Geoffray12bdb722015-06-17 09:44:43 +0100236 }
Roland Levillainf2650d12015-05-28 14:53:28 +0100237}
238
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100239void InlineInfo::Dump(VariableIndentationOutputStream* vios,
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100240 const CodeInfo& code_info,
241 uint16_t number_of_dex_registers[]) const {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100242 vios->Stream() << "InlineInfo with depth " << static_cast<uint32_t>(GetDepth()) << "\n";
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100243
244 for (size_t i = 0; i < GetDepth(); ++i) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100245 vios->Stream()
246 << " At depth " << i
247 << std::hex
248 << " (dex_pc=0x" << GetDexPcAtDepth(i)
249 << std::dec
250 << ", method_index=" << GetMethodIndexAtDepth(i)
251 << ", invoke_type=" << static_cast<InvokeType>(GetInvokeTypeAtDepth(i))
252 << ")\n";
Nicolas Geoffray12bdb722015-06-17 09:44:43 +0100253 if (HasDexRegisterMapAtDepth(i) && (number_of_dex_registers != nullptr)) {
David Brazdilf677ebf2015-05-29 16:29:43 +0100254 StackMapEncoding encoding = code_info.ExtractEncoding();
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100255 DexRegisterMap dex_register_map =
David Brazdilf677ebf2015-05-29 16:29:43 +0100256 code_info.GetDexRegisterMapAtDepth(i, *this, encoding, number_of_dex_registers[i]);
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100257 ScopedIndentation indent1(vios);
258 dex_register_map.Dump(vios, code_info, number_of_dex_registers[i]);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100259 }
260 }
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000261}
262
263} // namespace art