/* * Copyright (C) 2011 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 "oat_quick_method_header.h" #include "art_method.h" #include "mapping_table.h" #include "scoped_thread_state_change.h" #include "thread.h" namespace art { OatQuickMethodHeader::OatQuickMethodHeader( uint32_t mapping_table_offset, uint32_t vmap_table_offset, uint32_t gc_map_offset, uint32_t frame_size_in_bytes, uint32_t core_spill_mask, uint32_t fp_spill_mask, uint32_t code_size) : mapping_table_offset_(mapping_table_offset), vmap_table_offset_(vmap_table_offset), gc_map_offset_(gc_map_offset), frame_info_(frame_size_in_bytes, core_spill_mask, fp_spill_mask), code_size_(code_size) {} OatQuickMethodHeader::~OatQuickMethodHeader() {} uint32_t OatQuickMethodHeader::ToDexPc(ArtMethod* method, const uintptr_t pc, bool abort_on_failure) const { const void* entry_point = GetEntryPoint(); uint32_t sought_offset = pc - reinterpret_cast(entry_point); if (IsOptimized()) { CodeInfo code_info = GetOptimizedCodeInfo(); StackMapEncoding encoding = code_info.ExtractEncoding(); StackMap stack_map = code_info.GetStackMapForNativePcOffset(sought_offset, encoding); if (stack_map.IsValid()) { return stack_map.GetDexPc(encoding); } } else { MappingTable table(GetMappingTable()); // NOTE: Special methods (see Mir2Lir::GenSpecialCase()) have an empty mapping // but they have no suspend checks and, consequently, we never call ToDexPc() for them. if (table.TotalSize() == 0) { DCHECK(method->IsNative()); return DexFile::kDexNoIndex; } // Assume the caller wants a pc-to-dex mapping so check here first. typedef MappingTable::PcToDexIterator It; for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) { if (cur.NativePcOffset() == sought_offset) { return cur.DexPc(); } } // Now check dex-to-pc mappings. typedef MappingTable::DexToPcIterator It2; for (It2 cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) { if (cur.NativePcOffset() == sought_offset) { return cur.DexPc(); } } } if (abort_on_failure) { ScopedObjectAccess soa(Thread::Current()); LOG(FATAL) << "Failed to find Dex offset for PC offset " << reinterpret_cast(sought_offset) << "(PC " << reinterpret_cast(pc) << ", entry_point=" << entry_point << " current entry_point=" << method->GetEntryPointFromQuickCompiledCode() << ") in " << PrettyMethod(method); } return DexFile::kDexNoIndex; } uintptr_t OatQuickMethodHeader::ToNativeQuickPc(ArtMethod* method, const uint32_t dex_pc, bool is_for_catch_handler, bool abort_on_failure) const { const void* entry_point = GetEntryPoint(); if (IsOptimized()) { // Optimized code does not have a mapping table. Search for the dex-to-pc // mapping in stack maps. CodeInfo code_info = GetOptimizedCodeInfo(); StackMapEncoding encoding = code_info.ExtractEncoding(); // All stack maps are stored in the same CodeItem section, safepoint stack // maps first, then catch stack maps. We use `is_for_catch_handler` to select // the order of iteration. StackMap stack_map = LIKELY(is_for_catch_handler) ? code_info.GetCatchStackMapForDexPc(dex_pc, encoding) : code_info.GetStackMapForDexPc(dex_pc, encoding); if (stack_map.IsValid()) { return reinterpret_cast(entry_point) + stack_map.GetNativePcOffset(encoding); } } else { MappingTable table(GetMappingTable()); if (table.TotalSize() == 0) { DCHECK_EQ(dex_pc, 0U); return 0; // Special no mapping/pc == 0 case } // Assume the caller wants a dex-to-pc mapping so check here first. typedef MappingTable::DexToPcIterator It; for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) { if (cur.DexPc() == dex_pc) { return reinterpret_cast(entry_point) + cur.NativePcOffset(); } } // Now check pc-to-dex mappings. typedef MappingTable::PcToDexIterator It2; for (It2 cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) { if (cur.DexPc() == dex_pc) { return reinterpret_cast(entry_point) + cur.NativePcOffset(); } } } if (abort_on_failure) { ScopedObjectAccess soa(Thread::Current()); LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc << " in " << PrettyMethod(method); } return UINTPTR_MAX; } } // namespace art