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 27 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 39 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. 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 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 105 uint32_t StackMap::GetDexPc(const CodeInfo& info) const { 106 return LoadAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset()); 107 } 108 109 void StackMap::SetDexPc(const CodeInfo& info, uint32_t dex_pc) { 110 StoreAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset(), dex_pc); 111 } 112 113 uint32_t StackMap::GetNativePcOffset(const CodeInfo& info) const { 114 return LoadAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset()); 115 } 116 117 void StackMap::SetNativePcOffset(const CodeInfo& info, uint32_t native_pc_offset) { 118 StoreAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset(), native_pc_offset); 119 } 120 121 uint32_t StackMap::GetDexRegisterMapOffset(const CodeInfo& info) const { 122 return LoadAt(region_, 123 info.NumberOfBytesForDexRegisterMap(), 124 info.ComputeStackMapDexRegisterMapOffset(), 125 /* check_max */ true); 126 } 127 128 void StackMap::SetDexRegisterMapOffset(const CodeInfo& info, uint32_t offset) { 129 StoreAt(region_, 130 info.NumberOfBytesForDexRegisterMap(), 131 info.ComputeStackMapDexRegisterMapOffset(), 132 offset); 133 } 134 135 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 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 151 uint32_t StackMap::GetRegisterMask(const CodeInfo& info) const { 152 return LoadAt(region_, 153 info.NumberOfBytesForRegisterMask(), 154 info.ComputeStackMapRegisterMaskOffset()); 155 } 156 157 void StackMap::SetRegisterMask(const CodeInfo& info, uint32_t mask) { 158 StoreAt(region_, 159 info.NumberOfBytesForRegisterMask(), 160 info.ComputeStackMapRegisterMaskOffset(), 161 mask); 162 } 163 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 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 197 MemoryRegion StackMap::GetStackMask(const CodeInfo& info) const { 198 return region_.Subregion(info.ComputeStackMapStackMaskOffset(), info.GetStackMaskSize()); 199 } 200 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 211 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 229 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