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
24namespace art {
25
26constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex;
27constexpr uint32_t StackMap::kNoDexRegisterMap;
28constexpr uint32_t StackMap::kNoInlineInfo;
29
30std::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
55DexRegisterLocation::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
69DexRegisterLocation 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
82static 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
92void 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
104void 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
115void 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
148void 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
163void 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
185void 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
221void 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