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