1 /*
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
19 #include <stdint.h>
20
21 #include "indenter.h"
22 #include "invoke_type.h"
23
24 namespace art {
25
26 constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex;
27 constexpr uint32_t StackMap::kNoDexRegisterMap;
28 constexpr uint32_t StackMap::kNoInlineInfo;
29
operator <<(std::ostream & stream,const DexRegisterLocation::Kind & kind)30 std::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
GetLocationInternalKind(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info,const CodeInfoEncoding & enc) const55 DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind(
56 uint16_t dex_register_number,
57 uint16_t number_of_dex_registers,
58 const CodeInfo& code_info,
59 const CodeInfoEncoding& enc) const {
60 DexRegisterLocationCatalog dex_register_location_catalog =
61 code_info.GetDexRegisterLocationCatalog(enc);
62 size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
63 dex_register_number,
64 number_of_dex_registers,
65 code_info.GetNumberOfLocationCatalogEntries(enc));
66 return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index);
67 }
68
GetDexRegisterLocation(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info,const CodeInfoEncoding & enc) const69 DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number,
70 uint16_t number_of_dex_registers,
71 const CodeInfo& code_info,
72 const CodeInfoEncoding& enc) const {
73 DexRegisterLocationCatalog dex_register_location_catalog =
74 code_info.GetDexRegisterLocationCatalog(enc);
75 size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
76 dex_register_number,
77 number_of_dex_registers,
78 code_info.GetNumberOfLocationCatalogEntries(enc));
79 return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index);
80 }
81
DumpRegisterMapping(std::ostream & os,size_t dex_register_num,DexRegisterLocation location,const std::string & prefix="v",const std::string & suffix="")82 static void DumpRegisterMapping(std::ostream& os,
83 size_t dex_register_num,
84 DexRegisterLocation location,
85 const std::string& prefix = "v",
86 const std::string& suffix = "") {
87 os << prefix << dex_register_num << ": "
88 << location.GetInternalKind()
89 << " (" << location.GetValue() << ")" << suffix << '\n';
90 }
91
Dump(VariableIndentationOutputStream * vios) const92 void StackMapEncoding::Dump(VariableIndentationOutputStream* vios) const {
93 vios->Stream()
94 << "StackMapEncoding"
95 << " (native_pc_bit_offset=" << static_cast<uint32_t>(kNativePcBitOffset)
96 << ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_)
97 << ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_)
98 << ", inline_info_bit_offset=" << static_cast<uint32_t>(inline_info_bit_offset_)
99 << ", register_mask_bit_offset=" << static_cast<uint32_t>(register_mask_bit_offset_)
100 << ", stack_mask_bit_offset=" << static_cast<uint32_t>(stack_mask_bit_offset_)
101 << ")\n";
102 }
103
Dump(VariableIndentationOutputStream * vios) const104 void InlineInfoEncoding::Dump(VariableIndentationOutputStream* vios) const {
105 vios->Stream()
106 << "InlineInfoEncoding"
107 << " (method_index_bit_offset=" << static_cast<uint32_t>(kMethodIndexBitOffset)
108 << ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_)
109 << ", invoke_type_bit_offset=" << static_cast<uint32_t>(invoke_type_bit_offset_)
110 << ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_)
111 << ", total_bit_size=" << static_cast<uint32_t>(total_bit_size_)
112 << ")\n";
113 }
114
Dump(VariableIndentationOutputStream * vios,uint32_t code_offset,uint16_t number_of_dex_registers,bool dump_stack_maps) const115 void CodeInfo::Dump(VariableIndentationOutputStream* vios,
116 uint32_t code_offset,
117 uint16_t number_of_dex_registers,
118 bool dump_stack_maps) const {
119 CodeInfoEncoding encoding = ExtractEncoding();
120 size_t number_of_stack_maps = GetNumberOfStackMaps(encoding);
121 vios->Stream()
122 << "Optimized CodeInfo (number_of_dex_registers=" << number_of_dex_registers
123 << ", number_of_stack_maps=" << number_of_stack_maps
124 << ")\n";
125 ScopedIndentation indent1(vios);
126 encoding.stack_map_encoding.Dump(vios);
127 if (HasInlineInfo(encoding)) {
128 encoding.inline_info_encoding.Dump(vios);
129 }
130 // Display the Dex register location catalog.
131 GetDexRegisterLocationCatalog(encoding).Dump(vios, *this);
132 // Display stack maps along with (live) Dex register maps.
133 if (dump_stack_maps) {
134 for (size_t i = 0; i < number_of_stack_maps; ++i) {
135 StackMap stack_map = GetStackMapAt(i, encoding);
136 stack_map.Dump(vios,
137 *this,
138 encoding,
139 code_offset,
140 number_of_dex_registers,
141 " " + std::to_string(i));
142 }
143 }
144 // TODO: Dump the stack map's inline information? We need to know more from the caller:
145 // we need to know the number of dex registers for each inlined method.
146 }
147
Dump(VariableIndentationOutputStream * vios,const CodeInfo & code_info)148 void DexRegisterLocationCatalog::Dump(VariableIndentationOutputStream* vios,
149 const CodeInfo& code_info) {
150 CodeInfoEncoding encoding = code_info.ExtractEncoding();
151 size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding);
152 size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize(encoding);
153 vios->Stream()
154 << "DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
155 << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n";
156 for (size_t i = 0; i < number_of_location_catalog_entries; ++i) {
157 DexRegisterLocation location = GetDexRegisterLocation(i);
158 ScopedIndentation indent1(vios);
159 DumpRegisterMapping(vios->Stream(), i, location, "entry ");
160 }
161 }
162
Dump(VariableIndentationOutputStream * vios,const CodeInfo & code_info,uint16_t number_of_dex_registers) const163 void DexRegisterMap::Dump(VariableIndentationOutputStream* vios,
164 const CodeInfo& code_info,
165 uint16_t number_of_dex_registers) const {
166 CodeInfoEncoding encoding = code_info.ExtractEncoding();
167 size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding);
168 // TODO: Display the bit mask of live Dex registers.
169 for (size_t j = 0; j < number_of_dex_registers; ++j) {
170 if (IsDexRegisterLive(j)) {
171 size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
172 j, number_of_dex_registers, number_of_location_catalog_entries);
173 DexRegisterLocation location = GetDexRegisterLocation(j,
174 number_of_dex_registers,
175 code_info,
176 encoding);
177 ScopedIndentation indent1(vios);
178 DumpRegisterMapping(
179 vios->Stream(), j, location, "v",
180 "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
181 }
182 }
183 }
184
Dump(VariableIndentationOutputStream * vios,const CodeInfo & code_info,const CodeInfoEncoding & encoding,uint32_t code_offset,uint16_t number_of_dex_registers,const std::string & header_suffix) const185 void StackMap::Dump(VariableIndentationOutputStream* vios,
186 const CodeInfo& code_info,
187 const CodeInfoEncoding& encoding,
188 uint32_t code_offset,
189 uint16_t number_of_dex_registers,
190 const std::string& header_suffix) const {
191 StackMapEncoding stack_map_encoding = encoding.stack_map_encoding;
192 vios->Stream()
193 << "StackMap" << header_suffix
194 << std::hex
195 << " [native_pc=0x" << code_offset + GetNativePcOffset(stack_map_encoding) << "]"
196 << " (dex_pc=0x" << GetDexPc(stack_map_encoding)
197 << ", native_pc_offset=0x" << GetNativePcOffset(stack_map_encoding)
198 << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(stack_map_encoding)
199 << ", inline_info_offset=0x" << GetInlineDescriptorOffset(stack_map_encoding)
200 << ", register_mask=0x" << GetRegisterMask(stack_map_encoding)
201 << std::dec
202 << ", stack_mask=0b";
203 for (size_t i = 0, e = GetNumberOfStackMaskBits(stack_map_encoding); i < e; ++i) {
204 vios->Stream() << GetStackMaskBit(stack_map_encoding, e - i - 1);
205 }
206 vios->Stream() << ")\n";
207 if (HasDexRegisterMap(stack_map_encoding)) {
208 DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
209 *this, encoding, number_of_dex_registers);
210 dex_register_map.Dump(vios, code_info, number_of_dex_registers);
211 }
212 if (HasInlineInfo(stack_map_encoding)) {
213 InlineInfo inline_info = code_info.GetInlineInfoOf(*this, encoding);
214 // We do not know the length of the dex register maps of inlined frames
215 // at this level, so we just pass null to `InlineInfo::Dump` to tell
216 // it not to look at these maps.
217 inline_info.Dump(vios, code_info, nullptr);
218 }
219 }
220
Dump(VariableIndentationOutputStream * vios,const CodeInfo & code_info,uint16_t number_of_dex_registers[]) const221 void InlineInfo::Dump(VariableIndentationOutputStream* vios,
222 const CodeInfo& code_info,
223 uint16_t number_of_dex_registers[]) const {
224 InlineInfoEncoding inline_info_encoding = code_info.ExtractEncoding().inline_info_encoding;
225 vios->Stream() << "InlineInfo with depth "
226 << static_cast<uint32_t>(GetDepth(inline_info_encoding))
227 << "\n";
228
229 for (size_t i = 0; i < GetDepth(inline_info_encoding); ++i) {
230 vios->Stream()
231 << " At depth " << i
232 << std::hex
233 << " (dex_pc=0x" << GetDexPcAtDepth(inline_info_encoding, i)
234 << std::dec
235 << ", method_index=" << GetMethodIndexAtDepth(inline_info_encoding, i)
236 << ", invoke_type=" << static_cast<InvokeType>(GetInvokeTypeAtDepth(inline_info_encoding,
237 i))
238 << ")\n";
239 if (HasDexRegisterMapAtDepth(inline_info_encoding, i) && (number_of_dex_registers != nullptr)) {
240 CodeInfoEncoding encoding = code_info.ExtractEncoding();
241 DexRegisterMap dex_register_map =
242 code_info.GetDexRegisterMapAtDepth(i, *this, encoding, number_of_dex_registers[i]);
243 ScopedIndentation indent1(vios);
244 dex_register_map.Dump(vios, code_info, number_of_dex_registers[i]);
245 }
246 }
247 }
248
249 } // namespace art
250