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 namespace art {
22
23 constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex;
24 constexpr uint32_t StackMap::kNoDexRegisterMap;
25 constexpr uint32_t StackMap::kNoInlineInfo;
26
GetLocationInternalKind(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info) const27 DexRegisterLocation::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
GetDexRegisterLocation(uint16_t dex_register_number,uint16_t number_of_dex_registers,const CodeInfo & code_info) const39 DexRegisterLocation 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.
LoadAt(MemoryRegion region,size_t number_of_bytes,size_t offset,bool check_max=false)53 static 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
StoreAt(MemoryRegion region,size_t number_of_bytes,size_t offset,uint32_t value)89 static 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
GetDexPc(const CodeInfo & info) const105 uint32_t StackMap::GetDexPc(const CodeInfo& info) const {
106 return LoadAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset());
107 }
108
SetDexPc(const CodeInfo & info,uint32_t dex_pc)109 void StackMap::SetDexPc(const CodeInfo& info, uint32_t dex_pc) {
110 StoreAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset(), dex_pc);
111 }
112
GetNativePcOffset(const CodeInfo & info) const113 uint32_t StackMap::GetNativePcOffset(const CodeInfo& info) const {
114 return LoadAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset());
115 }
116
SetNativePcOffset(const CodeInfo & info,uint32_t native_pc_offset)117 void StackMap::SetNativePcOffset(const CodeInfo& info, uint32_t native_pc_offset) {
118 StoreAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset(), native_pc_offset);
119 }
120
GetDexRegisterMapOffset(const CodeInfo & info) const121 uint32_t StackMap::GetDexRegisterMapOffset(const CodeInfo& info) const {
122 return LoadAt(region_,
123 info.NumberOfBytesForDexRegisterMap(),
124 info.ComputeStackMapDexRegisterMapOffset(),
125 /* check_max */ true);
126 }
127
SetDexRegisterMapOffset(const CodeInfo & info,uint32_t offset)128 void StackMap::SetDexRegisterMapOffset(const CodeInfo& info, uint32_t offset) {
129 StoreAt(region_,
130 info.NumberOfBytesForDexRegisterMap(),
131 info.ComputeStackMapDexRegisterMapOffset(),
132 offset);
133 }
134
GetInlineDescriptorOffset(const CodeInfo & info) const135 uint32_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
SetInlineDescriptorOffset(const CodeInfo & info,uint32_t offset)143 void 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
GetRegisterMask(const CodeInfo & info) const151 uint32_t StackMap::GetRegisterMask(const CodeInfo& info) const {
152 return LoadAt(region_,
153 info.NumberOfBytesForRegisterMask(),
154 info.ComputeStackMapRegisterMaskOffset());
155 }
156
SetRegisterMask(const CodeInfo & info,uint32_t mask)157 void StackMap::SetRegisterMask(const CodeInfo& info, uint32_t mask) {
158 StoreAt(region_,
159 info.NumberOfBytesForRegisterMask(),
160 info.ComputeStackMapRegisterMaskOffset(),
161 mask);
162 }
163
ComputeStackMapSizeInternal(size_t stack_mask_size,size_t number_of_bytes_for_inline_info,size_t number_of_bytes_for_dex_map,size_t number_of_bytes_for_dex_pc,size_t number_of_bytes_for_native_pc,size_t number_of_bytes_for_register_mask)164 size_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
ComputeStackMapSize(size_t stack_mask_size,size_t inline_info_size,size_t dex_register_map_size,size_t dex_pc_max,size_t native_pc_max,size_t register_mask_max)178 size_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
GetStackMask(const CodeInfo & info) const197 MemoryRegion StackMap::GetStackMask(const CodeInfo& info) const {
198 return region_.Subregion(info.ComputeStackMapStackMaskOffset(), info.GetStackMaskSize());
199 }
200
DumpRegisterMapping(std::ostream & os,size_t dex_register_num,DexRegisterLocation location,const std::string & prefix="v",const std::string & suffix="")201 static 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
DumpStackMapHeader(std::ostream & os,size_t stack_map_num) const211 void 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
Dump(std::ostream & os,uint16_t number_of_dex_registers) const229 void 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