diff options
author | 2015-10-16 17:13:34 +0100 | |
---|---|---|
committer | 2015-10-20 11:52:11 +0100 | |
commit | 524e7ea8cd17bad17bd9f3e0ccbb19ad0d4d9c02 (patch) | |
tree | ad07cc96f633bdae839ff2f1553d84b9c864a930 | |
parent | b697c447eb61c2e14315166ec3b0d16375ae403c (diff) |
Remove ArtCode.
- Instead use OatQuickMethodHeader.
- Various cleanups now that we don't have all those
ArtMethod -> ArtCode -> OatQuickMethodHeader indirections.
As a consequence of this cleanup, exception handling got a bit
faster.
ParserCombinators benchmark (exception intensive) on x64: (lower is better)
Before:
ParserCombinators(RunTime): 1062500.0 us.
After:
ParserCombinators(RunTime): 833000.0 us.
Change-Id: Idac917b6f1b0dc254ad68fb3781cd61bccadb0f3
56 files changed, 673 insertions, 719 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index 1727657d58..58a2f96cd9 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -32,6 +32,7 @@ #include "mirror/class-inl.h" #include "mirror/dex_cache.h" #include "mirror/object-inl.h" +#include "oat_quick_method_header.h" #include "scoped_thread_state_change.h" #include "thread-inl.h" #include "utils.h" diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc index 64becb9b85..e5d3841b14 100644 --- a/compiler/dex/quick/x86/assemble_x86.cc +++ b/compiler/dex/quick/x86/assemble_x86.cc @@ -21,6 +21,7 @@ #include "dex/compiler_ir.h" #include "dex/quick/mir_to_lir.h" #include "oat.h" +#include "oat_quick_method_header.h" #include "utils.h" #include "x86_lir.h" diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index 25fb8869b6..75f3fef599 100755 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -31,6 +31,7 @@ #include "mirror/array-inl.h" #include "mirror/string.h" #include "oat.h" +#include "oat_quick_method_header.h" #include "x86_lir.h" namespace art { diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index a45df95d1d..fcbd483f7a 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -30,6 +30,7 @@ #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "oat_file-inl.h" +#include "oat_quick_method_header.h" #include "object_lock.h" #include "thread_list.h" #include "verifier/method_verifier-inl.h" diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc index ceace824ea..cb9ea38b1c 100644 --- a/compiler/linker/arm/relative_patcher_arm_base.cc +++ b/compiler/linker/arm/relative_patcher_arm_base.cc @@ -18,6 +18,7 @@ #include "compiled_method.h" #include "oat.h" +#include "oat_quick_method_header.h" #include "output_stream.h" namespace art { diff --git a/compiler/linker/arm/relative_patcher_thumb2_test.cc b/compiler/linker/arm/relative_patcher_thumb2_test.cc index 13f67e6fd4..551531314a 100644 --- a/compiler/linker/arm/relative_patcher_thumb2_test.cc +++ b/compiler/linker/arm/relative_patcher_thumb2_test.cc @@ -16,6 +16,7 @@ #include "linker/relative_patcher_test.h" #include "linker/arm/relative_patcher_thumb2.h" +#include "oat_quick_method_header.h" namespace art { namespace linker { diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc index 6b9c530d7a..6f234a8367 100644 --- a/compiler/linker/arm64/relative_patcher_arm64.cc +++ b/compiler/linker/arm64/relative_patcher_arm64.cc @@ -22,6 +22,7 @@ #include "driver/compiler_driver.h" #include "utils/arm64/assembler_arm64.h" #include "oat.h" +#include "oat_quick_method_header.h" #include "output_stream.h" namespace art { diff --git a/compiler/linker/arm64/relative_patcher_arm64_test.cc b/compiler/linker/arm64/relative_patcher_arm64_test.cc index b3af4c6a05..857d5842b5 100644 --- a/compiler/linker/arm64/relative_patcher_arm64_test.cc +++ b/compiler/linker/arm64/relative_patcher_arm64_test.cc @@ -16,6 +16,7 @@ #include "linker/relative_patcher_test.h" #include "linker/arm64/relative_patcher_arm64.h" +#include "oat_quick_method_header.h" namespace art { namespace linker { diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h index 31d1bced9c..e357662388 100644 --- a/compiler/linker/relative_patcher_test.h +++ b/compiler/linker/relative_patcher_test.h @@ -30,6 +30,7 @@ #include "linker/relative_patcher.h" #include "method_reference.h" #include "oat.h" +#include "oat_quick_method_header.h" #include "utils/array_ref.h" #include "vector_output_stream.h" diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index a78a5b3644..640698b0e9 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -39,6 +39,7 @@ #include "mirror/class_loader.h" #include "mirror/dex_cache-inl.h" #include "mirror/object-inl.h" +#include "oat_quick_method_header.h" #include "os.h" #include "output_stream.h" #include "safe_map.h" diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index dbf536575a..ea61b43627 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -26,7 +26,6 @@ #include <vector> #include "arch/instruction_set_features.h" -#include "art_code.h" #include "art_field-inl.h" #include "art_method-inl.h" #include "base/unix_file/fd_file.h" @@ -1967,10 +1966,13 @@ class ImageDumper { InstructionSetPointerSize(state->oat_dumper_->GetOatInstructionSet()); const void* quick_oat_code_begin = state->GetQuickOatCodeBegin(method); const void* quick_oat_code_end = state->GetQuickOatCodeEnd(method); - ArtCode art_code(method); + OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>( + reinterpret_cast<uintptr_t>(quick_oat_code_begin) - sizeof(OatQuickMethodHeader)); if (method->IsNative()) { - DCHECK(art_code.GetNativeGcMap(image_pointer_size) == nullptr) << PrettyMethod(method); - DCHECK(art_code.GetMappingTable(image_pointer_size) == nullptr) << PrettyMethod(method); + if (!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(quick_oat_code_begin)) { + DCHECK(method_header->GetNativeGcMap() == nullptr) << PrettyMethod(method); + DCHECK(method_header->GetMappingTable() == nullptr) << PrettyMethod(method); + } bool first_occurrence; uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method); state->ComputeOatSize(quick_oat_code_begin, &first_occurrence); @@ -1984,8 +1986,6 @@ class ImageDumper { } else if (method->IsAbstract() || method->IsCalleeSaveMethod() || method->IsResolutionMethod() || method->IsImtConflictMethod() || method->IsImtUnimplementedMethod() || method->IsClassInitializer()) { - DCHECK(art_code.GetNativeGcMap(image_pointer_size) == nullptr) << PrettyMethod(method); - DCHECK(art_code.GetMappingTable(image_pointer_size) == nullptr) << PrettyMethod(method); } else { const DexFile::CodeItem* code_item = method->GetCodeItem(); size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2; @@ -1993,22 +1993,22 @@ class ImageDumper { bool first_occurrence; size_t gc_map_bytes = state->ComputeOatSize( - art_code.GetNativeGcMap(image_pointer_size), &first_occurrence); + method_header->GetNativeGcMap(), &first_occurrence); if (first_occurrence) { state->stats_.gc_map_bytes += gc_map_bytes; } size_t pc_mapping_table_bytes = state->ComputeOatSize( - art_code.GetMappingTable(image_pointer_size), &first_occurrence); + method_header->GetMappingTable(), &first_occurrence); if (first_occurrence) { state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes; } size_t vmap_table_bytes = 0u; - if (!art_code.IsOptimized(image_pointer_size)) { + if (!method_header->IsOptimized()) { // Method compiled with the optimizing compiler have no vmap table. vmap_table_bytes = state->ComputeOatSize( - art_code.GetVmapTable(image_pointer_size), &first_occurrence); + method_header->GetVmapTable(), &first_occurrence); if (first_occurrence) { state->stats_.vmap_table_bytes += vmap_table_bytes; } diff --git a/runtime/Android.mk b/runtime/Android.mk index 8fe3fa2df1..9236ffb032 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -19,7 +19,6 @@ LOCAL_PATH := $(call my-dir) include art/build/Android.common_build.mk LIBART_COMMON_SRC_FILES := \ - art_code.cc \ art_field.cc \ art_method.cc \ atomic.cc.arm \ @@ -156,6 +155,7 @@ LIBART_COMMON_SRC_FILES := \ oat_file.cc \ oat_file_assistant.cc \ oat_file_manager.cc \ + oat_quick_method_header.cc \ object_lock.cc \ offsets.cc \ os_linux.cc \ diff --git a/runtime/arch/arch_test.cc b/runtime/arch/arch_test.cc index e676a09733..d6ba304bd1 100644 --- a/runtime/arch/arch_test.cc +++ b/runtime/arch/arch_test.cc @@ -39,7 +39,7 @@ class ArchTest : public CommonRuntimeTest { runtime->SetInstructionSet(isa); ArtMethod* save_method = runtime->CreateCalleeSaveMethod(); runtime->SetCalleeSaveMethod(save_method, type); - QuickMethodFrameInfo frame_info = ArtCode(save_method).GetQuickFrameInfo(); + QuickMethodFrameInfo frame_info = runtime->GetRuntimeMethodFrameInfo(save_method); EXPECT_EQ(frame_info.FrameSizeInBytes(), save_size) << "Expected and real size differs for " << type << " core spills=" << std::hex << frame_info.CoreSpillMask() << " fp spills=" << frame_info.FpSpillMask() << std::dec; diff --git a/runtime/arch/arm/context_arm.cc b/runtime/arch/arm/context_arm.cc index d5c7846951..9cbec1e5bc 100644 --- a/runtime/arch/arm/context_arm.cc +++ b/runtime/arch/arm/context_arm.cc @@ -16,9 +16,9 @@ #include "context_arm.h" -#include "art_method-inl.h" #include "base/bit_utils.h" #include "quick/quick_method_frame_info.h" +#include "thread-inl.h" namespace art { namespace arm { @@ -37,23 +37,21 @@ void ArmContext::Reset() { arg0_ = 0; } -void ArmContext::FillCalleeSaves(const StackVisitor& fr) { - ArtCode art_code = fr.GetCurrentCode(); - const QuickMethodFrameInfo frame_info = art_code.GetQuickFrameInfo(); +void ArmContext::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) { int spill_pos = 0; // Core registers come first, from the highest down to the lowest. uint32_t core_regs = frame_info.CoreSpillMask(); DCHECK_EQ(0u, core_regs & (static_cast<uint32_t>(-1) << kNumberOfCoreRegisters)); for (uint32_t core_reg : HighToLowBits(core_regs)) { - gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()); ++spill_pos; } DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask())); // FP registers come second, from the highest down to the lowest. for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) { - fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + fprs_[fp_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()); ++spill_pos; } DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask())); diff --git a/runtime/arch/arm/context_arm.h b/runtime/arch/arm/context_arm.h index ea31055e9d..2623ee9315 100644 --- a/runtime/arch/arm/context_arm.h +++ b/runtime/arch/arm/context_arm.h @@ -35,7 +35,7 @@ class ArmContext : public Context { void Reset() OVERRIDE; - void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_); + void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) OVERRIDE; void SetSP(uintptr_t new_sp) OVERRIDE { SetGPR(SP, new_sp); diff --git a/runtime/arch/arm64/context_arm64.cc b/runtime/arch/arm64/context_arm64.cc index cdc03fe16f..d5d1ec7f07 100644 --- a/runtime/arch/arm64/context_arm64.cc +++ b/runtime/arch/arm64/context_arm64.cc @@ -18,9 +18,9 @@ #include "context_arm64.h" -#include "art_method-inl.h" #include "base/bit_utils.h" #include "quick/quick_method_frame_info.h" +#include "thread-inl.h" namespace art { namespace arm64 { @@ -39,21 +39,19 @@ void Arm64Context::Reset() { arg0_ = 0; } -void Arm64Context::FillCalleeSaves(const StackVisitor& fr) { - ArtCode code = fr.GetCurrentCode(); - const QuickMethodFrameInfo frame_info = code.GetQuickFrameInfo(); +void Arm64Context::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) { int spill_pos = 0; // Core registers come first, from the highest down to the lowest. for (uint32_t core_reg : HighToLowBits(frame_info.CoreSpillMask())) { - gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()); ++spill_pos; } DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask())); // FP registers come second, from the highest down to the lowest. for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) { - fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + fprs_[fp_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()); ++spill_pos; } DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask())); diff --git a/runtime/arch/arm64/context_arm64.h b/runtime/arch/arm64/context_arm64.h index 11314e08ed..105e78461d 100644 --- a/runtime/arch/arm64/context_arm64.h +++ b/runtime/arch/arm64/context_arm64.h @@ -35,7 +35,7 @@ class Arm64Context : public Context { void Reset() OVERRIDE; - void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_); + void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) OVERRIDE; void SetSP(uintptr_t new_sp) OVERRIDE { SetGPR(SP, new_sp); diff --git a/runtime/arch/context.h b/runtime/arch/context.h index 9af7c04f5c..a50064851b 100644 --- a/runtime/arch/context.h +++ b/runtime/arch/context.h @@ -25,7 +25,7 @@ namespace art { -class StackVisitor; +class QuickMethodFrameInfo; // Representation of a thread's context on the executing machine, used to implement long jumps in // the quick stack frame layout. @@ -39,10 +39,18 @@ class Context { // Re-initializes the registers for context re-use. virtual void Reset() = 0; + static uintptr_t* CalleeSaveAddress(uint8_t* frame, int num, size_t frame_size) { + // Callee saves are held at the top of the frame + uint8_t* save_addr = frame + frame_size - ((num + 1) * sizeof(void*)); +#if defined(__i386__) || defined(__x86_64__) + save_addr -= sizeof(void*); // account for return address +#endif + return reinterpret_cast<uintptr_t*>(save_addr); + } + // Reads values from callee saves in the given frame. The frame also holds // the method that holds the layout. - virtual void FillCalleeSaves(const StackVisitor& fr) - SHARED_REQUIRES(Locks::mutator_lock_) = 0; + virtual void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) = 0; // Sets the stack pointer value. virtual void SetSP(uintptr_t new_sp) = 0; diff --git a/runtime/arch/mips/context_mips.cc b/runtime/arch/mips/context_mips.cc index dba62d9200..4dedb3339e 100644 --- a/runtime/arch/mips/context_mips.cc +++ b/runtime/arch/mips/context_mips.cc @@ -16,7 +16,6 @@ #include "context_mips.h" -#include "art_method-inl.h" #include "base/bit_utils.h" #include "quick/quick_method_frame_info.h" @@ -37,21 +36,19 @@ void MipsContext::Reset() { arg0_ = 0; } -void MipsContext::FillCalleeSaves(const StackVisitor& fr) { - ArtCode code = fr.GetCurrentCode(); - const QuickMethodFrameInfo frame_info = code.GetQuickFrameInfo(); +void MipsContext::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) { int spill_pos = 0; // Core registers come first, from the highest down to the lowest. for (uint32_t core_reg : HighToLowBits(frame_info.CoreSpillMask())) { - gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()); ++spill_pos; } DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask())); // FP registers come second, from the highest down to the lowest. for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) { - fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + fprs_[fp_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()); ++spill_pos; } DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask())); diff --git a/runtime/arch/mips/context_mips.h b/runtime/arch/mips/context_mips.h index 0affe5397a..f1e2905592 100644 --- a/runtime/arch/mips/context_mips.h +++ b/runtime/arch/mips/context_mips.h @@ -34,7 +34,7 @@ class MipsContext : public Context { void Reset() OVERRIDE; - void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_); + void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) OVERRIDE; void SetSP(uintptr_t new_sp) OVERRIDE { SetGPR(SP, new_sp); diff --git a/runtime/arch/mips64/context_mips64.cc b/runtime/arch/mips64/context_mips64.cc index d808c9e0dc..bd1ac3b0a7 100644 --- a/runtime/arch/mips64/context_mips64.cc +++ b/runtime/arch/mips64/context_mips64.cc @@ -16,7 +16,6 @@ #include "context_mips64.h" -#include "art_method-inl.h" #include "base/bit_utils.h" #include "quick/quick_method_frame_info.h" @@ -37,21 +36,19 @@ void Mips64Context::Reset() { arg0_ = 0; } -void Mips64Context::FillCalleeSaves(const StackVisitor& fr) { - ArtCode code = fr.GetCurrentCode(); - const QuickMethodFrameInfo frame_info = code.GetQuickFrameInfo(); +void Mips64Context::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) { int spill_pos = 0; // Core registers come first, from the highest down to the lowest. for (uint32_t core_reg : HighToLowBits(frame_info.CoreSpillMask())) { - gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()); ++spill_pos; } DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask())); // FP registers come second, from the highest down to the lowest. for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) { - fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + fprs_[fp_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()); ++spill_pos; } DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask())); diff --git a/runtime/arch/mips64/context_mips64.h b/runtime/arch/mips64/context_mips64.h index 84b1c9bad4..89fbf8ffc3 100644 --- a/runtime/arch/mips64/context_mips64.h +++ b/runtime/arch/mips64/context_mips64.h @@ -34,7 +34,7 @@ class Mips64Context : public Context { void Reset() OVERRIDE; - void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_); + void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) OVERRIDE; void SetSP(uintptr_t new_sp) OVERRIDE { SetGPR(SP, new_sp); diff --git a/runtime/arch/x86/context_x86.cc b/runtime/arch/x86/context_x86.cc index 0d88dd0dc5..077d2db870 100644 --- a/runtime/arch/x86/context_x86.cc +++ b/runtime/arch/x86/context_x86.cc @@ -16,10 +16,8 @@ #include "context_x86.h" -#include "art_code.h" #include "base/bit_utils.h" #include "quick/quick_method_frame_info.h" -#include "stack.h" namespace art { namespace x86 { @@ -37,9 +35,7 @@ void X86Context::Reset() { arg0_ = 0; } -void X86Context::FillCalleeSaves(const StackVisitor& fr) { - ArtCode code = fr.GetCurrentCode(); - const QuickMethodFrameInfo frame_info = code.GetQuickFrameInfo(); +void X86Context::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) { int spill_pos = 0; // Core registers come first, from the highest down to the lowest. @@ -47,7 +43,7 @@ void X86Context::FillCalleeSaves(const StackVisitor& fr) { frame_info.CoreSpillMask() & ~(static_cast<uint32_t>(-1) << kNumberOfCpuRegisters); DCHECK_EQ(1, POPCOUNT(frame_info.CoreSpillMask() & ~core_regs)); // Return address spill. for (uint32_t core_reg : HighToLowBits(core_regs)) { - gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()); ++spill_pos; } DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) - 1); @@ -58,9 +54,9 @@ void X86Context::FillCalleeSaves(const StackVisitor& fr) { for (uint32_t fp_reg : HighToLowBits(fp_regs)) { // Two void* per XMM register. fprs_[2 * fp_reg] = reinterpret_cast<uint32_t*>( - fr.CalleeSaveAddress(spill_pos + 1, frame_info.FrameSizeInBytes())); + CalleeSaveAddress(frame, spill_pos + 1, frame_info.FrameSizeInBytes())); fprs_[2 * fp_reg + 1] = reinterpret_cast<uint32_t*>( - fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes())); + CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes())); spill_pos += 2; } DCHECK_EQ(spill_pos, diff --git a/runtime/arch/x86/context_x86.h b/runtime/arch/x86/context_x86.h index 59beb12ffa..f482d9ffcb 100644 --- a/runtime/arch/x86/context_x86.h +++ b/runtime/arch/x86/context_x86.h @@ -34,7 +34,7 @@ class X86Context : public Context { void Reset() OVERRIDE; - void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_); + void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) OVERRIDE; void SetSP(uintptr_t new_sp) OVERRIDE { SetGPR(ESP, new_sp); diff --git a/runtime/arch/x86_64/context_x86_64.cc b/runtime/arch/x86_64/context_x86_64.cc index 12c94bc598..7c49e9c2b2 100644 --- a/runtime/arch/x86_64/context_x86_64.cc +++ b/runtime/arch/x86_64/context_x86_64.cc @@ -16,10 +16,8 @@ #include "context_x86_64.h" -#include "art_code.h" #include "base/bit_utils.h" #include "quick/quick_method_frame_info.h" -#include "stack.h" namespace art { namespace x86_64 { @@ -37,9 +35,7 @@ void X86_64Context::Reset() { arg0_ = 0; } -void X86_64Context::FillCalleeSaves(const StackVisitor& fr) { - ArtCode code = fr.GetCurrentCode(); - const QuickMethodFrameInfo frame_info = code.GetQuickFrameInfo(); +void X86_64Context::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) { int spill_pos = 0; // Core registers come first, from the highest down to the lowest. @@ -47,7 +43,7 @@ void X86_64Context::FillCalleeSaves(const StackVisitor& fr) { frame_info.CoreSpillMask() & ~(static_cast<uint32_t>(-1) << kNumberOfCpuRegisters); DCHECK_EQ(1, POPCOUNT(frame_info.CoreSpillMask() & ~core_regs)); // Return address spill. for (uint32_t core_reg : HighToLowBits(core_regs)) { - gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()); ++spill_pos; } DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) - 1); @@ -57,7 +53,7 @@ void X86_64Context::FillCalleeSaves(const StackVisitor& fr) { DCHECK_EQ(0u, fp_regs & (static_cast<uint32_t>(-1) << kNumberOfFloatRegisters)); for (uint32_t fp_reg : HighToLowBits(fp_regs)) { fprs_[fp_reg] = reinterpret_cast<uint64_t*>( - fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes())); + CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes())); ++spill_pos; } DCHECK_EQ(spill_pos, diff --git a/runtime/arch/x86_64/context_x86_64.h b/runtime/arch/x86_64/context_x86_64.h index f05b7f093f..46f2b63848 100644 --- a/runtime/arch/x86_64/context_x86_64.h +++ b/runtime/arch/x86_64/context_x86_64.h @@ -34,7 +34,7 @@ class X86_64Context : public Context { void Reset() OVERRIDE; - void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_); + void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) OVERRIDE; void SetSP(uintptr_t new_sp) OVERRIDE { SetGPR(RSP, new_sp); diff --git a/runtime/art_code.cc b/runtime/art_code.cc deleted file mode 100644 index ad0b170079..0000000000 --- a/runtime/art_code.cc +++ /dev/null @@ -1,333 +0,0 @@ -/* - * 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 "art_code.h" - -#include "art_method.h" -#include "art_method-inl.h" -#include "class_linker.h" -#include "entrypoints/runtime_asm_entrypoints.h" -#include "handle_scope.h" -#include "jit/jit.h" -#include "jit/jit_code_cache.h" -#include "mapping_table.h" -#include "oat.h" -#include "runtime.h" -#include "utils.h" - -namespace art { - - // Converts a dex PC to a native PC. -uintptr_t ArtCode::ToNativeQuickPc(const uint32_t dex_pc, - bool is_for_catch_handler, - bool abort_on_failure) - SHARED_REQUIRES(Locks::mutator_lock_) { - const void* entry_point = GetQuickOatEntryPoint(sizeof(void*)); - if (IsOptimized(sizeof(void*))) { - // 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<uintptr_t>(entry_point) + stack_map.GetNativePcOffset(encoding); - } - } else { - MappingTable table((entry_point != nullptr) ? GetMappingTable(sizeof(void*)) : nullptr); - 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<uintptr_t>(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<uintptr_t>(entry_point) + cur.NativePcOffset(); - } - } - } - - if (abort_on_failure) { - LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc - << " in " << PrettyMethod(method_); - } - return UINTPTR_MAX; -} - -bool ArtCode::IsOptimized(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_) { - // Temporary solution for detecting if a method has been optimized: the compiler - // does not create a GC map. Instead, the vmap table contains the stack map - // (as in stack_map.h). - return !method_->IsNative() - && method_->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size) != nullptr - && GetQuickOatEntryPoint(pointer_size) != nullptr - && GetNativeGcMap(pointer_size) == nullptr; -} - -CodeInfo ArtCode::GetOptimizedCodeInfo() { - DCHECK(IsOptimized(sizeof(void*))); - const void* code_pointer = EntryPointToCodePointer(GetQuickOatEntryPoint(sizeof(void*))); - DCHECK(code_pointer != nullptr); - uint32_t offset = - reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].vmap_table_offset_; - const void* data = - reinterpret_cast<const void*>(reinterpret_cast<const uint8_t*>(code_pointer) - offset); - return CodeInfo(data); -} - -uintptr_t ArtCode::NativeQuickPcOffset(const uintptr_t pc) { - const void* quick_entry_point = GetQuickOatEntryPoint(sizeof(void*)); - CHECK_NE(quick_entry_point, GetQuickToInterpreterBridge()); - CHECK_EQ(quick_entry_point, - Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(method_, sizeof(void*))); - return pc - reinterpret_cast<uintptr_t>(quick_entry_point); -} - -uint32_t ArtCode::ToDexPc(const uintptr_t pc, bool abort_on_failure) { - const void* entry_point = GetQuickOatEntryPoint(sizeof(void*)); - uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(entry_point); - if (IsOptimized(sizeof(void*))) { - 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(entry_point != nullptr ? GetMappingTable(sizeof(void*)) : nullptr); - if (table.TotalSize() == 0) { - // NOTE: Special methods (see Mir2Lir::GenSpecialCase()) have an empty mapping - // but they have no suspend checks and, consequently, we never call ToDexPc() for them. - DCHECK(method_->IsNative() || method_->IsCalleeSaveMethod() || method_->IsProxyMethod()) - << PrettyMethod(method_); - return DexFile::kDexNoIndex; // Special no mapping case - } - // 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) { - LOG(FATAL) << "Failed to find Dex offset for PC offset " << reinterpret_cast<void*>(sought_offset) - << "(PC " << reinterpret_cast<void*>(pc) << ", entry_point=" << entry_point - << " current entry_point=" << GetQuickOatEntryPoint(sizeof(void*)) - << ") in " << PrettyMethod(method_); - } - return DexFile::kDexNoIndex; -} - -const uint8_t* ArtCode::GetNativeGcMap(size_t pointer_size) { - const void* code_pointer = EntryPointToCodePointer(GetQuickOatEntryPoint(pointer_size)); - if (code_pointer == nullptr) { - return nullptr; - } - uint32_t offset = - reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].gc_map_offset_; - if (UNLIKELY(offset == 0u)) { - return nullptr; - } - return reinterpret_cast<const uint8_t*>(code_pointer) - offset; -} - -const uint8_t* ArtCode::GetVmapTable(size_t pointer_size) { - CHECK(!IsOptimized(pointer_size)) << "Unimplemented vmap table for optimized compiler"; - const void* code_pointer = EntryPointToCodePointer(GetQuickOatEntryPoint(pointer_size)); - if (code_pointer == nullptr) { - return nullptr; - } - uint32_t offset = - reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].vmap_table_offset_; - if (UNLIKELY(offset == 0u)) { - return nullptr; - } - return reinterpret_cast<const uint8_t*>(code_pointer) - offset; -} - -const uint8_t* ArtCode::GetMappingTable(size_t pointer_size) { - const void* code_pointer = EntryPointToCodePointer(GetQuickOatEntryPoint(pointer_size)); - if (code_pointer == nullptr) { - return nullptr; - } - uint32_t offset = - reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].mapping_table_offset_; - if (UNLIKELY(offset == 0u)) { - return nullptr; - } - return reinterpret_cast<const uint8_t*>(code_pointer) - offset; -} - -// Counts the number of references in the parameter list of the corresponding method. -// Note: Thus does _not_ include "this" for non-static methods. -static uint32_t GetNumberOfReferenceArgsWithoutReceiver(ArtMethod* method) - SHARED_REQUIRES(Locks::mutator_lock_) { - uint32_t shorty_len; - const char* shorty = method->GetShorty(&shorty_len); - uint32_t refs = 0; - for (uint32_t i = 1; i < shorty_len ; ++i) { - if (shorty[i] == 'L') { - refs++; - } - } - return refs; -} - -QuickMethodFrameInfo ArtCode::GetQuickFrameInfo() { - Runtime* runtime = Runtime::Current(); - - if (UNLIKELY(method_->IsAbstract())) { - return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs); - } - - // This goes before IsProxyMethod since runtime methods have a null declaring class. - if (UNLIKELY(method_->IsRuntimeMethod())) { - return runtime->GetRuntimeMethodFrameInfo(method_); - } - - // For Proxy method we add special handling for the direct method case (there is only one - // direct method - constructor). Direct method is cloned from original - // java.lang.reflect.Proxy class together with code and as a result it is executed as usual - // quick compiled method without any stubs. So the frame info should be returned as it is a - // quick method not a stub. However, if instrumentation stubs are installed, the - // instrumentation->GetQuickCodeFor() returns the artQuickProxyInvokeHandler instead of an - // oat code pointer, thus we have to add a special case here. - if (UNLIKELY(method_->IsProxyMethod())) { - if (method_->IsDirect()) { - CHECK(method_->IsConstructor()); - const void* code_pointer = - EntryPointToCodePointer(method_->GetEntryPointFromQuickCompiledCode()); - return reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].frame_info_; - } else { - return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs); - } - } - - const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(method_, sizeof(void*)); - ClassLinker* class_linker = runtime->GetClassLinker(); - // On failure, instead of null we get the quick-generic-jni-trampoline for native method - // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline) - // for non-native methods. And we really shouldn't see a failure for non-native methods here. - DCHECK(!class_linker->IsQuickToInterpreterBridge(entry_point)); - - if (class_linker->IsQuickGenericJniStub(entry_point)) { - // Generic JNI frame. - DCHECK(method_->IsNative()); - uint32_t handle_refs = GetNumberOfReferenceArgsWithoutReceiver(method_) + 1; - size_t scope_size = HandleScope::SizeOf(handle_refs); - QuickMethodFrameInfo callee_info = runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs); - - // Callee saves + handle scope + method ref + alignment - // Note: -sizeof(void*) since callee-save frame stores a whole method pointer. - size_t frame_size = RoundUp(callee_info.FrameSizeInBytes() - sizeof(void*) + - sizeof(ArtMethod*) + scope_size, kStackAlignment); - return QuickMethodFrameInfo(frame_size, callee_info.CoreSpillMask(), callee_info.FpSpillMask()); - } - - const void* code_pointer = EntryPointToCodePointer(entry_point); - return reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].frame_info_; -} - -void ArtCode::AssertPcIsWithinQuickCode(uintptr_t pc) { - if (method_->IsNative() || method_->IsRuntimeMethod() || method_->IsProxyMethod()) { - return; - } - if (pc == reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc())) { - return; - } - const void* code = method_->GetEntryPointFromQuickCompiledCode(); - if (code == GetQuickInstrumentationEntryPoint()) { - return; - } - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - if (class_linker->IsQuickToInterpreterBridge(code) || - class_linker->IsQuickResolutionStub(code)) { - return; - } - // If we are the JIT then we may have just compiled the method after the - // IsQuickToInterpreterBridge check. - jit::Jit* const jit = Runtime::Current()->GetJit(); - if (jit != nullptr && - jit->GetCodeCache()->ContainsCodePtr(reinterpret_cast<const void*>(code))) { - return; - } - - uint32_t code_size = reinterpret_cast<const OatQuickMethodHeader*>( - EntryPointToCodePointer(code))[-1].code_size_; - uintptr_t code_start = reinterpret_cast<uintptr_t>(code); - CHECK(code_start <= pc && pc <= (code_start + code_size)) - << PrettyMethod(method_) - << " pc=" << std::hex << pc - << " code=" << code - << " size=" << code_size; -} - -bool ArtCode::PcIsWithinQuickCode(uintptr_t pc) { - /* - * During a stack walk, a return PC may point past-the-end of the code - * in the case that the last instruction is a call that isn't expected to - * return. Thus, we check <= code + GetCodeSize(). - * - * NOTE: For Thumb both pc and code are offset by 1 indicating the Thumb state. - */ - uintptr_t code = reinterpret_cast<uintptr_t>(EntryPointToCodePointer( - method_->GetEntryPointFromQuickCompiledCode())); - if (code == 0) { - return pc == 0; - } - uintptr_t code_size = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].code_size_; - return code <= pc && pc <= (code + code_size); -} - -const void* ArtCode::GetQuickOatEntryPoint(size_t pointer_size) { - if (method_->IsAbstract() || method_->IsRuntimeMethod() || method_->IsProxyMethod()) { - return nullptr; - } - Runtime* runtime = Runtime::Current(); - ClassLinker* class_linker = runtime->GetClassLinker(); - const void* code = runtime->GetInstrumentation()->GetQuickCodeFor(method_, pointer_size); - // On failure, instead of null we get the quick-generic-jni-trampoline for native method - // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline) - // for non-native methods. - if (class_linker->IsQuickToInterpreterBridge(code) || - class_linker->IsQuickGenericJniStub(code)) { - return nullptr; - } - return code; -} - -} // namespace art diff --git a/runtime/art_code.h b/runtime/art_code.h deleted file mode 100644 index 1d2d898ed6..0000000000 --- a/runtime/art_code.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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. - */ - -#ifndef ART_RUNTIME_ART_CODE_H_ -#define ART_RUNTIME_ART_CODE_H_ - -#include "base/mutex.h" -#include "offsets.h" -#include "quick/quick_method_frame_info.h" -#include "stack_map.h" - -namespace art { - -class ArtMethod; - -class ArtCode FINAL { - public: - explicit ArtCode(ArtMethod** method) : method_(*method) {} - explicit ArtCode(ArtMethod* method) : method_(method) {} - ArtCode() : method_(nullptr) {} - - // Converts a dex PC to a native PC. - uintptr_t ToNativeQuickPc(const uint32_t dex_pc, - bool is_for_catch_handler, - bool abort_on_failure = true) - SHARED_REQUIRES(Locks::mutator_lock_); - - bool IsOptimized(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - - CodeInfo GetOptimizedCodeInfo() SHARED_REQUIRES(Locks::mutator_lock_); - - uintptr_t NativeQuickPcOffset(const uintptr_t pc) SHARED_REQUIRES(Locks::mutator_lock_); - - // Converts a native PC to a dex PC. - uint32_t ToDexPc(const uintptr_t pc, bool abort_on_failure = true) - SHARED_REQUIRES(Locks::mutator_lock_); - - // Callers should wrap the uint8_t* in a GcMap instance for convenient access. - const uint8_t* GetNativeGcMap(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - - const uint8_t* GetVmapTable(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - - const uint8_t* GetMappingTable(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - - QuickMethodFrameInfo GetQuickFrameInfo() SHARED_REQUIRES(Locks::mutator_lock_); - - FrameOffset GetReturnPcOffset() SHARED_REQUIRES(Locks::mutator_lock_) { - return FrameOffset(GetFrameSizeInBytes() - sizeof(void*)); - } - - template <bool kCheckFrameSize = true> - uint32_t GetFrameSizeInBytes() SHARED_REQUIRES(Locks::mutator_lock_) { - uint32_t result = GetQuickFrameInfo().FrameSizeInBytes(); - if (kCheckFrameSize) { - DCHECK_LE(static_cast<size_t>(kStackAlignment), result); - } - return result; - } - - const void* GetQuickOatEntryPoint(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - - void AssertPcIsWithinQuickCode(uintptr_t pc) SHARED_REQUIRES(Locks::mutator_lock_); - - bool PcIsWithinQuickCode(uintptr_t pc) SHARED_REQUIRES(Locks::mutator_lock_); - - FrameOffset GetHandleScopeOffset() SHARED_REQUIRES(Locks::mutator_lock_) { - constexpr size_t handle_scope_offset = sizeof(ArtMethod*); - DCHECK_LT(handle_scope_offset, GetFrameSizeInBytes()); - return FrameOffset(handle_scope_offset); - } - - ArtMethod* GetMethod() const { return method_; } - - private: - ArtMethod* method_; -}; - -} // namespace art - -#endif // ART_RUNTIME_ART_CODE_H_ diff --git a/runtime/art_method.cc b/runtime/art_method.cc index f9d9077261..f5befdfc07 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -384,4 +384,28 @@ const uint8_t* ArtMethod::GetQuickenedInfo() { return oat_method.GetVmapTable(); } +const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) { + if (IsRuntimeMethod() || IsProxyMethod()) { + return nullptr; + } + + Runtime* runtime = Runtime::Current(); + const void* code = runtime->GetInstrumentation()->GetQuickCodeFor(this, sizeof(void*)); + DCHECK(code != nullptr); + + if (runtime->GetClassLinker()->IsQuickGenericJniStub(code)) { + // The generic JNI does not have any method header. + return nullptr; + } + + code = EntryPointToCodePointer(code); + OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>( + reinterpret_cast<uintptr_t>(code) - sizeof(OatQuickMethodHeader)); + + // TODO(ngeoffray): validate the pc. Note that unit tests can give unrelated pcs (for + // example arch_test). + UNUSED(pc); + return method_header; +} + } // namespace art diff --git a/runtime/art_method.h b/runtime/art_method.h index 9743250cc0..9f1495cf39 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -32,6 +32,7 @@ namespace art { union JValue; +class OatQuickMethodHeader; class ProfilingInfo; class ScopedObjectAccessAlreadyRunnable; class StringPiece; @@ -434,6 +435,11 @@ class ArtMethod FINAL { const uint8_t* GetQuickenedInfo() SHARED_REQUIRES(Locks::mutator_lock_); + // Returns the method header for the compiled code containing 'pc'. Note that runtime + // methods will return null for this method, as they are not oat based. + const OatQuickMethodHeader* GetOatQuickMethodHeader(uintptr_t pc) + SHARED_REQUIRES(Locks::mutator_lock_); + protected: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". // The class we are a part of. diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h index e8973511e3..b9ea475149 100644 --- a/runtime/check_reference_map_visitor.h +++ b/runtime/check_reference_map_visitor.h @@ -17,9 +17,9 @@ #ifndef ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_ #define ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_ -#include "art_code.h" #include "art_method-inl.h" #include "gc_map.h" +#include "oat_quick_method_header.h" #include "scoped_thread_state_change.h" #include "stack_map.h" @@ -54,7 +54,7 @@ class CheckReferenceMapVisitor : public StackVisitor { void CheckReferences(int* registers, int number_of_references, uint32_t native_pc_offset) SHARED_REQUIRES(Locks::mutator_lock_) { - if (GetCurrentCode().IsOptimized(sizeof(void*))) { + if (GetCurrentOatQuickMethodHeader()->IsOptimized()) { CheckOptimizedMethod(registers, number_of_references, native_pc_offset); } else { CheckQuickMethod(registers, number_of_references, native_pc_offset); @@ -65,7 +65,7 @@ class CheckReferenceMapVisitor : public StackVisitor { void CheckOptimizedMethod(int* registers, int number_of_references, uint32_t native_pc_offset) SHARED_REQUIRES(Locks::mutator_lock_) { ArtMethod* m = GetMethod(); - CodeInfo code_info = GetCurrentCode().GetOptimizedCodeInfo(); + CodeInfo code_info = GetCurrentOatQuickMethodHeader()->GetOptimizedCodeInfo(); StackMapEncoding encoding = code_info.ExtractEncoding(); StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); uint16_t number_of_dex_registers = m->GetCodeItem()->registers_size_; @@ -109,7 +109,7 @@ class CheckReferenceMapVisitor : public StackVisitor { void CheckQuickMethod(int* registers, int number_of_references, uint32_t native_pc_offset) SHARED_REQUIRES(Locks::mutator_lock_) { ArtMethod* m = GetMethod(); - NativePcOffsetToReferenceMap map(GetCurrentCode().GetNativeGcMap(sizeof(void*))); + NativePcOffsetToReferenceMap map(GetCurrentOatQuickMethodHeader()->GetNativeGcMap()); const uint8_t* ref_bitmap = map.FindBitMap(native_pc_offset); CHECK(ref_bitmap); for (int i = 0; i < number_of_references; ++i) { diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index 17e6aac357..e57569e140 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -16,7 +16,6 @@ #include "entrypoints/entrypoint_utils.h" -#include "art_code.h" #include "art_field-inl.h" #include "art_method-inl.h" #include "base/mutex.h" @@ -31,6 +30,7 @@ #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "nth_caller_visitor.h" +#include "oat_quick_method_header.h" #include "reflection.h" #include "scoped_thread_state_change.h" #include "ScopedLocalRef.h" @@ -359,33 +359,31 @@ ArtMethod* GetCalleeSaveMethodCaller(ArtMethod** sp, const size_t callee_frame_size = GetCalleeSaveFrameSize(kRuntimeISA, type); auto** caller_sp = reinterpret_cast<ArtMethod**>( reinterpret_cast<uintptr_t>(sp) + callee_frame_size); - ArtCode current_code = GetCallingCodeFrom(caller_sp); + const size_t callee_return_pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, type); + uintptr_t caller_pc = *reinterpret_cast<uintptr_t*>( + (reinterpret_cast<uint8_t*>(sp) + callee_return_pc_offset)); ArtMethod* outer_method = *caller_sp; ArtMethod* caller = outer_method; - if ((outer_method != nullptr) && current_code.IsOptimized(sizeof(void*))) { - const size_t callee_return_pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, type); - uintptr_t caller_pc = *reinterpret_cast<uintptr_t*>( - (reinterpret_cast<uint8_t*>(sp) + callee_return_pc_offset)); - if (LIKELY(caller_pc != reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()))) { - uintptr_t native_pc_offset = current_code.NativeQuickPcOffset(caller_pc); - CodeInfo code_info = current_code.GetOptimizedCodeInfo(); - StackMapEncoding encoding = code_info.ExtractEncoding(); - StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); - DCHECK(stack_map.IsValid()); - if (stack_map.HasInlineInfo(encoding)) { - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); - caller = GetResolvedMethod(outer_method, inline_info, inline_info.GetDepth() - 1); - } - } else { - // We're instrumenting, just use the StackVisitor which knows how to - // handle instrumented frames. - NthCallerVisitor visitor(Thread::Current(), 1, true); - visitor.WalkStack(); - caller = visitor.caller; - if (kIsDebugBuild) { - // Avoid doing the check below. - do_caller_check = false; + if (outer_method != nullptr) { + const OatQuickMethodHeader* current_code = outer_method->GetOatQuickMethodHeader(caller_pc); + if (current_code->IsOptimized()) { + if (LIKELY(caller_pc != reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()))) { + uintptr_t native_pc_offset = current_code->NativeQuickPcOffset(caller_pc); + CodeInfo code_info = current_code->GetOptimizedCodeInfo(); + StackMapEncoding encoding = code_info.ExtractEncoding(); + StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); + DCHECK(stack_map.IsValid()); + if (stack_map.HasInlineInfo(encoding)) { + InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); + caller = GetResolvedMethod(outer_method, inline_info, inline_info.GetDepth() - 1); + } + } else { + // We're instrumenting, just use the StackVisitor which knows how to + // handle instrumented frames. + NthCallerVisitor visitor(Thread::Current(), 1, true); + visitor.WalkStack(); + caller = visitor.caller; } } } diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index 171ace27a5..0469ee6eb6 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -20,7 +20,6 @@ #include <jni.h> #include <stdint.h> -#include "art_code.h" #include "base/macros.h" #include "base/mutex.h" #include "dex_instruction.h" @@ -40,6 +39,7 @@ namespace mirror { class ArtField; class ArtMethod; +class OatQuickMethodHeader; class ScopedObjectAccessAlreadyRunnable; class Thread; @@ -185,10 +185,6 @@ ArtMethod* GetCalleeSaveMethodCaller(ArtMethod** sp, Runtime::CalleeSaveType type, bool do_caller_check = false); -inline ArtCode GetCallingCodeFrom(ArtMethod** sp) { - return ArtCode(sp); -} - } // namespace art #endif // ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_ diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 6035dfe084..5eda6d6bd3 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -14,7 +14,6 @@ * limitations under the License. */ -#include "art_code.h" #include "art_method-inl.h" #include "callee_save_frame.h" #include "common_throws.h" @@ -30,6 +29,7 @@ #include "mirror/method.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" +#include "oat_quick_method_header.h" #include "quick_exception_handler.h" #include "runtime.h" #include "scoped_thread_state_change.h" @@ -295,8 +295,6 @@ class QuickArgumentVisitor { static mirror::Object* GetProxyThisObject(ArtMethod** sp) SHARED_REQUIRES(Locks::mutator_lock_) { CHECK((*sp)->IsProxyMethod()); - CHECK_EQ(kQuickCalleeSaveFrame_RefAndArgs_FrameSize, - GetCallingCodeFrom(sp).GetFrameSizeInBytes()); CHECK_GT(kNumQuickGprArgs, 0u); constexpr uint32_t kThisGprIndex = 0u; // 'this' is in the 1st GPR. size_t this_arg_offset = kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset + @@ -323,10 +321,11 @@ class QuickArgumentVisitor { ArtMethod** caller_sp = reinterpret_cast<ArtMethod**>( reinterpret_cast<uintptr_t>(sp) + callee_frame_size); uintptr_t outer_pc = QuickArgumentVisitor::GetCallingPc(sp); - uintptr_t outer_pc_offset = GetCallingCodeFrom(caller_sp).NativeQuickPcOffset(outer_pc); + const OatQuickMethodHeader* current_code = (*caller_sp)->GetOatQuickMethodHeader(outer_pc); + uintptr_t outer_pc_offset = current_code->NativeQuickPcOffset(outer_pc); - if (GetCallingCodeFrom(caller_sp).IsOptimized(sizeof(void*))) { - CodeInfo code_info = GetCallingCodeFrom(caller_sp).GetOptimizedCodeInfo(); + if (current_code->IsOptimized()) { + CodeInfo code_info = current_code->GetOptimizedCodeInfo(); StackMapEncoding encoding = code_info.ExtractEncoding(); StackMap stack_map = code_info.GetStackMapForNativePcOffset(outer_pc_offset, encoding); DCHECK(stack_map.IsValid()); @@ -337,7 +336,7 @@ class QuickArgumentVisitor { return stack_map.GetDexPc(encoding); } } else { - return GetCallingCodeFrom(caller_sp).ToDexPc(outer_pc); + return current_code->ToDexPc(*caller_sp, outer_pc); } } @@ -842,10 +841,6 @@ extern "C" uint64_t artQuickProxyInvokeHandler( self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments"); // Register the top of the managed stack, making stack crawlable. DCHECK_EQ((*sp), proxy_method) << PrettyMethod(proxy_method); - DCHECK_EQ(GetCallingCodeFrom(sp).GetFrameSizeInBytes(), - ArtCode(Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)) - .GetFrameSizeInBytes()) - << PrettyMethod(proxy_method); self->VerifyStack(); // Start new JNI local reference state. JNIEnvExt* env = self->GetJniEnv(); diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc index 5299394d7c..4e8591339c 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc @@ -49,7 +49,7 @@ class QuickTrampolineEntrypointsTest : public CommonRuntimeTest { static void CheckFrameSize(InstructionSet isa, Runtime::CalleeSaveType type, uint32_t save_size) NO_THREAD_SAFETY_ANALYSIS { ArtMethod* save_method = CreateCalleeSaveMethod(isa, type); - QuickMethodFrameInfo frame_info = ArtCode(save_method).GetQuickFrameInfo(); + QuickMethodFrameInfo frame_info = Runtime::Current()->GetRuntimeMethodFrameInfo(save_method); EXPECT_EQ(frame_info.FrameSizeInBytes(), save_size) << "Expected and real size differs for " << type << " core spills=" << std::hex << frame_info.CoreSpillMask() << " fp spills=" << frame_info.FpSpillMask() << std::dec << " ISA " << isa; @@ -58,8 +58,8 @@ class QuickTrampolineEntrypointsTest : public CommonRuntimeTest { static void CheckPCOffset(InstructionSet isa, Runtime::CalleeSaveType type, size_t pc_offset) NO_THREAD_SAFETY_ANALYSIS { ArtMethod* save_method = CreateCalleeSaveMethod(isa, type); - QuickMethodFrameInfo frame_info = ArtCode(save_method).GetQuickFrameInfo(); - EXPECT_EQ(ArtCode(save_method).GetReturnPcOffset().SizeValue(), pc_offset) + QuickMethodFrameInfo frame_info = Runtime::Current()->GetRuntimeMethodFrameInfo(save_method); + EXPECT_EQ(frame_info.GetReturnPcOffset(), pc_offset) << "Expected and real pc offset differs for " << type << " core spills=" << std::hex << frame_info.CoreSpillMask() << " fp spills=" << frame_info.FpSpillMask() << std::dec << " ISA " << isa; diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc index da1d80ea33..4de8a8ead9 100644 --- a/runtime/exception_test.cc +++ b/runtime/exception_test.cc @@ -26,6 +26,7 @@ #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" #include "mirror/stack_trace_element.h" +#include "oat_quick_method_header.h" #include "runtime.h" #include "scoped_thread_state_change.h" #include "handle_scope-inl.h" @@ -169,7 +170,7 @@ TEST_F(ExceptionTest, StackTraceElement) { r->SetInstructionSet(kRuntimeISA); ArtMethod* save_method = r->CreateCalleeSaveMethod(); r->SetCalleeSaveMethod(save_method, Runtime::kSaveAll); - QuickMethodFrameInfo frame_info = ArtCode(save_method).GetQuickFrameInfo(); + QuickMethodFrameInfo frame_info = r->GetRuntimeMethodFrameInfo(save_method); ASSERT_EQ(kStackAlignment, 16U); // ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t)); @@ -186,15 +187,15 @@ TEST_F(ExceptionTest, StackTraceElement) { fake_stack.push_back(0); } - fake_stack.push_back( - ArtCode(method_g_).ToNativeQuickPc(dex_pc, /* is_catch_handler */ false)); // return pc + fake_stack.push_back(method_g_->GetOatQuickMethodHeader(0)->ToNativeQuickPc( + method_g_, dex_pc, /* is_catch_handler */ false)); // return pc // Create/push fake 16byte stack frame for method g fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_)); fake_stack.push_back(0); fake_stack.push_back(0); - fake_stack.push_back( - ArtCode(method_g_).ToNativeQuickPc(dex_pc, /* is_catch_handler */ false)); // return pc + fake_stack.push_back(method_g_->GetOatQuickMethodHeader(0)->ToNativeQuickPc( + method_g_, dex_pc, /* is_catch_handler */ false)); // return pc // Create/push fake 16byte stack frame for method f fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_)); diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc index 5b31b3aa4b..52ccbeeca0 100644 --- a/runtime/fault_handler.cc +++ b/runtime/fault_handler.cc @@ -20,10 +20,10 @@ #include <sys/mman.h> #include <sys/ucontext.h> -#include "art_code.h" #include "art_method-inl.h" #include "base/stl_util.h" #include "mirror/class.h" +#include "oat_quick_method_header.h" #include "sigchain.h" #include "thread-inl.h" #include "verify_object-inl.h" @@ -360,17 +360,17 @@ bool FaultManager::IsInGeneratedCode(siginfo_t* siginfo, void* context, bool che return false; } - ArtCode art_code(method_obj); + const OatQuickMethodHeader* method_header = method_obj->GetOatQuickMethodHeader(return_pc); // We can be certain that this is a method now. Check if we have a GC map // at the return PC address. if (true || kIsDebugBuild) { VLOG(signals) << "looking for dex pc for return pc " << std::hex << return_pc; uint32_t sought_offset = return_pc - - reinterpret_cast<uintptr_t>(art_code.GetQuickOatEntryPoint(sizeof(void*))); + reinterpret_cast<uintptr_t>(method_header->GetEntryPoint()); VLOG(signals) << "pc offset: " << std::hex << sought_offset; } - uint32_t dexpc = art_code.ToDexPc(return_pc, false); + uint32_t dexpc = method_header->ToDexPc(method_obj, return_pc, false); VLOG(signals) << "dexpc: " << dexpc; return !check_dex_pc || dexpc != DexFile::kDexNoIndex; } diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 2dd2b7d403..ed64d7efbe 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -19,7 +19,6 @@ #include <sstream> #include "arch/context.h" -#include "art_code.h" #include "art_method-inl.h" #include "atomic.h" #include "class_linker.h" @@ -37,6 +36,7 @@ #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" #include "nth_caller_visitor.h" +#include "oat_quick_method_header.h" #include "thread.h" #include "thread_list.h" @@ -252,7 +252,9 @@ static void InstrumentationInstallStack(Thread* thread, void* arg) instrumentation_stack_->insert(it, instrumentation_frame); SetReturnPc(instrumentation_exit_pc_); } - dex_pcs_.push_back(GetCurrentCode().ToDexPc(last_return_pc_)); + dex_pcs_.push_back((GetCurrentOatQuickMethodHeader() == nullptr) + ? DexFile::kDexNoIndex + : GetCurrentOatQuickMethodHeader()->ToDexPc(m, last_return_pc_)); last_return_pc_ = return_pc; ++instrumentation_stack_depth_; return true; // Continue. diff --git a/runtime/oat.cc b/runtime/oat.cc index 5625499848..40aca0d249 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -483,15 +483,4 @@ OatMethodOffsets::OatMethodOffsets(uint32_t code_offset) : code_offset_(code_off OatMethodOffsets::~OatMethodOffsets() {} -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() {} - } // namespace art diff --git a/runtime/oat.h b/runtime/oat.h index 2aa5783bde..276e7f3ea5 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -22,7 +22,6 @@ #include "arch/instruction_set.h" #include "base/macros.h" #include "dex_file.h" -#include "quick/quick_method_frame_info.h" #include "safe_map.h" namespace art { @@ -170,30 +169,6 @@ class PACKED(4) OatMethodOffsets { uint32_t code_offset_; }; -// OatQuickMethodHeader precedes the raw code chunk generated by the Quick compiler. -class PACKED(4) OatQuickMethodHeader { - public: - OatQuickMethodHeader(uint32_t mapping_table_offset = 0U, uint32_t vmap_table_offset = 0U, - uint32_t gc_map_offset = 0U, uint32_t frame_size_in_bytes = 0U, - uint32_t core_spill_mask = 0U, uint32_t fp_spill_mask = 0U, - uint32_t code_size = 0U); - - ~OatQuickMethodHeader(); - - OatQuickMethodHeader& operator=(const OatQuickMethodHeader&) = default; - - // The offset in bytes from the start of the mapping table to the end of the header. - uint32_t mapping_table_offset_; - // The offset in bytes from the start of the vmap table to the end of the header. - uint32_t vmap_table_offset_; - // The offset in bytes from the start of the gc map to the end of the header. - uint32_t gc_map_offset_; - // The stack frame information. - QuickMethodFrameInfo frame_info_; - // The code size in bytes. - uint32_t code_size_; -}; - } // namespace art #endif // ART_RUNTIME_OAT_H_ diff --git a/runtime/oat_file-inl.h b/runtime/oat_file-inl.h index f7913e177a..7b92120fde 100644 --- a/runtime/oat_file-inl.h +++ b/runtime/oat_file-inl.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_OAT_FILE_INL_H_ #include "oat_file.h" +#include "oat_quick_method_header.h" namespace art { diff --git a/runtime/oat_quick_method_header.cc b/runtime/oat_quick_method_header.cc new file mode 100644 index 0000000000..9786c05a9d --- /dev/null +++ b/runtime/oat_quick_method_header.cc @@ -0,0 +1,139 @@ +/* + * 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<uintptr_t>(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<void*>(sought_offset) + << "(PC " << reinterpret_cast<void*>(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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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 diff --git a/runtime/oat_quick_method_header.h b/runtime/oat_quick_method_header.h new file mode 100644 index 0000000000..6eadd87d38 --- /dev/null +++ b/runtime/oat_quick_method_header.h @@ -0,0 +1,127 @@ +/* + * 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. + */ + +#ifndef ART_RUNTIME_OAT_QUICK_METHOD_HEADER_H_ +#define ART_RUNTIME_OAT_QUICK_METHOD_HEADER_H_ + +#include "arch/instruction_set.h" +#include "base/macros.h" +#include "quick/quick_method_frame_info.h" +#include "stack_map.h" + +namespace art { + +class ArtMethod; + +// OatQuickMethodHeader precedes the raw code chunk generated by the compiler. +class PACKED(4) OatQuickMethodHeader { + public: + OatQuickMethodHeader(uint32_t mapping_table_offset = 0U, + uint32_t vmap_table_offset = 0U, + uint32_t gc_map_offset = 0U, + uint32_t frame_size_in_bytes = 0U, + uint32_t core_spill_mask = 0U, + uint32_t fp_spill_mask = 0U, + uint32_t code_size = 0U); + + ~OatQuickMethodHeader(); + + OatQuickMethodHeader& operator=(const OatQuickMethodHeader&) = default; + + uintptr_t NativeQuickPcOffset(const uintptr_t pc) const { + return pc - reinterpret_cast<uintptr_t>(GetEntryPoint()); + } + + bool IsOptimized() const { + return gc_map_offset_ == 0 && vmap_table_offset_ != 0; + } + + CodeInfo GetOptimizedCodeInfo() const { + DCHECK(IsOptimized()); + const void* data = reinterpret_cast<const void*>(code_ - vmap_table_offset_); + return CodeInfo(data); + } + + const uint8_t* GetCode() const { + return code_; + } + + const uint8_t* GetNativeGcMap() const { + return (gc_map_offset_ == 0) ? nullptr : code_ - gc_map_offset_; + } + + const uint8_t* GetMappingTable() const { + return (mapping_table_offset_ == 0) ? nullptr : code_ - mapping_table_offset_; + } + + const uint8_t* GetVmapTable() const { + CHECK(!IsOptimized()) << "Unimplemented vmap table for optimizing compiler"; + return (vmap_table_offset_ == 0) ? nullptr : code_ - vmap_table_offset_; + } + + bool Contains(uintptr_t pc) const { + uintptr_t code_start = reinterpret_cast<uintptr_t>(code_); + return code_start <= pc && pc <= (code_start + code_size_); + } + + const uint8_t* GetEntryPoint() const { + // When the runtime architecture is ARM, `kRuntimeISA` is set to `kArm` + // (not `kThumb2`), *but* we always generate code for the Thumb-2 + // instruction set anyway. Thumb-2 requires the entrypoint to be of + // offset 1. + static_assert(kRuntimeISA != kThumb2, "kThumb2 cannot be a runtime ISA"); + return (kRuntimeISA == kArm) + ? reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(code_) | 1) + : code_; + } + + template <bool kCheckFrameSize = true> + uint32_t GetFrameSizeInBytes() { + uint32_t result = frame_info_.FrameSizeInBytes(); + if (kCheckFrameSize) { + DCHECK_LE(static_cast<size_t>(kStackAlignment), result); + } + return result; + } + + QuickMethodFrameInfo GetFrameInfo() const { + return frame_info_; + } + + uintptr_t ToNativeQuickPc(ArtMethod* method, + const uint32_t dex_pc, + bool is_for_catch_handler, + bool abort_on_failure = true) const; + + uint32_t ToDexPc(ArtMethod* method, const uintptr_t pc, bool abort_on_failure = true) const; + + // The offset in bytes from the start of the mapping table to the end of the header. + uint32_t mapping_table_offset_; + // The offset in bytes from the start of the vmap table to the end of the header. + uint32_t vmap_table_offset_; + // The offset in bytes from the start of the gc map to the end of the header. + uint32_t gc_map_offset_; + // The stack frame information. + QuickMethodFrameInfo frame_info_; + // The code size in bytes. + uint32_t code_size_; + // The actual code. + uint8_t code_[0]; +}; + +} // namespace art + +#endif // ART_RUNTIME_OAT_QUICK_METHOD_HEADER_H_ diff --git a/runtime/quick/quick_method_frame_info.h b/runtime/quick/quick_method_frame_info.h index 684d4da30e..71f8265bef 100644 --- a/runtime/quick/quick_method_frame_info.h +++ b/runtime/quick/quick_method_frame_info.h @@ -50,6 +50,10 @@ class PACKED(4) QuickMethodFrameInfo { return fp_spill_mask_; } + size_t GetReturnPcOffset() const { + return FrameSizeInBytes() - sizeof(void*); + } + private: uint32_t frame_size_in_bytes_; uint32_t core_spill_mask_; diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index 7ba19ab8d6..d05f909b82 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -17,7 +17,6 @@ #include "quick_exception_handler.h" #include "arch/context.h" -#include "art_code.h" #include "art_method-inl.h" #include "dex_instruction.h" #include "entrypoints/entrypoint_utils.h" @@ -27,6 +26,7 @@ #include "mirror/class-inl.h" #include "mirror/class_loader.h" #include "mirror/throwable.h" +#include "oat_quick_method_header.h" #include "stack_map.h" #include "verifier/method_verifier.h" @@ -36,13 +36,19 @@ static constexpr bool kDebugExceptionDelivery = false; static constexpr size_t kInvalidFrameDepth = 0xffffffff; QuickExceptionHandler::QuickExceptionHandler(Thread* self, bool is_deoptimization) - : self_(self), context_(self->GetLongJumpContext()), is_deoptimization_(is_deoptimization), - method_tracing_active_(is_deoptimization || - Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()), - handler_quick_frame_(nullptr), handler_quick_frame_pc_(0), handler_quick_arg0_(0), - handler_method_(nullptr), handler_dex_pc_(0), clear_exception_(false), - handler_frame_depth_(kInvalidFrameDepth) { -} + : self_(self), + context_(self->GetLongJumpContext()), + is_deoptimization_(is_deoptimization), + method_tracing_active_(is_deoptimization || + Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()), + handler_quick_frame_(nullptr), + handler_quick_frame_pc_(0), + handler_method_header_(nullptr), + handler_quick_arg0_(0), + handler_method_(nullptr), + handler_dex_pc_(0), + clear_exception_(false), + handler_frame_depth_(kInvalidFrameDepth) {} // Finds catch handler. class CatchBlockStackVisitor FINAL : public StackVisitor { @@ -62,6 +68,7 @@ class CatchBlockStackVisitor FINAL : public StackVisitor { // This is the upcall, we remember the frame and last pc so that we may long jump to them. exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc()); exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame()); + exception_handler_->SetHandlerMethodHeader(GetCurrentOatQuickMethodHeader()); uint32_t next_dex_pc; ArtMethod* next_art_method; bool has_next = GetNextMethodAndDexPc(&next_art_method, &next_dex_pc); @@ -101,8 +108,10 @@ class CatchBlockStackVisitor FINAL : public StackVisitor { exception_handler_->SetHandlerMethod(method); exception_handler_->SetHandlerDexPc(found_dex_pc); exception_handler_->SetHandlerQuickFramePc( - GetCurrentCode().ToNativeQuickPc(found_dex_pc, /* is_catch_handler */ true)); + GetCurrentOatQuickMethodHeader()->ToNativeQuickPc( + method, found_dex_pc, /* is_catch_handler */ true)); exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame()); + exception_handler_->SetHandlerMethodHeader(GetCurrentOatQuickMethodHeader()); return false; // End stack walk. } else if (UNLIKELY(GetThread()->HasDebuggerShadowFrames())) { // We are going to unwind this frame. Did we prepare a shadow frame for debugging? @@ -160,8 +169,8 @@ void QuickExceptionHandler::FindCatch(mirror::Throwable* exception) { } // If the handler is in optimized code, we need to set the catch environment. if (*handler_quick_frame_ != nullptr && - handler_method_ != nullptr && - ArtCode(handler_quick_frame_).IsOptimized(sizeof(void*))) { + handler_method_header_ != nullptr && + handler_method_header_->IsOptimized()) { SetCatchEnvironmentForOptimizedHandler(&visitor); } } @@ -202,14 +211,14 @@ static VRegKind ToVRegKind(DexRegisterLocation::Kind kind) { void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* stack_visitor) { DCHECK(!is_deoptimization_); DCHECK(*handler_quick_frame_ != nullptr) << "Method should not be called on upcall exceptions"; - DCHECK(handler_method_ != nullptr && ArtCode(handler_quick_frame_).IsOptimized(sizeof(void*))); + DCHECK(handler_method_ != nullptr && handler_method_header_->IsOptimized()); if (kDebugExceptionDelivery) { self_->DumpStack(LOG(INFO) << "Setting catch phis: "); } const size_t number_of_vregs = handler_method_->GetCodeItem()->registers_size_; - CodeInfo code_info = ArtCode(handler_quick_frame_).GetOptimizedCodeInfo(); + CodeInfo code_info = handler_method_header_->GetOptimizedCodeInfo(); StackMapEncoding encoding = code_info.ExtractEncoding(); // Find stack map of the throwing instruction. @@ -285,6 +294,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { // and last pc so that we may long jump to them. exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc()); exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame()); + exception_handler_->SetHandlerMethodHeader(GetCurrentOatQuickMethodHeader()); if (!stacked_shadow_frame_pushed_) { // In case there is no deoptimized shadow frame for this upcall, we still // need to push a nullptr to the stack since there is always a matching pop after diff --git a/runtime/quick_exception_handler.h b/runtime/quick_exception_handler.h index 89d6a25128..eedf83f6df 100644 --- a/runtime/quick_exception_handler.h +++ b/runtime/quick_exception_handler.h @@ -71,6 +71,10 @@ class QuickExceptionHandler { handler_quick_frame_pc_ = handler_quick_frame_pc; } + void SetHandlerMethodHeader(const OatQuickMethodHeader* handler_method_header) { + handler_method_header_ = handler_method_header; + } + void SetHandlerQuickArg0(uintptr_t handler_quick_arg0) { handler_quick_arg0_ = handler_quick_arg0; } @@ -115,6 +119,8 @@ class QuickExceptionHandler { ArtMethod** handler_quick_frame_; // PC to branch to for the handler. uintptr_t handler_quick_frame_pc_; + // Quick code of the handler. + const OatQuickMethodHeader* handler_method_header_; // The value for argument 0. uintptr_t handler_quick_arg0_; // The handler method to report to the debugger. diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc index 44a13c9020..f0b3c4e4cb 100644 --- a/runtime/runtime_linux.cc +++ b/runtime/runtime_linux.cc @@ -41,7 +41,7 @@ struct Backtrace { public: explicit Backtrace(void* raw_context) : raw_context_(raw_context) {} void Dump(std::ostream& os) const { - DumpNativeStack(os, GetTid(), "\t", nullptr, nullptr, raw_context_); + DumpNativeStack(os, GetTid(), "\t", nullptr, raw_context_); } private: // Stores the context of the signal that was unexpected and will terminate the runtime. The diff --git a/runtime/stack.cc b/runtime/stack.cc index d8d916c7ee..9359d27822 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -17,7 +17,6 @@ #include "stack.h" #include "arch/context.h" -#include "art_code.h" #include "art_method-inl.h" #include "base/hex_dump.h" #include "entrypoints/entrypoint_utils-inl.h" @@ -25,10 +24,13 @@ #include "gc_map.h" #include "gc/space/image_space.h" #include "gc/space/space-inl.h" +#include "jit/jit.h" +#include "jit/jit_code_cache.h" #include "linear_alloc.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" +#include "oat_quick_method_header.h" #include "quick/quick_method_frame_info.h" #include "runtime.h" #include "thread.h" @@ -103,6 +105,7 @@ StackVisitor::StackVisitor(Thread* thread, cur_shadow_frame_(nullptr), cur_quick_frame_(nullptr), cur_quick_frame_pc_(0), + cur_oat_quick_method_header_(nullptr), num_frames_(num_frames), cur_depth_(0), current_inlining_depth_(0), @@ -111,9 +114,9 @@ StackVisitor::StackVisitor(Thread* thread, } InlineInfo StackVisitor::GetCurrentInlineInfo() const { - ArtCode outer_code = GetCurrentCode(); - uint32_t native_pc_offset = outer_code.NativeQuickPcOffset(cur_quick_frame_pc_); - CodeInfo code_info = outer_code.GetOptimizedCodeInfo(); + const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); + uint32_t native_pc_offset = method_header->NativeQuickPcOffset(cur_quick_frame_pc_); + CodeInfo code_info = method_header->GetOptimizedCodeInfo(); StackMapEncoding encoding = code_info.ExtractEncoding(); StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); DCHECK(stack_map.IsValid()); @@ -142,8 +145,11 @@ uint32_t StackVisitor::GetDexPc(bool abort_on_failure) const { if (IsInInlinedFrame()) { size_t depth_in_stack_map = current_inlining_depth_ - 1; return GetCurrentInlineInfo().GetDexPcAtDepth(depth_in_stack_map); + } else if (cur_oat_quick_method_header_ == nullptr) { + return DexFile::kDexNoIndex; } else { - return GetCurrentCode().ToDexPc(cur_quick_frame_pc_, abort_on_failure); + return cur_oat_quick_method_header_->ToDexPc( + GetMethod(), cur_quick_frame_pc_, abort_on_failure); } } else { return 0; @@ -161,8 +167,7 @@ mirror::Object* StackVisitor::GetThisObject() const { } else if (m->IsNative()) { if (cur_quick_frame_ != nullptr) { HandleScope* hs = reinterpret_cast<HandleScope*>( - reinterpret_cast<char*>(cur_quick_frame_) + - GetCurrentCode().GetHandleScopeOffset().SizeValue()); + reinterpret_cast<char*>(cur_quick_frame_) + sizeof(ArtMethod*)); return hs->GetReference(0); } else { return cur_shadow_frame_->GetVRegReference(0); @@ -192,7 +197,7 @@ mirror::Object* StackVisitor::GetThisObject() const { size_t StackVisitor::GetNativePcOffset() const { DCHECK(!IsShadowFrame()); - return GetCurrentCode().NativeQuickPcOffset(cur_quick_frame_pc_); + return GetCurrentOatQuickMethodHeader()->NativeQuickPcOffset(cur_quick_frame_pc_); } bool StackVisitor::IsReferenceVReg(ArtMethod* m, uint16_t vreg) { @@ -201,10 +206,11 @@ bool StackVisitor::IsReferenceVReg(ArtMethod* m, uint16_t vreg) { if (m->IsNative() || m->IsRuntimeMethod() || m->IsProxyMethod()) { return false; } - if (GetCurrentCode().IsOptimized(sizeof(void*))) { + const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); + if (method_header->IsOptimized()) { return true; // TODO: Implement. } - const uint8_t* native_gc_map = GetCurrentCode().GetNativeGcMap(sizeof(void*)); + const uint8_t* native_gc_map = method_header->GetNativeGcMap(); CHECK(native_gc_map != nullptr) << PrettyMethod(m); const DexFile::CodeItem* code_item = m->GetCodeItem(); // Can't be null or how would we compile its instructions? @@ -213,7 +219,7 @@ bool StackVisitor::IsReferenceVReg(ArtMethod* m, uint16_t vreg) { size_t num_regs = std::min(map.RegWidth() * 8, static_cast<size_t>(code_item->registers_size_)); const uint8_t* reg_bitmap = nullptr; if (num_regs > 0) { - uintptr_t native_pc_offset = GetCurrentCode().NativeQuickPcOffset(GetCurrentQuickFramePc()); + uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc()); reg_bitmap = map.FindBitMap(native_pc_offset); DCHECK(reg_bitmap != nullptr); } @@ -252,7 +258,7 @@ bool StackVisitor::GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* if (GetVRegFromDebuggerShadowFrame(vreg, kind, val)) { return true; } - if (GetCurrentCode().IsOptimized(sizeof(void*))) { + if (cur_oat_quick_method_header_->IsOptimized()) { return GetVRegFromOptimizedCode(m, vreg, kind, val); } else { return GetVRegFromQuickCode(m, vreg, kind, val); @@ -267,8 +273,9 @@ bool StackVisitor::GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* bool StackVisitor::GetVRegFromQuickCode(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const { DCHECK_EQ(m, GetMethod()); - const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*))); - QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo(); + const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); + QuickMethodFrameInfo frame_info = method_header->GetFrameInfo(); + const VmapTable vmap_table(method_header->GetVmapTable()); uint32_t vmap_offset; // TODO: IsInContext stops before spotting floating point registers. if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) { @@ -294,10 +301,11 @@ bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKin // its instructions? uint16_t number_of_dex_registers = code_item->registers_size_; DCHECK_LT(vreg, code_item->registers_size_); - CodeInfo code_info = GetCurrentCode().GetOptimizedCodeInfo(); + const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); + CodeInfo code_info = method_header->GetOptimizedCodeInfo(); StackMapEncoding encoding = code_info.ExtractEncoding(); - uint32_t native_pc_offset = GetCurrentCode().NativeQuickPcOffset(cur_quick_frame_pc_); + uint32_t native_pc_offset = method_header->NativeQuickPcOffset(cur_quick_frame_pc_); StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); DCHECK(stack_map.IsValid()); size_t depth_in_stack_map = current_inlining_depth_ - 1; @@ -402,7 +410,7 @@ bool StackVisitor::GetVRegPair(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, if (cur_quick_frame_ != nullptr) { DCHECK(context_ != nullptr); // You can't reliably read registers without a context. DCHECK(m == GetMethod()); - if (GetCurrentCode().IsOptimized(sizeof(void*))) { + if (cur_oat_quick_method_header_->IsOptimized()) { return GetVRegPairFromOptimizedCode(m, vreg, kind_lo, kind_hi, val); } else { return GetVRegPairFromQuickCode(m, vreg, kind_lo, kind_hi, val); @@ -417,8 +425,9 @@ bool StackVisitor::GetVRegPair(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, bool StackVisitor::GetVRegPairFromQuickCode(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, VRegKind kind_hi, uint64_t* val) const { DCHECK_EQ(m, GetMethod()); - const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*))); - QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo(); + const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); + QuickMethodFrameInfo frame_info = method_header->GetFrameInfo(); + const VmapTable vmap_table(method_header->GetVmapTable()); uint32_t vmap_offset_lo, vmap_offset_hi; // TODO: IsInContext stops before spotting floating point registers. if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) && @@ -477,7 +486,7 @@ bool StackVisitor::SetVReg(ArtMethod* m, uint16_t vreg, uint32_t new_value, if (cur_quick_frame_ != nullptr) { DCHECK(context_ != nullptr); // You can't reliably write registers without a context. DCHECK(m == GetMethod()); - if (GetCurrentCode().IsOptimized(sizeof(void*))) { + if (cur_oat_quick_method_header_->IsOptimized()) { return false; } else { return SetVRegFromQuickCode(m, vreg, new_value, kind); @@ -492,8 +501,9 @@ bool StackVisitor::SetVRegFromQuickCode(ArtMethod* m, uint16_t vreg, uint32_t ne VRegKind kind) { DCHECK(context_ != nullptr); // You can't reliably write registers without a context. DCHECK(m == GetMethod()); - const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*))); - QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo(); + const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); + QuickMethodFrameInfo frame_info = method_header->GetFrameInfo(); + const VmapTable vmap_table(method_header->GetVmapTable()); uint32_t vmap_offset; // TODO: IsInContext stops before spotting floating point registers. if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) { @@ -584,7 +594,7 @@ bool StackVisitor::SetVRegPair(ArtMethod* m, uint16_t vreg, uint64_t new_value, if (cur_quick_frame_ != nullptr) { DCHECK(context_ != nullptr); // You can't reliably write registers without a context. DCHECK(m == GetMethod()); - if (GetCurrentCode().IsOptimized(sizeof(void*))) { + if (cur_oat_quick_method_header_->IsOptimized()) { return false; } else { return SetVRegPairFromQuickCode(m, vreg, new_value, kind_lo, kind_hi); @@ -599,8 +609,9 @@ bool StackVisitor::SetVRegPair(ArtMethod* m, uint16_t vreg, uint64_t new_value, bool StackVisitor::SetVRegPairFromQuickCode( ArtMethod* m, uint16_t vreg, uint64_t new_value, VRegKind kind_lo, VRegKind kind_hi) { DCHECK_EQ(m, GetMethod()); - const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*))); - QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo(); + const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); + QuickMethodFrameInfo frame_info = method_header->GetFrameInfo(); + const VmapTable vmap_table(method_header->GetVmapTable()); uint32_t vmap_offset_lo, vmap_offset_hi; // TODO: IsInContext stops before spotting floating point registers. if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) && @@ -717,14 +728,14 @@ void StackVisitor::SetFPR(uint32_t reg, uintptr_t value) { uintptr_t StackVisitor::GetReturnPc() const { uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame()); DCHECK(sp != nullptr); - uint8_t* pc_addr = sp + GetCurrentCode().GetReturnPcOffset().SizeValue(); + uint8_t* pc_addr = sp + GetCurrentQuickFrameInfo().GetReturnPcOffset(); return *reinterpret_cast<uintptr_t*>(pc_addr); } void StackVisitor::SetReturnPc(uintptr_t new_ret_pc) { uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame()); CHECK(sp != nullptr); - uint8_t* pc_addr = sp + GetCurrentCode().GetReturnPcOffset().SizeValue(); + uint8_t* pc_addr = sp + GetCurrentQuickFrameInfo().GetReturnPcOffset(); *reinterpret_cast<uintptr_t*>(pc_addr) = new_ret_pc; } @@ -821,6 +832,45 @@ static instrumentation::InstrumentationStackFrame& GetInstrumentationStackFrame( return thread->GetInstrumentationStack()->at(depth); } +static void AssertPcIsWithinQuickCode(ArtMethod* method, uintptr_t pc) + SHARED_REQUIRES(Locks::mutator_lock_) { + if (method->IsNative() || method->IsRuntimeMethod() || method->IsProxyMethod()) { + return; + } + + if (pc == reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc())) { + return; + } + + const void* code = method->GetEntryPointFromQuickCompiledCode(); + if (code == GetQuickInstrumentationEntryPoint()) { + return; + } + + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + if (class_linker->IsQuickToInterpreterBridge(code) || + class_linker->IsQuickResolutionStub(code)) { + return; + } + + // If we are the JIT then we may have just compiled the method after the + // IsQuickToInterpreterBridge check. + jit::Jit* const jit = Runtime::Current()->GetJit(); + if (jit != nullptr && + jit->GetCodeCache()->ContainsCodePtr(reinterpret_cast<const void*>(code))) { + return; + } + + uint32_t code_size = reinterpret_cast<const OatQuickMethodHeader*>( + EntryPointToCodePointer(code))[-1].code_size_; + uintptr_t code_start = reinterpret_cast<uintptr_t>(code); + CHECK(code_start <= pc && pc <= (code_start + code_size)) + << PrettyMethod(method) + << " pc=" << std::hex << pc + << " code=" << code + << " size=" << code_size; +} + void StackVisitor::SanityCheckFrame() const { if (kIsDebugBuild) { ArtMethod* method = GetMethod(); @@ -859,9 +909,9 @@ void StackVisitor::SanityCheckFrame() const { } } if (cur_quick_frame_ != nullptr) { - GetCurrentCode().AssertPcIsWithinQuickCode(cur_quick_frame_pc_); + AssertPcIsWithinQuickCode(method, cur_quick_frame_pc_); // Frame sanity. - size_t frame_size = GetCurrentCode().GetFrameSizeInBytes(); + size_t frame_size = GetCurrentQuickFrameInfo().FrameSizeInBytes(); CHECK_NE(frame_size, 0u); // A rough guess at an upper size we expect to see for a frame. // 256 registers @@ -871,13 +921,80 @@ void StackVisitor::SanityCheckFrame() const { // TODO: 083-compiler-regressions ManyFloatArgs shows this estimate is wrong. // const size_t kMaxExpectedFrameSize = (256 + 2 + 3 + 3) * sizeof(word); const size_t kMaxExpectedFrameSize = 2 * KB; - CHECK_LE(frame_size, kMaxExpectedFrameSize); - size_t return_pc_offset = GetCurrentCode().GetReturnPcOffset().SizeValue(); + CHECK_LE(frame_size, kMaxExpectedFrameSize) << PrettyMethod(method); + size_t return_pc_offset = GetCurrentQuickFrameInfo().GetReturnPcOffset(); CHECK_LT(return_pc_offset, frame_size); } } } +// Counts the number of references in the parameter list of the corresponding method. +// Note: Thus does _not_ include "this" for non-static methods. +static uint32_t GetNumberOfReferenceArgsWithoutReceiver(ArtMethod* method) + SHARED_REQUIRES(Locks::mutator_lock_) { + uint32_t shorty_len; + const char* shorty = method->GetShorty(&shorty_len); + uint32_t refs = 0; + for (uint32_t i = 1; i < shorty_len ; ++i) { + if (shorty[i] == 'L') { + refs++; + } + } + return refs; +} + +QuickMethodFrameInfo StackVisitor::GetCurrentQuickFrameInfo() const { + if (cur_oat_quick_method_header_ != nullptr) { + return cur_oat_quick_method_header_->GetFrameInfo(); + } + + ArtMethod* method = GetMethod(); + Runtime* runtime = Runtime::Current(); + + if (method->IsAbstract()) { + return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs); + } + + // This goes before IsProxyMethod since runtime methods have a null declaring class. + if (method->IsRuntimeMethod()) { + return runtime->GetRuntimeMethodFrameInfo(method); + } + + // For Proxy method we add special handling for the direct method case (there is only one + // direct method - constructor). Direct method is cloned from original + // java.lang.reflect.Proxy class together with code and as a result it is executed as usual + // quick compiled method without any stubs. So the frame info should be returned as it is a + // quick method not a stub. However, if instrumentation stubs are installed, the + // instrumentation->GetQuickCodeFor() returns the artQuickProxyInvokeHandler instead of an + // oat code pointer, thus we have to add a special case here. + if (method->IsProxyMethod()) { + if (method->IsDirect()) { + CHECK(method->IsConstructor()); + const void* code_pointer = + EntryPointToCodePointer(method->GetEntryPointFromQuickCompiledCode()); + return reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].frame_info_; + } else { + return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs); + } + } + + ClassLinker* class_linker = runtime->GetClassLinker(); + DCHECK(method->IsNative()); + const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(method, sizeof(void*)); + DCHECK(class_linker->IsQuickGenericJniStub(entry_point)) << PrettyMethod(method); + // Generic JNI frame. + uint32_t handle_refs = GetNumberOfReferenceArgsWithoutReceiver(method) + 1; + size_t scope_size = HandleScope::SizeOf(handle_refs); + QuickMethodFrameInfo callee_info = runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs); + + // Callee saves + handle scope + method ref + alignment + // Note: -sizeof(void*) since callee-save frame stores a whole method pointer. + size_t frame_size = RoundUp( + callee_info.FrameSizeInBytes() - sizeof(void*) + sizeof(ArtMethod*) + scope_size, + kStackAlignment); + return QuickMethodFrameInfo(frame_size, callee_info.CoreSpillMask(), callee_info.FpSpillMask()); +} + void StackVisitor::WalkStack(bool include_transitions) { DCHECK(thread_ == Thread::Current() || thread_->IsSuspended()); CHECK_EQ(cur_depth_, 0U); @@ -890,19 +1007,23 @@ void StackVisitor::WalkStack(bool include_transitions) { cur_shadow_frame_ = current_fragment->GetTopShadowFrame(); cur_quick_frame_ = current_fragment->GetTopQuickFrame(); cur_quick_frame_pc_ = 0; + cur_oat_quick_method_header_ = nullptr; if (cur_quick_frame_ != nullptr) { // Handle quick stack frames. // Can't be both a shadow and a quick fragment. DCHECK(current_fragment->GetTopShadowFrame() == nullptr); ArtMethod* method = *cur_quick_frame_; while (method != nullptr) { + cur_oat_quick_method_header_ = method->GetOatQuickMethodHeader(cur_quick_frame_pc_); SanityCheckFrame(); if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames) - && GetCurrentCode().IsOptimized(sizeof(void*))) { - CodeInfo code_info = GetCurrentCode().GetOptimizedCodeInfo(); + && (cur_oat_quick_method_header_ != nullptr) + && cur_oat_quick_method_header_->IsOptimized()) { + CodeInfo code_info = cur_oat_quick_method_header_->GetOptimizedCodeInfo(); StackMapEncoding encoding = code_info.ExtractEncoding(); - uint32_t native_pc_offset = GetCurrentCode().NativeQuickPcOffset(cur_quick_frame_pc_); + uint32_t native_pc_offset = + cur_oat_quick_method_header_->NativeQuickPcOffset(cur_quick_frame_pc_); StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); if (stack_map.IsValid() && stack_map.HasInlineInfo(encoding)) { InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); @@ -925,14 +1046,16 @@ void StackVisitor::WalkStack(bool include_transitions) { return; } + QuickMethodFrameInfo frame_info = GetCurrentQuickFrameInfo(); if (context_ != nullptr) { - context_->FillCalleeSaves(*this); + context_->FillCalleeSaves(reinterpret_cast<uint8_t*>(cur_quick_frame_), frame_info); } - size_t frame_size = GetCurrentCode().GetFrameSizeInBytes(); // Compute PC for next stack frame from return PC. - size_t return_pc_offset = GetCurrentCode().GetReturnPcOffset().SizeValue(); + size_t frame_size = frame_info.FrameSizeInBytes(); + size_t return_pc_offset = frame_size - sizeof(void*); uint8_t* return_pc_addr = reinterpret_cast<uint8_t*>(cur_quick_frame_) + return_pc_offset; uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr); + if (UNLIKELY(exit_stubs_installed)) { // While profiling, the return pc is restored from the side stack, except when walking // the stack for an exception where the side stack will be unwound in VisitFrame. @@ -963,7 +1086,6 @@ void StackVisitor::WalkStack(bool include_transitions) { return_pc = instrumentation_frame.return_pc_; } } - ArtCode code = GetCurrentCode(); cur_quick_frame_pc_ = return_pc; uint8_t* next_frame = reinterpret_cast<uint8_t*>(cur_quick_frame_) + frame_size; @@ -971,8 +1093,11 @@ void StackVisitor::WalkStack(bool include_transitions) { if (kDebugStackWalk) { LOG(INFO) << PrettyMethod(method) << "@" << method << " size=" << frame_size - << " optimized=" << code.IsOptimized(sizeof(void*)) + << std::boolalpha + << " optimized=" << (cur_oat_quick_method_header_ != nullptr && + cur_oat_quick_method_header_->IsOptimized()) << " native=" << method->IsNative() + << std::noboolalpha << " entrypoints=" << method->GetEntryPointFromQuickCompiledCode() << "," << method->GetEntryPointFromJni() << " next=" << *cur_quick_frame_; diff --git a/runtime/stack.h b/runtime/stack.h index 3e0566d2f0..1f477b6a69 100644 --- a/runtime/stack.h +++ b/runtime/stack.h @@ -20,13 +20,13 @@ #include <stdint.h> #include <string> -#include "art_code.h" #include "arch/instruction_set.h" #include "base/macros.h" #include "base/mutex.h" #include "dex_file.h" #include "gc_root.h" #include "mirror/object_reference.h" +#include "quick/quick_method_frame_info.h" #include "read_barrier.h" #include "verify_object.h" @@ -40,6 +40,7 @@ class ArtMethod; class Context; class HandleScope; class InlineInfo; +class OatQuickMethodHeader; class ScopedObjectAccess; class ShadowFrame; class StackVisitor; @@ -561,18 +562,6 @@ class StackVisitor { size_t GetNativePcOffset() const SHARED_REQUIRES(Locks::mutator_lock_); - uintptr_t* CalleeSaveAddress(int num, size_t frame_size) const - SHARED_REQUIRES(Locks::mutator_lock_) { - // Callee saves are held at the top of the frame - DCHECK(GetMethod() != nullptr); - uint8_t* save_addr = - reinterpret_cast<uint8_t*>(cur_quick_frame_) + frame_size - ((num + 1) * sizeof(void*)); -#if defined(__i386__) || defined(__x86_64__) - save_addr -= sizeof(void*); // account for return address -#endif - return reinterpret_cast<uintptr_t*>(save_addr); - } - // Returns the height of the stack in the managed stack frames, including transitions. size_t GetFrameHeight() SHARED_REQUIRES(Locks::mutator_lock_) { return GetNumFrames() - cur_depth_ - 1; @@ -735,7 +724,11 @@ class StackVisitor { static void DescribeStack(Thread* thread) SHARED_REQUIRES(Locks::mutator_lock_); - ArtCode GetCurrentCode() const { return ArtCode(cur_quick_frame_); } + const OatQuickMethodHeader* GetCurrentOatQuickMethodHeader() const { + return cur_oat_quick_method_header_; + } + + QuickMethodFrameInfo GetCurrentQuickFrameInfo() const SHARED_REQUIRES(Locks::mutator_lock_); private: // Private constructor known in the case that num_frames_ has already been computed. @@ -813,6 +806,7 @@ class StackVisitor { ShadowFrame* cur_shadow_frame_; ArtMethod** cur_quick_frame_; uintptr_t cur_quick_frame_pc_; + const OatQuickMethodHeader* cur_oat_quick_method_header_; // Lazily computed, number of frames in the stack. size_t num_frames_; // Depth of the frame we're currently at. diff --git a/runtime/thread.cc b/runtime/thread.cc index 8e0c288185..114e0f6a9c 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -32,7 +32,6 @@ #include <sstream> #include "arch/context.h" -#include "art_code.h" #include "art_field-inl.h" #include "art_method-inl.h" #include "base/bit_utils.h" @@ -58,6 +57,7 @@ #include "mirror/object_array-inl.h" #include "mirror/stack_trace_element.h" #include "monitor.h" +#include "oat_quick_method_header.h" #include "object_lock.h" #include "quick_exception_handler.h" #include "quick/quick_method_frame_info.h" @@ -1496,8 +1496,7 @@ void Thread::DumpStack(std::ostream& os) const { if (dump_for_abort || ShouldShowNativeStack(this)) { DumpKernelStack(os, GetTid(), " kernel: ", false); ArtMethod* method = GetCurrentMethod(nullptr, !dump_for_abort); - ArtCode art_code(method); - DumpNativeStack(os, GetTid(), " native: ", method, &art_code); + DumpNativeStack(os, GetTid(), " native: ", method); } DumpJavaStack(os); } else { @@ -2640,38 +2639,15 @@ class ReferenceMapVisitor : public StackVisitor { VisitDeclaringClass(m); DCHECK(m != nullptr); size_t num_regs = shadow_frame->NumberOfVRegs(); - if (m->IsNative() || shadow_frame->HasReferenceArray()) { - // handle scope for JNI or References for interpreter. - for (size_t reg = 0; reg < num_regs; ++reg) { - mirror::Object* ref = shadow_frame->GetVRegReference(reg); - if (ref != nullptr) { - mirror::Object* new_ref = ref; - visitor_(&new_ref, reg, this); - if (new_ref != ref) { - shadow_frame->SetVRegReference(reg, new_ref); - } - } - } - } else { - // Java method. - // Portable path use DexGcMap and store in Method.native_gc_map_. - const uint8_t* gc_map = GetCurrentCode().GetNativeGcMap(sizeof(void*)); - CHECK(gc_map != nullptr) << PrettyMethod(m); - verifier::DexPcToReferenceMap dex_gc_map(gc_map); - uint32_t dex_pc = shadow_frame->GetDexPC(); - const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc); - DCHECK(reg_bitmap != nullptr); - num_regs = std::min(dex_gc_map.RegWidth() * 8, num_regs); - for (size_t reg = 0; reg < num_regs; ++reg) { - if (TestBitmap(reg, reg_bitmap)) { - mirror::Object* ref = shadow_frame->GetVRegReference(reg); - if (ref != nullptr) { - mirror::Object* new_ref = ref; - visitor_(&new_ref, reg, this); - if (new_ref != ref) { - shadow_frame->SetVRegReference(reg, new_ref); - } - } + DCHECK(m->IsNative() || shadow_frame->HasReferenceArray()); + // handle scope for JNI or References for interpreter. + for (size_t reg = 0; reg < num_regs; ++reg) { + mirror::Object* ref = shadow_frame->GetVRegReference(reg); + if (ref != nullptr) { + mirror::Object* new_ref = ref; + visitor_(&new_ref, reg, this); + if (new_ref != ref) { + shadow_frame->SetVRegReference(reg, new_ref); } } } @@ -2702,11 +2678,12 @@ class ReferenceMapVisitor : public StackVisitor { // Process register map (which native and runtime methods don't have) if (!m->IsNative() && !m->IsRuntimeMethod() && !m->IsProxyMethod()) { - if (GetCurrentCode().IsOptimized(sizeof(void*))) { + const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); + if (method_header->IsOptimized()) { auto* vreg_base = reinterpret_cast<StackReference<mirror::Object>*>( reinterpret_cast<uintptr_t>(cur_quick_frame)); - uintptr_t native_pc_offset = GetCurrentCode().NativeQuickPcOffset(GetCurrentQuickFramePc()); - CodeInfo code_info = GetCurrentCode().GetOptimizedCodeInfo(); + uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc()); + CodeInfo code_info = method_header->GetOptimizedCodeInfo(); StackMapEncoding encoding = code_info.ExtractEncoding(); StackMap map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); DCHECK(map.IsValid()); @@ -2736,7 +2713,7 @@ class ReferenceMapVisitor : public StackVisitor { } } } else { - const uint8_t* native_gc_map = GetCurrentCode().GetNativeGcMap(sizeof(void*)); + const uint8_t* native_gc_map = method_header->GetNativeGcMap(); CHECK(native_gc_map != nullptr) << PrettyMethod(m); const DexFile::CodeItem* code_item = m->GetCodeItem(); // Can't be null or how would we compile its instructions? @@ -2744,12 +2721,11 @@ class ReferenceMapVisitor : public StackVisitor { NativePcOffsetToReferenceMap map(native_gc_map); size_t num_regs = map.RegWidth() * 8; if (num_regs > 0) { - uintptr_t native_pc_offset = - GetCurrentCode().NativeQuickPcOffset(GetCurrentQuickFramePc()); + uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc()); const uint8_t* reg_bitmap = map.FindBitMap(native_pc_offset); DCHECK(reg_bitmap != nullptr); - const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*))); - QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo(); + const VmapTable vmap_table(method_header->GetVmapTable()); + QuickMethodFrameInfo frame_info = method_header->GetFrameInfo(); // For all dex registers in the bitmap DCHECK(cur_quick_frame != nullptr); for (size_t reg = 0; reg < num_regs; ++reg) { diff --git a/runtime/utils.cc b/runtime/utils.cc index 40cd6d340c..98ccd8e5b7 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -25,7 +25,6 @@ #include <unistd.h> #include <memory> -#include "art_code.h" #include "art_field-inl.h" #include "art_method-inl.h" #include "base/stl_util.h" @@ -37,6 +36,7 @@ #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/string.h" +#include "oat_quick_method_header.h" #include "os.h" #include "scoped_thread_state_change.h" #include "utf-inl.h" @@ -1092,8 +1092,18 @@ static void Addr2line(const std::string& map_src, uintptr_t offset, std::ostream } #endif +static bool PcIsWithinQuickCode(ArtMethod* method, uintptr_t pc) NO_THREAD_SAFETY_ANALYSIS { + uintptr_t code = reinterpret_cast<uintptr_t>(EntryPointToCodePointer( + method->GetEntryPointFromQuickCompiledCode())); + if (code == 0) { + return pc == 0; + } + uintptr_t code_size = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].code_size_; + return code <= pc && pc <= (code + code_size); +} + void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix, - ArtMethod* current_method, ArtCode* current_code, void* ucontext_ptr) { + ArtMethod* current_method, void* ucontext_ptr) { #if __linux__ // b/18119146 if (RUNNING_ON_MEMORY_TOOL != 0) { @@ -1147,10 +1157,10 @@ void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix, os << "+" << it->func_offset; } try_addr2line = true; - } else if ( - current_method != nullptr && Locks::mutator_lock_->IsSharedHeld(Thread::Current()) && - current_code->PcIsWithinQuickCode(it->pc)) { - const void* start_of_code = current_code->GetQuickOatEntryPoint(sizeof(void*)); + } else if (current_method != nullptr && + Locks::mutator_lock_->IsSharedHeld(Thread::Current()) && + PcIsWithinQuickCode(current_method, it->pc)) { + const void* start_of_code = current_method->GetEntryPointFromQuickCompiledCode(); os << JniLongName(current_method) << "+" << (it->pc - reinterpret_cast<uintptr_t>(start_of_code)); } else { diff --git a/runtime/utils.h b/runtime/utils.h index 457d43f312..79502c7971 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -222,7 +222,7 @@ void SetThreadName(const char* thread_name); // Dumps the native stack for thread 'tid' to 'os'. void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix = "", - ArtMethod* current_method = nullptr, ArtCode* current_code = nullptr, void* ucontext = nullptr) + ArtMethod* current_method = nullptr, void* ucontext = nullptr) NO_THREAD_SAFETY_ANALYSIS; // Dumps the kernel stack for thread 'tid' to 'os'. Note that this is only available on linux-x86. diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc index f8d321cbec..34fb3f8a01 100644 --- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc +++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc @@ -19,15 +19,17 @@ namespace art { -#define CHECK_REGS_CONTAIN_REFS(dex_pc, abort_if_not_found, ...) do { \ - int t[] = {__VA_ARGS__}; \ - int t_size = sizeof(t) / sizeof(*t); \ - uintptr_t native_quick_pc = GetCurrentCode().ToNativeQuickPc(dex_pc, \ - /* is_catch_handler */ false, \ - abort_if_not_found); \ - if (native_quick_pc != UINTPTR_MAX) { \ - CheckReferences(t, t_size, GetCurrentCode().NativeQuickPcOffset(native_quick_pc)); \ - } \ +#define CHECK_REGS_CONTAIN_REFS(dex_pc, abort_if_not_found, ...) do { \ + int t[] = {__VA_ARGS__}; \ + int t_size = sizeof(t) / sizeof(*t); \ + const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); \ + uintptr_t native_quick_pc = method_header->ToNativeQuickPc(GetMethod(), \ + dex_pc, \ + /* is_catch_handler */ false, \ + abort_if_not_found); \ + if (native_quick_pc != UINTPTR_MAX) { \ + CheckReferences(t, t_size, method_header->NativeQuickPcOffset(native_quick_pc)); \ + } \ } while (false); struct ReferenceMap2Visitor : public CheckReferenceMapVisitor { @@ -49,7 +51,7 @@ struct ReferenceMap2Visitor : public CheckReferenceMapVisitor { CHECK_REGS_CONTAIN_REFS(0x06U, true, 8, 1); // v8: this, v1: x CHECK_REGS_CONTAIN_REFS(0x08U, true, 8, 3, 1); // v8: this, v3: y, v1: x CHECK_REGS_CONTAIN_REFS(0x0cU, true, 8, 3, 1); // v8: this, v3: y, v1: x - if (!GetCurrentCode().IsOptimized(sizeof(void*))) { + if (!GetCurrentOatQuickMethodHeader()->IsOptimized()) { CHECK_REGS_CONTAIN_REFS(0x0eU, true, 8, 3, 1); // v8: this, v3: y, v1: x } CHECK_REGS_CONTAIN_REFS(0x10U, true, 8, 3, 1); // v8: this, v3: y, v1: x @@ -65,7 +67,7 @@ struct ReferenceMap2Visitor : public CheckReferenceMapVisitor { // Note that v0: ex can be eliminated because it's a dead merge of two different exceptions. CHECK_REGS_CONTAIN_REFS(0x18U, true, 8, 2, 1); // v8: this, v2: y, v1: x (dead v0: ex) CHECK_REGS_CONTAIN_REFS(0x1aU, true, 8, 5, 2, 1); // v8: this, v5: x[1], v2: y, v1: x (dead v0: ex) - if (!GetCurrentCode().IsOptimized(sizeof(void*))) { + if (!GetCurrentOatQuickMethodHeader()->IsOptimized()) { // v8: this, v5: x[1], v2: y, v1: x (dead v0: ex) CHECK_REGS_CONTAIN_REFS(0x1dU, true, 8, 5, 2, 1); // v5 is removed from the root set because there is a "merge" operation. @@ -74,7 +76,7 @@ struct ReferenceMap2Visitor : public CheckReferenceMapVisitor { } CHECK_REGS_CONTAIN_REFS(0x21U, true, 8, 2, 1); // v8: this, v2: y, v1: x (dead v0: ex) - if (!GetCurrentCode().IsOptimized(sizeof(void*))) { + if (!GetCurrentOatQuickMethodHeader()->IsOptimized()) { CHECK_REGS_CONTAIN_REFS(0x27U, true, 8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x } CHECK_REGS_CONTAIN_REFS(0x29U, true, 8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x diff --git a/test/454-get-vreg/get_vreg_jni.cc b/test/454-get-vreg/get_vreg_jni.cc index 0ee2ff9fda..30f99542a1 100644 --- a/test/454-get-vreg/get_vreg_jni.cc +++ b/test/454-get-vreg/get_vreg_jni.cc @@ -15,9 +15,9 @@ */ #include "arch/context.h" -#include "art_code.h" #include "art_method-inl.h" #include "jni.h" +#include "oat_quick_method_header.h" #include "scoped_thread_state_change.h" #include "stack.h" #include "thread.h" @@ -46,12 +46,12 @@ class TestVisitor : public StackVisitor { CHECK_EQ(value, 42u); bool success = GetVReg(m, 1, kIntVReg, &value); - if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) { + if (!IsCurrentFrameInInterpreter() && GetCurrentOatQuickMethodHeader()->IsOptimized()) { CHECK(!success); } success = GetVReg(m, 2, kIntVReg, &value); - if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) { + if (!IsCurrentFrameInInterpreter() && GetCurrentOatQuickMethodHeader()->IsOptimized()) { CHECK(!success); } @@ -83,12 +83,12 @@ class TestVisitor : public StackVisitor { CHECK_EQ(value, 42u); bool success = GetVRegPair(m, 2, kLongLoVReg, kLongHiVReg, &value); - if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) { + if (!IsCurrentFrameInInterpreter() && GetCurrentOatQuickMethodHeader()->IsOptimized()) { CHECK(!success); } success = GetVRegPair(m, 4, kLongLoVReg, kLongHiVReg, &value); - if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) { + if (!IsCurrentFrameInInterpreter() && GetCurrentOatQuickMethodHeader()->IsOptimized()) { CHECK(!success); } diff --git a/test/457-regs/regs_jni.cc b/test/457-regs/regs_jni.cc index 6fcebdb8b5..64b2336bee 100644 --- a/test/457-regs/regs_jni.cc +++ b/test/457-regs/regs_jni.cc @@ -15,9 +15,9 @@ */ #include "arch/context.h" -#include "art_code.h" #include "art_method-inl.h" #include "jni.h" +#include "oat_quick_method_header.h" #include "scoped_thread_state_change.h" #include "stack.h" #include "thread.h" @@ -64,7 +64,7 @@ class TestVisitor : public StackVisitor { CHECK_EQ(value, 1u); bool success = GetVReg(m, 2, kIntVReg, &value); - if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) { + if (!IsCurrentFrameInInterpreter() && GetCurrentOatQuickMethodHeader()->IsOptimized()) { CHECK(!success); } diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc index 2a56a7fce7..375a3fc824 100644 --- a/test/466-get-live-vreg/get_live_vreg_jni.cc +++ b/test/466-get-live-vreg/get_live_vreg_jni.cc @@ -15,9 +15,9 @@ */ #include "arch/context.h" -#include "art_code.h" #include "art_method-inl.h" #include "jni.h" +#include "oat_quick_method_header.h" #include "scoped_thread_state_change.h" #include "stack.h" #include "thread.h" @@ -44,7 +44,7 @@ class TestVisitor : public StackVisitor { found_method_ = true; uint32_t value = 0; if (GetCurrentQuickFrame() != nullptr && - GetCurrentCode().IsOptimized(sizeof(void*)) && + GetCurrentOatQuickMethodHeader()->IsOptimized() && !Runtime::Current()->IsDebuggable()) { CHECK_EQ(GetVReg(m, 0, kIntVReg, &value), false); } else { |