blob: c36ee05eaae01ec3fac27dd9641437bf3be3e691 [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"
22
Nicolas Geoffray004c2302015-03-20 10:06:38 +000023namespace art {
24
Roland Levillaina552e1c2015-03-26 15:01:03 +000025constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000026constexpr uint32_t StackMap::kNoDexRegisterMap;
27constexpr uint32_t StackMap::kNoInlineInfo;
28
Roland Levillaina552e1c2015-03-26 15:01:03 +000029DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind(uint16_t dex_register_number,
30 uint16_t number_of_dex_registers,
31 const CodeInfo& code_info) const {
32 DexRegisterLocationCatalog dex_register_location_catalog =
33 code_info.GetDexRegisterLocationCatalog();
34 size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
35 dex_register_number,
36 number_of_dex_registers,
37 code_info.GetNumberOfDexRegisterLocationCatalogEntries());
38 return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index);
39}
40
41DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number,
42 uint16_t number_of_dex_registers,
43 const CodeInfo& code_info) const {
44 DexRegisterLocationCatalog dex_register_location_catalog =
45 code_info.GetDexRegisterLocationCatalog();
46 size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
47 dex_register_number,
48 number_of_dex_registers,
49 code_info.GetNumberOfDexRegisterLocationCatalogEntries());
50 return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index);
51}
52
Nicolas Geoffray896f8f72015-03-30 15:44:25 +010053// Loads `number_of_bytes` at the given `offset` and assemble a uint32_t. If `check_max` is true,
54// this method converts a maximum value of size `number_of_bytes` into a uint32_t 0xFFFFFFFF.
55static uint32_t LoadAt(MemoryRegion region,
56 size_t number_of_bytes,
57 size_t offset,
58 bool check_max = false) {
59 if (number_of_bytes == 0u) {
60 DCHECK(!check_max);
61 return 0;
62 } else if (number_of_bytes == 1u) {
63 uint8_t value = region.LoadUnaligned<uint8_t>(offset);
64 if (check_max && value == 0xFF) {
65 return -1;
66 } else {
67 return value;
68 }
69 } else if (number_of_bytes == 2u) {
70 uint16_t value = region.LoadUnaligned<uint16_t>(offset);
71 if (check_max && value == 0xFFFF) {
72 return -1;
73 } else {
74 return value;
75 }
76 } else if (number_of_bytes == 3u) {
77 uint16_t low = region.LoadUnaligned<uint16_t>(offset);
78 uint16_t high = region.LoadUnaligned<uint8_t>(offset + sizeof(uint16_t));
79 uint32_t value = (high << 16) + low;
80 if (check_max && value == 0xFFFFFF) {
81 return -1;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000082 } else {
83 return value;
84 }
85 } else {
Nicolas Geoffray896f8f72015-03-30 15:44:25 +010086 DCHECK_EQ(number_of_bytes, 4u);
87 return region.LoadUnaligned<uint32_t>(offset);
Nicolas Geoffray004c2302015-03-20 10:06:38 +000088 }
89}
90
Nicolas Geoffray896f8f72015-03-30 15:44:25 +010091static void StoreAt(MemoryRegion region, size_t number_of_bytes, size_t offset, uint32_t value) {
92 if (number_of_bytes == 0u) {
93 DCHECK_EQ(value, 0u);
94 } else if (number_of_bytes == 1u) {
95 region.StoreUnaligned<uint8_t>(offset, value);
96 } else if (number_of_bytes == 2u) {
97 region.StoreUnaligned<uint16_t>(offset, value);
98 } else if (number_of_bytes == 3u) {
99 region.StoreUnaligned<uint16_t>(offset, Low16Bits(value));
100 region.StoreUnaligned<uint8_t>(offset + sizeof(uint16_t), High16Bits(value));
101 } else {
102 region.StoreUnaligned<uint32_t>(offset, value);
103 DCHECK_EQ(number_of_bytes, 4u);
104 }
105}
106
107uint32_t StackMap::GetDexPc(const CodeInfo& info) const {
108 return LoadAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset());
109}
110
111void StackMap::SetDexPc(const CodeInfo& info, uint32_t dex_pc) {
112 StoreAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset(), dex_pc);
113}
114
115uint32_t StackMap::GetNativePcOffset(const CodeInfo& info) const {
116 return LoadAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset());
117}
118
119void StackMap::SetNativePcOffset(const CodeInfo& info, uint32_t native_pc_offset) {
120 StoreAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset(), native_pc_offset);
121}
122
123uint32_t StackMap::GetDexRegisterMapOffset(const CodeInfo& info) const {
124 return LoadAt(region_,
125 info.NumberOfBytesForDexRegisterMap(),
126 info.ComputeStackMapDexRegisterMapOffset(),
127 /* check_max */ true);
128}
129
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000130void StackMap::SetDexRegisterMapOffset(const CodeInfo& info, uint32_t offset) {
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100131 StoreAt(region_,
132 info.NumberOfBytesForDexRegisterMap(),
133 info.ComputeStackMapDexRegisterMapOffset(),
134 offset);
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000135}
136
137uint32_t StackMap::GetInlineDescriptorOffset(const CodeInfo& info) const {
138 if (!info.HasInlineInfo()) return kNoInlineInfo;
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100139 return LoadAt(region_,
140 info.NumberOfBytesForInlineInfo(),
141 info.ComputeStackMapInlineInfoOffset(),
142 /* check_max */ true);
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000143}
144
145void StackMap::SetInlineDescriptorOffset(const CodeInfo& info, uint32_t offset) {
146 DCHECK(info.HasInlineInfo());
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100147 StoreAt(region_,
148 info.NumberOfBytesForInlineInfo(),
149 info.ComputeStackMapInlineInfoOffset(),
150 offset);
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000151}
152
153uint32_t StackMap::GetRegisterMask(const CodeInfo& info) const {
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100154 return LoadAt(region_,
155 info.NumberOfBytesForRegisterMask(),
156 info.ComputeStackMapRegisterMaskOffset());
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000157}
158
159void StackMap::SetRegisterMask(const CodeInfo& info, uint32_t mask) {
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100160 StoreAt(region_,
161 info.NumberOfBytesForRegisterMask(),
162 info.ComputeStackMapRegisterMaskOffset(),
163 mask);
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000164}
165
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100166size_t StackMap::ComputeStackMapSizeInternal(size_t stack_mask_size,
167 size_t number_of_bytes_for_inline_info,
168 size_t number_of_bytes_for_dex_map,
169 size_t number_of_bytes_for_dex_pc,
170 size_t number_of_bytes_for_native_pc,
171 size_t number_of_bytes_for_register_mask) {
172 return stack_mask_size
173 + number_of_bytes_for_inline_info
174 + number_of_bytes_for_dex_map
175 + number_of_bytes_for_dex_pc
176 + number_of_bytes_for_native_pc
177 + number_of_bytes_for_register_mask;
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000178}
179
180size_t StackMap::ComputeStackMapSize(size_t stack_mask_size,
181 size_t inline_info_size,
182 size_t dex_register_map_size,
183 size_t dex_pc_max,
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100184 size_t native_pc_max,
185 size_t register_mask_max) {
186 return ComputeStackMapSizeInternal(
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000187 stack_mask_size,
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100188 inline_info_size == 0
189 ? 0
190 // + 1 to also encode kNoInlineInfo.
191 : CodeInfo::EncodingSizeInBytes(inline_info_size + dex_register_map_size + 1),
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000192 // + 1 to also encode kNoDexRegisterMap.
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100193 CodeInfo::EncodingSizeInBytes(dex_register_map_size + 1),
194 CodeInfo::EncodingSizeInBytes(dex_pc_max),
195 CodeInfo::EncodingSizeInBytes(native_pc_max),
196 CodeInfo::EncodingSizeInBytes(register_mask_max));
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000197}
198
199MemoryRegion StackMap::GetStackMask(const CodeInfo& info) const {
200 return region_.Subregion(info.ComputeStackMapStackMaskOffset(), info.GetStackMaskSize());
201}
202
Roland Levillaina552e1c2015-03-26 15:01:03 +0000203static void DumpRegisterMapping(std::ostream& os,
204 size_t dex_register_num,
205 DexRegisterLocation location,
206 const std::string& prefix = "v",
207 const std::string& suffix = "") {
Roland Levillain0396ed72015-05-27 15:12:19 +0100208 Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
209 std::ostream indented_os(&indent_filter);
210 indented_os << prefix << dex_register_num << ": "
211 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind())
212 << " (" << location.GetValue() << ")" << suffix << '\n';
213}
214
215void CodeInfo::DumpStackMap(std::ostream& os,
216 size_t stack_map_num,
217 uint16_t number_of_dex_registers) const {
218 StackMap stack_map = GetStackMapAt(stack_map_num);
219 DumpStackMapHeader(os, stack_map_num);
220 if (stack_map.HasDexRegisterMap(*this)) {
221 DexRegisterMap dex_register_map = GetDexRegisterMapOf(stack_map, number_of_dex_registers);
222 dex_register_map.Dump(os, *this, number_of_dex_registers);
223 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000224}
225
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000226void CodeInfo::DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const {
227 StackMap stack_map = GetStackMapAt(stack_map_num);
Roland Levillain0396ed72015-05-27 15:12:19 +0100228 Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
229 std::ostream indented_os(&indent_filter);
230 indented_os << "StackMap " << stack_map_num
231 << std::hex
232 << " (dex_pc=0x" << stack_map.GetDexPc(*this)
233 << ", native_pc_offset=0x" << stack_map.GetNativePcOffset(*this)
234 << ", dex_register_map_offset=0x" << stack_map.GetDexRegisterMapOffset(*this)
235 << ", inline_info_offset=0x" << stack_map.GetInlineDescriptorOffset(*this)
236 << ", register_mask=0x" << stack_map.GetRegisterMask(*this)
237 << std::dec
238 << ", stack_mask=0b";
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000239 MemoryRegion stack_mask = stack_map.GetStackMask(*this);
240 for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
Roland Levillain0396ed72015-05-27 15:12:19 +0100241 indented_os << stack_mask.LoadBit(e - i - 1);
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000242 }
Roland Levillain0396ed72015-05-27 15:12:19 +0100243 indented_os << ")\n";
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000244};
245
Roland Levillain0396ed72015-05-27 15:12:19 +0100246void CodeInfo::Dump(std::ostream& os,
247 uint16_t number_of_dex_registers,
248 bool dump_stack_maps) const {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000249 uint32_t code_info_size = GetOverallSize();
250 size_t number_of_stack_maps = GetNumberOfStackMaps();
Roland Levillain0396ed72015-05-27 15:12:19 +0100251 Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
252 std::ostream indented_os(&indent_filter);
253 indented_os << "Optimized CodeInfo (size=" << code_info_size
254 << ", number_of_dex_registers=" << number_of_dex_registers
255 << ", number_of_stack_maps=" << number_of_stack_maps
256 << ", has_inline_info=" << HasInlineInfo()
257 << ", number_of_bytes_for_inline_info=" << NumberOfBytesForInlineInfo()
258 << ", number_of_bytes_for_dex_register_map=" << NumberOfBytesForDexRegisterMap()
259 << ", number_of_bytes_for_dex_pc=" << NumberOfBytesForDexPc()
260 << ", number_of_bytes_for_native_pc=" << NumberOfBytesForNativePc()
261 << ", number_of_bytes_for_register_mask=" << NumberOfBytesForRegisterMask()
262 << ")\n";
Roland Levillaina552e1c2015-03-26 15:01:03 +0000263 // Display the Dex register location catalog.
Roland Levillain0396ed72015-05-27 15:12:19 +0100264 GetDexRegisterLocationCatalog().Dump(indented_os, *this);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000265 // Display stack maps along with (live) Dex register maps.
Roland Levillain0396ed72015-05-27 15:12:19 +0100266 if (dump_stack_maps) {
267 for (size_t i = 0; i < number_of_stack_maps; ++i) {
268 DumpStackMap(indented_os, i, number_of_dex_registers);
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000269 }
270 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100271 // TODO: Dump the stack map's inline information? We need to know more from the caller:
272 // we need to know the number of dex registers for each inlined method.
273}
274
Roland Levillain0396ed72015-05-27 15:12:19 +0100275void DexRegisterLocationCatalog::Dump(std::ostream& os, const CodeInfo& code_info) {
276 size_t number_of_location_catalog_entries =
277 code_info.GetNumberOfDexRegisterLocationCatalogEntries();
278 size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize();
279 Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
280 std::ostream indented_os(&indent_filter);
281 indented_os
282 << "DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
283 << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n";
284 for (size_t i = 0; i < number_of_location_catalog_entries; ++i) {
285 DexRegisterLocation location = GetDexRegisterLocation(i);
286 DumpRegisterMapping(indented_os, i, location, "entry ");
287 }
288}
289
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100290void DexRegisterMap::Dump(std::ostream& os,
291 const CodeInfo& code_info,
292 uint16_t number_of_dex_registers) const {
293 size_t number_of_location_catalog_entries =
294 code_info.GetNumberOfDexRegisterLocationCatalogEntries();
Roland Levillain0396ed72015-05-27 15:12:19 +0100295 Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
296 std::ostream indented_os(&indent_filter);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100297 // TODO: Display the bit mask of live Dex registers.
298 for (size_t j = 0; j < number_of_dex_registers; ++j) {
299 if (IsDexRegisterLive(j)) {
300 size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
301 j, number_of_dex_registers, number_of_location_catalog_entries);
302 DexRegisterLocation location = GetDexRegisterLocation(j, number_of_dex_registers, code_info);
303 DumpRegisterMapping(
Roland Levillain0396ed72015-05-27 15:12:19 +0100304 indented_os, j, location, "v",
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100305 "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
306 }
307 }
308}
309
310void InlineInfo::Dump(std::ostream& os,
311 const CodeInfo& code_info,
312 uint16_t number_of_dex_registers[]) const {
Roland Levillain0396ed72015-05-27 15:12:19 +0100313 Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
314 std::ostream indented_os(&indent_filter);
315 indented_os << "InlineInfo with depth " << static_cast<uint32_t>(GetDepth()) << "\n";
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100316
317 for (size_t i = 0; i < GetDepth(); ++i) {
Roland Levillain0396ed72015-05-27 15:12:19 +0100318 indented_os << " At depth " << i
319 << std::hex
320 << " (dex_pc=0x" << GetDexPcAtDepth(i)
321 << ", method_index=0x" << GetMethodIndexAtDepth(i)
322 << ")\n";
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100323 if (HasDexRegisterMapAtDepth(i)) {
324 DexRegisterMap dex_register_map =
325 code_info.GetDexRegisterMapAtDepth(i, *this, number_of_dex_registers[i]);
Roland Levillain0396ed72015-05-27 15:12:19 +0100326 dex_register_map.Dump(indented_os, code_info, number_of_dex_registers[i]);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100327 }
328 }
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000329}
330
331} // namespace art