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
21namespace art {
22
23constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex;
24constexpr uint32_t StackMap::kNoDexRegisterMap;
25constexpr uint32_t StackMap::kNoInlineInfo;
26
27DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind(uint16_t dex_register_number,
28                                                                  uint16_t number_of_dex_registers,
29                                                                  const CodeInfo& code_info) const {
30  DexRegisterLocationCatalog dex_register_location_catalog =
31      code_info.GetDexRegisterLocationCatalog();
32  size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
33      dex_register_number,
34      number_of_dex_registers,
35      code_info.GetNumberOfDexRegisterLocationCatalogEntries());
36  return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index);
37}
38
39DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number,
40                                                           uint16_t number_of_dex_registers,
41                                                           const CodeInfo& code_info) const {
42  DexRegisterLocationCatalog dex_register_location_catalog =
43      code_info.GetDexRegisterLocationCatalog();
44  size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
45      dex_register_number,
46      number_of_dex_registers,
47      code_info.GetNumberOfDexRegisterLocationCatalogEntries());
48  return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index);
49}
50
51// Loads `number_of_bytes` at the given `offset` and assemble a uint32_t. If `check_max` is true,
52// this method converts a maximum value of size `number_of_bytes` into a uint32_t 0xFFFFFFFF.
53static uint32_t LoadAt(MemoryRegion region,
54                       size_t number_of_bytes,
55                       size_t offset,
56                       bool check_max = false) {
57  if (number_of_bytes == 0u) {
58    DCHECK(!check_max);
59    return 0;
60  } else if (number_of_bytes == 1u) {
61    uint8_t value = region.LoadUnaligned<uint8_t>(offset);
62    if (check_max && value == 0xFF) {
63      return -1;
64    } else {
65      return value;
66    }
67  } else if (number_of_bytes == 2u) {
68    uint16_t value = region.LoadUnaligned<uint16_t>(offset);
69    if (check_max && value == 0xFFFF) {
70      return -1;
71    } else {
72      return value;
73    }
74  } else if (number_of_bytes == 3u) {
75    uint16_t low = region.LoadUnaligned<uint16_t>(offset);
76    uint16_t high = region.LoadUnaligned<uint8_t>(offset + sizeof(uint16_t));
77    uint32_t value = (high << 16) + low;
78    if (check_max && value == 0xFFFFFF) {
79      return -1;
80    } else {
81      return value;
82    }
83  } else {
84    DCHECK_EQ(number_of_bytes, 4u);
85    return region.LoadUnaligned<uint32_t>(offset);
86  }
87}
88
89static void StoreAt(MemoryRegion region, size_t number_of_bytes, size_t offset, uint32_t value) {
90  if (number_of_bytes == 0u) {
91    DCHECK_EQ(value, 0u);
92  } else if (number_of_bytes == 1u) {
93    region.StoreUnaligned<uint8_t>(offset, value);
94  } else if (number_of_bytes == 2u) {
95    region.StoreUnaligned<uint16_t>(offset, value);
96  } else if (number_of_bytes == 3u) {
97    region.StoreUnaligned<uint16_t>(offset, Low16Bits(value));
98    region.StoreUnaligned<uint8_t>(offset + sizeof(uint16_t), High16Bits(value));
99  } else {
100    region.StoreUnaligned<uint32_t>(offset, value);
101    DCHECK_EQ(number_of_bytes, 4u);
102  }
103}
104
105uint32_t StackMap::GetDexPc(const CodeInfo& info) const {
106  return LoadAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset());
107}
108
109void StackMap::SetDexPc(const CodeInfo& info, uint32_t dex_pc) {
110  StoreAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset(), dex_pc);
111}
112
113uint32_t StackMap::GetNativePcOffset(const CodeInfo& info) const {
114  return LoadAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset());
115}
116
117void StackMap::SetNativePcOffset(const CodeInfo& info, uint32_t native_pc_offset) {
118  StoreAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset(), native_pc_offset);
119}
120
121uint32_t StackMap::GetDexRegisterMapOffset(const CodeInfo& info) const {
122  return LoadAt(region_,
123                info.NumberOfBytesForDexRegisterMap(),
124                info.ComputeStackMapDexRegisterMapOffset(),
125                /* check_max */ true);
126}
127
128void StackMap::SetDexRegisterMapOffset(const CodeInfo& info, uint32_t offset) {
129  StoreAt(region_,
130          info.NumberOfBytesForDexRegisterMap(),
131          info.ComputeStackMapDexRegisterMapOffset(),
132          offset);
133}
134
135uint32_t StackMap::GetInlineDescriptorOffset(const CodeInfo& info) const {
136  if (!info.HasInlineInfo()) return kNoInlineInfo;
137  return LoadAt(region_,
138                info.NumberOfBytesForInlineInfo(),
139                info.ComputeStackMapInlineInfoOffset(),
140                /* check_max */ true);
141}
142
143void StackMap::SetInlineDescriptorOffset(const CodeInfo& info, uint32_t offset) {
144  DCHECK(info.HasInlineInfo());
145  StoreAt(region_,
146          info.NumberOfBytesForInlineInfo(),
147          info.ComputeStackMapInlineInfoOffset(),
148          offset);
149}
150
151uint32_t StackMap::GetRegisterMask(const CodeInfo& info) const {
152  return LoadAt(region_,
153                info.NumberOfBytesForRegisterMask(),
154                info.ComputeStackMapRegisterMaskOffset());
155}
156
157void StackMap::SetRegisterMask(const CodeInfo& info, uint32_t mask) {
158  StoreAt(region_,
159          info.NumberOfBytesForRegisterMask(),
160          info.ComputeStackMapRegisterMaskOffset(),
161          mask);
162}
163
164size_t StackMap::ComputeStackMapSizeInternal(size_t stack_mask_size,
165                                             size_t number_of_bytes_for_inline_info,
166                                             size_t number_of_bytes_for_dex_map,
167                                             size_t number_of_bytes_for_dex_pc,
168                                             size_t number_of_bytes_for_native_pc,
169                                             size_t number_of_bytes_for_register_mask) {
170  return stack_mask_size
171      + number_of_bytes_for_inline_info
172      + number_of_bytes_for_dex_map
173      + number_of_bytes_for_dex_pc
174      + number_of_bytes_for_native_pc
175      + number_of_bytes_for_register_mask;
176}
177
178size_t StackMap::ComputeStackMapSize(size_t stack_mask_size,
179                                     size_t inline_info_size,
180                                     size_t dex_register_map_size,
181                                     size_t dex_pc_max,
182                                     size_t native_pc_max,
183                                     size_t register_mask_max) {
184  return ComputeStackMapSizeInternal(
185      stack_mask_size,
186      inline_info_size == 0
187          ? 0
188            // + 1 to also encode kNoInlineInfo.
189          :  CodeInfo::EncodingSizeInBytes(inline_info_size + dex_register_map_size + 1),
190      // + 1 to also encode kNoDexRegisterMap.
191      CodeInfo::EncodingSizeInBytes(dex_register_map_size + 1),
192      CodeInfo::EncodingSizeInBytes(dex_pc_max),
193      CodeInfo::EncodingSizeInBytes(native_pc_max),
194      CodeInfo::EncodingSizeInBytes(register_mask_max));
195}
196
197MemoryRegion StackMap::GetStackMask(const CodeInfo& info) const {
198  return region_.Subregion(info.ComputeStackMapStackMaskOffset(), info.GetStackMaskSize());
199}
200
201static void DumpRegisterMapping(std::ostream& os,
202                                size_t dex_register_num,
203                                DexRegisterLocation location,
204                                const std::string& prefix = "v",
205                                const std::string& suffix = "") {
206  os << "      " << prefix << dex_register_num << ": "
207     << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind())
208     << " (" << location.GetValue() << ")" << suffix << '\n';
209}
210
211void CodeInfo::DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const {
212  StackMap stack_map = GetStackMapAt(stack_map_num);
213  os << "    StackMap " << stack_map_num
214     << std::hex
215     << " (dex_pc=0x" << stack_map.GetDexPc(*this)
216     << ", native_pc_offset=0x" << stack_map.GetNativePcOffset(*this)
217     << ", dex_register_map_offset=0x" << stack_map.GetDexRegisterMapOffset(*this)
218     << ", inline_info_offset=0x" << stack_map.GetInlineDescriptorOffset(*this)
219     << ", register_mask=0x" << stack_map.GetRegisterMask(*this)
220     << std::dec
221     << ", stack_mask=0b";
222  MemoryRegion stack_mask = stack_map.GetStackMask(*this);
223  for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
224    os << stack_mask.LoadBit(e - i - 1);
225  }
226  os << ")\n";
227};
228
229void CodeInfo::Dump(std::ostream& os, uint16_t number_of_dex_registers) const {
230  uint32_t code_info_size = GetOverallSize();
231  size_t number_of_stack_maps = GetNumberOfStackMaps();
232  os << "  Optimized CodeInfo (size=" << code_info_size
233     << ", number_of_dex_registers=" << number_of_dex_registers
234     << ", number_of_stack_maps=" << number_of_stack_maps
235     << ", has_inline_info=" << HasInlineInfo()
236     << ", number_of_bytes_for_inline_info=" << NumberOfBytesForInlineInfo()
237     << ", number_of_bytes_for_dex_register_map=" << NumberOfBytesForDexRegisterMap()
238     << ", number_of_bytes_for_dex_pc=" << NumberOfBytesForDexPc()
239     << ", number_of_bytes_for_native_pc=" << NumberOfBytesForNativePc()
240     << ", number_of_bytes_for_register_mask=" << NumberOfBytesForRegisterMask()
241     << ")\n";
242
243  // Display the Dex register location catalog.
244  size_t number_of_location_catalog_entries = GetNumberOfDexRegisterLocationCatalogEntries();
245  size_t location_catalog_size_in_bytes = GetDexRegisterLocationCatalogSize();
246  os << "  DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
247     << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n";
248  DexRegisterLocationCatalog dex_register_location_catalog = GetDexRegisterLocationCatalog();
249  for (size_t i = 0; i < number_of_location_catalog_entries; ++i) {
250    DexRegisterLocation location = dex_register_location_catalog.GetDexRegisterLocation(i);
251    DumpRegisterMapping(os, i, location, "entry ");
252  }
253
254  // Display stack maps along with (live) Dex register maps.
255  for (size_t i = 0; i < number_of_stack_maps; ++i) {
256    StackMap stack_map = GetStackMapAt(i);
257    DumpStackMapHeader(os, i);
258    if (stack_map.HasDexRegisterMap(*this)) {
259      DexRegisterMap dex_register_map = GetDexRegisterMapOf(stack_map, number_of_dex_registers);
260      // TODO: Display the bit mask of live Dex registers.
261      for (size_t j = 0; j < number_of_dex_registers; ++j) {
262        if (dex_register_map.IsDexRegisterLive(j)) {
263          size_t location_catalog_entry_index = dex_register_map.GetLocationCatalogEntryIndex(
264              j, number_of_dex_registers, number_of_location_catalog_entries);
265          DexRegisterLocation location =
266              dex_register_map.GetDexRegisterLocation(j, number_of_dex_registers, *this);
267          DumpRegisterMapping(
268              os, j, location, "v",
269              "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
270        }
271      }
272    }
273  }
274  // TODO: Dump the stack map's inline information.
275}
276
277}  // namespace art
278