/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "stack_map.h" #include namespace art { constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex; constexpr uint32_t StackMap::kNoDexRegisterMap; constexpr uint32_t StackMap::kNoInlineInfo; DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind(uint16_t dex_register_number, uint16_t number_of_dex_registers, const CodeInfo& code_info) const { DexRegisterLocationCatalog dex_register_location_catalog = code_info.GetDexRegisterLocationCatalog(); size_t location_catalog_entry_index = GetLocationCatalogEntryIndex( dex_register_number, number_of_dex_registers, code_info.GetNumberOfDexRegisterLocationCatalogEntries()); return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index); } DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number, uint16_t number_of_dex_registers, const CodeInfo& code_info) const { DexRegisterLocationCatalog dex_register_location_catalog = code_info.GetDexRegisterLocationCatalog(); size_t location_catalog_entry_index = GetLocationCatalogEntryIndex( dex_register_number, number_of_dex_registers, code_info.GetNumberOfDexRegisterLocationCatalogEntries()); return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index); } // Loads `number_of_bytes` at the given `offset` and assemble a uint32_t. If `check_max` is true, // this method converts a maximum value of size `number_of_bytes` into a uint32_t 0xFFFFFFFF. static uint32_t LoadAt(MemoryRegion region, size_t number_of_bytes, size_t offset, bool check_max = false) { if (number_of_bytes == 0u) { DCHECK(!check_max); return 0; } else if (number_of_bytes == 1u) { uint8_t value = region.LoadUnaligned(offset); if (check_max && value == 0xFF) { return -1; } else { return value; } } else if (number_of_bytes == 2u) { uint16_t value = region.LoadUnaligned(offset); if (check_max && value == 0xFFFF) { return -1; } else { return value; } } else if (number_of_bytes == 3u) { uint16_t low = region.LoadUnaligned(offset); uint16_t high = region.LoadUnaligned(offset + sizeof(uint16_t)); uint32_t value = (high << 16) + low; if (check_max && value == 0xFFFFFF) { return -1; } else { return value; } } else { DCHECK_EQ(number_of_bytes, 4u); return region.LoadUnaligned(offset); } } static void StoreAt(MemoryRegion region, size_t number_of_bytes, size_t offset, uint32_t value) { if (number_of_bytes == 0u) { DCHECK_EQ(value, 0u); } else if (number_of_bytes == 1u) { region.StoreUnaligned(offset, value); } else if (number_of_bytes == 2u) { region.StoreUnaligned(offset, value); } else if (number_of_bytes == 3u) { region.StoreUnaligned(offset, Low16Bits(value)); region.StoreUnaligned(offset + sizeof(uint16_t), High16Bits(value)); } else { region.StoreUnaligned(offset, value); DCHECK_EQ(number_of_bytes, 4u); } } uint32_t StackMap::GetDexPc(const CodeInfo& info) const { return LoadAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset()); } void StackMap::SetDexPc(const CodeInfo& info, uint32_t dex_pc) { StoreAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset(), dex_pc); } uint32_t StackMap::GetNativePcOffset(const CodeInfo& info) const { return LoadAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset()); } void StackMap::SetNativePcOffset(const CodeInfo& info, uint32_t native_pc_offset) { StoreAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset(), native_pc_offset); } uint32_t StackMap::GetDexRegisterMapOffset(const CodeInfo& info) const { return LoadAt(region_, info.NumberOfBytesForDexRegisterMap(), info.ComputeStackMapDexRegisterMapOffset(), /* check_max */ true); } void StackMap::SetDexRegisterMapOffset(const CodeInfo& info, uint32_t offset) { StoreAt(region_, info.NumberOfBytesForDexRegisterMap(), info.ComputeStackMapDexRegisterMapOffset(), offset); } uint32_t StackMap::GetInlineDescriptorOffset(const CodeInfo& info) const { if (!info.HasInlineInfo()) return kNoInlineInfo; return LoadAt(region_, info.NumberOfBytesForInlineInfo(), info.ComputeStackMapInlineInfoOffset(), /* check_max */ true); } void StackMap::SetInlineDescriptorOffset(const CodeInfo& info, uint32_t offset) { DCHECK(info.HasInlineInfo()); StoreAt(region_, info.NumberOfBytesForInlineInfo(), info.ComputeStackMapInlineInfoOffset(), offset); } uint32_t StackMap::GetRegisterMask(const CodeInfo& info) const { return LoadAt(region_, info.NumberOfBytesForRegisterMask(), info.ComputeStackMapRegisterMaskOffset()); } void StackMap::SetRegisterMask(const CodeInfo& info, uint32_t mask) { StoreAt(region_, info.NumberOfBytesForRegisterMask(), info.ComputeStackMapRegisterMaskOffset(), mask); } size_t StackMap::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) { return stack_mask_size + number_of_bytes_for_inline_info + number_of_bytes_for_dex_map + number_of_bytes_for_dex_pc + number_of_bytes_for_native_pc + number_of_bytes_for_register_mask; } size_t StackMap::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) { return ComputeStackMapSizeInternal( stack_mask_size, inline_info_size == 0 ? 0 // + 1 to also encode kNoInlineInfo. : CodeInfo::EncodingSizeInBytes(inline_info_size + dex_register_map_size + 1), // + 1 to also encode kNoDexRegisterMap. CodeInfo::EncodingSizeInBytes(dex_register_map_size + 1), CodeInfo::EncodingSizeInBytes(dex_pc_max), CodeInfo::EncodingSizeInBytes(native_pc_max), CodeInfo::EncodingSizeInBytes(register_mask_max)); } MemoryRegion StackMap::GetStackMask(const CodeInfo& info) const { return region_.Subregion(info.ComputeStackMapStackMaskOffset(), info.GetStackMaskSize()); } static void DumpRegisterMapping(std::ostream& os, size_t dex_register_num, DexRegisterLocation location, const std::string& prefix = "v", const std::string& suffix = "") { os << " " << prefix << dex_register_num << ": " << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind()) << " (" << location.GetValue() << ")" << suffix << '\n'; } void CodeInfo::DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const { StackMap stack_map = GetStackMapAt(stack_map_num); os << " StackMap " << stack_map_num << std::hex << " (dex_pc=0x" << stack_map.GetDexPc(*this) << ", native_pc_offset=0x" << stack_map.GetNativePcOffset(*this) << ", dex_register_map_offset=0x" << stack_map.GetDexRegisterMapOffset(*this) << ", inline_info_offset=0x" << stack_map.GetInlineDescriptorOffset(*this) << ", register_mask=0x" << stack_map.GetRegisterMask(*this) << std::dec << ", stack_mask=0b"; MemoryRegion stack_mask = stack_map.GetStackMask(*this); for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) { os << stack_mask.LoadBit(e - i - 1); } os << ")\n"; }; void CodeInfo::Dump(std::ostream& os, uint16_t number_of_dex_registers) const { uint32_t code_info_size = GetOverallSize(); size_t number_of_stack_maps = GetNumberOfStackMaps(); os << " Optimized CodeInfo (size=" << code_info_size << ", number_of_dex_registers=" << number_of_dex_registers << ", number_of_stack_maps=" << number_of_stack_maps << ", has_inline_info=" << HasInlineInfo() << ", number_of_bytes_for_inline_info=" << NumberOfBytesForInlineInfo() << ", number_of_bytes_for_dex_register_map=" << NumberOfBytesForDexRegisterMap() << ", number_of_bytes_for_dex_pc=" << NumberOfBytesForDexPc() << ", number_of_bytes_for_native_pc=" << NumberOfBytesForNativePc() << ", number_of_bytes_for_register_mask=" << NumberOfBytesForRegisterMask() << ")\n"; // Display the Dex register location catalog. size_t number_of_location_catalog_entries = GetNumberOfDexRegisterLocationCatalogEntries(); size_t location_catalog_size_in_bytes = GetDexRegisterLocationCatalogSize(); os << " DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n"; DexRegisterLocationCatalog dex_register_location_catalog = GetDexRegisterLocationCatalog(); for (size_t i = 0; i < number_of_location_catalog_entries; ++i) { DexRegisterLocation location = dex_register_location_catalog.GetDexRegisterLocation(i); DumpRegisterMapping(os, i, location, "entry "); } // Display stack maps along with (live) Dex register maps. for (size_t i = 0; i < number_of_stack_maps; ++i) { StackMap stack_map = GetStackMapAt(i); DumpStackMapHeader(os, i); if (stack_map.HasDexRegisterMap(*this)) { DexRegisterMap dex_register_map = GetDexRegisterMapOf(stack_map, number_of_dex_registers); // TODO: Display the bit mask of live Dex registers. for (size_t j = 0; j < number_of_dex_registers; ++j) { if (dex_register_map.IsDexRegisterLive(j)) { size_t location_catalog_entry_index = dex_register_map.GetLocationCatalogEntryIndex( j, number_of_dex_registers, number_of_location_catalog_entries); DexRegisterLocation location = dex_register_map.GetDexRegisterLocation(j, number_of_dex_registers, *this); DumpRegisterMapping( os, j, location, "v", "\t[entry " + std::to_string(static_cast(location_catalog_entry_index)) + "]"); } } } } // TODO: Dump the stack map's inline information. } } // namespace art