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 "art_method.h"
22 #include "indenter.h"
23 #include "scoped_thread_state_change-inl.h"
24 
25 namespace art {
26 
27 constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex;
28 constexpr uint32_t StackMap::kNoDexRegisterMap;
29 constexpr uint32_t StackMap::kNoInlineInfo;
30 
operator <<(std::ostream & stream,const DexRegisterLocation::Kind & kind)31 std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind) {
32   using Kind = DexRegisterLocation::Kind;
33   switch (kind) {
34     case Kind::kNone:
35       return stream << "none";
36     case Kind::kInStack:
37       return stream << "in stack";
38     case Kind::kInRegister:
39       return stream << "in register";
40     case Kind::kInRegisterHigh:
41       return stream << "in register high";
42     case Kind::kInFpuRegister:
43       return stream << "in fpu register";
44     case Kind::kInFpuRegisterHigh:
45       return stream << "in fpu register high";
46     case Kind::kConstant:
47       return stream << "as constant";
48     case Kind::kInStackLargeOffset:
49       return stream << "in stack (large offset)";
50     case Kind::kConstantLargeValue:
51       return stream << "as constant (large value)";
52   }
53   return stream << "Kind<" << static_cast<uint32_t>(kind) << ">";
54 }
55 
GetLocationInternalKind(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info,const CodeInfoEncoding & enc) const56 DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind(
57     uint16_t dex_register_number,
58     uint16_t number_of_dex_registers,
59     const CodeInfo& code_info,
60     const CodeInfoEncoding& enc) const {
61   DexRegisterLocationCatalog dex_register_location_catalog =
62       code_info.GetDexRegisterLocationCatalog(enc);
63   size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
64       dex_register_number,
65       number_of_dex_registers,
66       code_info.GetNumberOfLocationCatalogEntries(enc));
67   return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index);
68 }
69 
GetDexRegisterLocation(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info,const CodeInfoEncoding & enc) const70 DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number,
71                                                            uint16_t number_of_dex_registers,
72                                                            const CodeInfo& code_info,
73                                                            const CodeInfoEncoding& enc) const {
74   DexRegisterLocationCatalog dex_register_location_catalog =
75       code_info.GetDexRegisterLocationCatalog(enc);
76   size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
77       dex_register_number,
78       number_of_dex_registers,
79       code_info.GetNumberOfLocationCatalogEntries(enc));
80   return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index);
81 }
82 
DumpRegisterMapping(std::ostream & os,size_t dex_register_num,DexRegisterLocation location,const std::string & prefix="v",const std::string & suffix="")83 static void DumpRegisterMapping(std::ostream& os,
84                                 size_t dex_register_num,
85                                 DexRegisterLocation location,
86                                 const std::string& prefix = "v",
87                                 const std::string& suffix = "") {
88   os << prefix << dex_register_num << ": "
89      << location.GetInternalKind()
90      << " (" << location.GetValue() << ")" << suffix << '\n';
91 }
92 
Dump(VariableIndentationOutputStream * vios) const93 void StackMapEncoding::Dump(VariableIndentationOutputStream* vios) const {
94   vios->Stream()
95       << "StackMapEncoding"
96       << " (native_pc_bit_offset=" << static_cast<uint32_t>(kNativePcBitOffset)
97       << ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_)
98       << ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_)
99       << ", inline_info_bit_offset=" << static_cast<uint32_t>(inline_info_bit_offset_)
100       << ", register_mask_bit_offset=" << static_cast<uint32_t>(register_mask_index_bit_offset_)
101       << ", stack_mask_index_bit_offset=" << static_cast<uint32_t>(stack_mask_index_bit_offset_)
102       << ", total_bit_size=" << static_cast<uint32_t>(total_bit_size_)
103       << ")\n";
104 }
105 
Dump(VariableIndentationOutputStream * vios) const106 void InlineInfoEncoding::Dump(VariableIndentationOutputStream* vios) const {
107   vios->Stream()
108       << "InlineInfoEncoding"
109       << " (method_index_bit_offset=" << static_cast<uint32_t>(kMethodIndexBitOffset)
110       << ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_)
111       << ", extra_data_bit_offset=" << static_cast<uint32_t>(extra_data_bit_offset_)
112       << ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_)
113       << ", total_bit_size=" << static_cast<uint32_t>(total_bit_size_)
114       << ")\n";
115 }
116 
Dump(VariableIndentationOutputStream * vios,uint32_t code_offset,uint16_t number_of_dex_registers,bool dump_stack_maps,InstructionSet instruction_set,const MethodInfo & method_info) const117 void CodeInfo::Dump(VariableIndentationOutputStream* vios,
118                     uint32_t code_offset,
119                     uint16_t number_of_dex_registers,
120                     bool dump_stack_maps,
121                     InstructionSet instruction_set,
122                     const MethodInfo& method_info) const {
123   CodeInfoEncoding encoding = ExtractEncoding();
124   size_t number_of_stack_maps = GetNumberOfStackMaps(encoding);
125   vios->Stream()
126       << "Optimized CodeInfo (number_of_dex_registers=" << number_of_dex_registers
127       << ", number_of_stack_maps=" << number_of_stack_maps
128       << ")\n";
129   ScopedIndentation indent1(vios);
130   encoding.stack_map.encoding.Dump(vios);
131   if (HasInlineInfo(encoding)) {
132     encoding.inline_info.encoding.Dump(vios);
133   }
134   // Display the Dex register location catalog.
135   GetDexRegisterLocationCatalog(encoding).Dump(vios, *this);
136   // Display stack maps along with (live) Dex register maps.
137   if (dump_stack_maps) {
138     for (size_t i = 0; i < number_of_stack_maps; ++i) {
139       StackMap stack_map = GetStackMapAt(i, encoding);
140       stack_map.Dump(vios,
141                      *this,
142                      encoding,
143                      method_info,
144                      code_offset,
145                      number_of_dex_registers,
146                      instruction_set,
147                      " " + std::to_string(i));
148     }
149   }
150   // TODO: Dump the stack map's inline information? We need to know more from the caller:
151   //       we need to know the number of dex registers for each inlined method.
152 }
153 
Dump(VariableIndentationOutputStream * vios,const CodeInfo & code_info)154 void DexRegisterLocationCatalog::Dump(VariableIndentationOutputStream* vios,
155                                       const CodeInfo& code_info) {
156   CodeInfoEncoding encoding = code_info.ExtractEncoding();
157   size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding);
158   size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize(encoding);
159   vios->Stream()
160       << "DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
161       << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n";
162   for (size_t i = 0; i < number_of_location_catalog_entries; ++i) {
163     DexRegisterLocation location = GetDexRegisterLocation(i);
164     ScopedIndentation indent1(vios);
165     DumpRegisterMapping(vios->Stream(), i, location, "entry ");
166   }
167 }
168 
Dump(VariableIndentationOutputStream * vios,const CodeInfo & code_info,uint16_t number_of_dex_registers) const169 void DexRegisterMap::Dump(VariableIndentationOutputStream* vios,
170                           const CodeInfo& code_info,
171                           uint16_t number_of_dex_registers) const {
172   CodeInfoEncoding encoding = code_info.ExtractEncoding();
173   size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding);
174   // TODO: Display the bit mask of live Dex registers.
175   for (size_t j = 0; j < number_of_dex_registers; ++j) {
176     if (IsDexRegisterLive(j)) {
177       size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
178           j, number_of_dex_registers, number_of_location_catalog_entries);
179       DexRegisterLocation location = GetDexRegisterLocation(j,
180                                                             number_of_dex_registers,
181                                                             code_info,
182                                                             encoding);
183       ScopedIndentation indent1(vios);
184       DumpRegisterMapping(
185           vios->Stream(), j, location, "v",
186           "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
187     }
188   }
189 }
190 
Dump(VariableIndentationOutputStream * vios,const CodeInfo & code_info,const CodeInfoEncoding & encoding,const MethodInfo & method_info,uint32_t code_offset,uint16_t number_of_dex_registers,InstructionSet instruction_set,const std::string & header_suffix) const191 void StackMap::Dump(VariableIndentationOutputStream* vios,
192                     const CodeInfo& code_info,
193                     const CodeInfoEncoding& encoding,
194                     const MethodInfo& method_info,
195                     uint32_t code_offset,
196                     uint16_t number_of_dex_registers,
197                     InstructionSet instruction_set,
198                     const std::string& header_suffix) const {
199   StackMapEncoding stack_map_encoding = encoding.stack_map.encoding;
200   const uint32_t pc_offset = GetNativePcOffset(stack_map_encoding, instruction_set);
201   vios->Stream()
202       << "StackMap" << header_suffix
203       << std::hex
204       << " [native_pc=0x" << code_offset + pc_offset << "]"
205       << " [entry_size=0x" << encoding.stack_map.encoding.BitSize() << " bits]"
206       << " (dex_pc=0x" << GetDexPc(stack_map_encoding)
207       << ", native_pc_offset=0x" << pc_offset
208       << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(stack_map_encoding)
209       << ", inline_info_offset=0x" << GetInlineInfoIndex(stack_map_encoding)
210       << ", register_mask=0x" << code_info.GetRegisterMaskOf(encoding, *this)
211       << std::dec
212       << ", stack_mask=0b";
213   BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, *this);
214   for (size_t i = 0, e = encoding.stack_mask.encoding.BitSize(); i < e; ++i) {
215     vios->Stream() << stack_mask.LoadBit(e - i - 1);
216   }
217   vios->Stream() << ")\n";
218   if (HasDexRegisterMap(stack_map_encoding)) {
219     DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
220         *this, encoding, number_of_dex_registers);
221     dex_register_map.Dump(vios, code_info, number_of_dex_registers);
222   }
223   if (HasInlineInfo(stack_map_encoding)) {
224     InlineInfo inline_info = code_info.GetInlineInfoOf(*this, encoding);
225     // We do not know the length of the dex register maps of inlined frames
226     // at this level, so we just pass null to `InlineInfo::Dump` to tell
227     // it not to look at these maps.
228     inline_info.Dump(vios, code_info, method_info, nullptr);
229   }
230 }
231 
Dump(VariableIndentationOutputStream * vios,const CodeInfo & code_info,const MethodInfo & method_info,uint16_t number_of_dex_registers[]) const232 void InlineInfo::Dump(VariableIndentationOutputStream* vios,
233                       const CodeInfo& code_info,
234                       const MethodInfo& method_info,
235                       uint16_t number_of_dex_registers[]) const {
236   InlineInfoEncoding inline_info_encoding = code_info.ExtractEncoding().inline_info.encoding;
237   vios->Stream() << "InlineInfo with depth "
238                  << static_cast<uint32_t>(GetDepth(inline_info_encoding))
239                  << "\n";
240 
241   for (size_t i = 0; i < GetDepth(inline_info_encoding); ++i) {
242     vios->Stream()
243         << " At depth " << i
244         << std::hex
245         << " (dex_pc=0x" << GetDexPcAtDepth(inline_info_encoding, i);
246     if (EncodesArtMethodAtDepth(inline_info_encoding, i)) {
247       ScopedObjectAccess soa(Thread::Current());
248       vios->Stream() << ", method=" << GetArtMethodAtDepth(inline_info_encoding, i)->PrettyMethod();
249     } else {
250       vios->Stream()
251           << std::dec
252           << ", method_index=" << GetMethodIndexAtDepth(inline_info_encoding, method_info, i);
253     }
254     vios->Stream() << ")\n";
255     if (HasDexRegisterMapAtDepth(inline_info_encoding, i) && (number_of_dex_registers != nullptr)) {
256       CodeInfoEncoding encoding = code_info.ExtractEncoding();
257       DexRegisterMap dex_register_map =
258           code_info.GetDexRegisterMapAtDepth(i, *this, encoding, number_of_dex_registers[i]);
259       ScopedIndentation indent1(vios);
260       dex_register_map.Dump(vios, code_info, number_of_dex_registers[i]);
261     }
262   }
263 }
264 
265 }  // namespace art
266