#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"
#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"
#include "mirror/array-inl.h"
#include "mirror/string.h"
#include "oat.h"
+#include "oat_quick_method_header.h"
#include "x86_lir.h"
namespace art {
#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"
#include "compiled_method.h"
#include "oat.h"
+#include "oat_quick_method_header.h"
#include "output_stream.h"
namespace art {
#include "linker/relative_patcher_test.h"
#include "linker/arm/relative_patcher_thumb2.h"
+#include "oat_quick_method_header.h"
namespace art {
namespace linker {
#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 {
#include "linker/relative_patcher_test.h"
#include "linker/arm64/relative_patcher_arm64.h"
+#include "oat_quick_method_header.h"
namespace art {
namespace linker {
#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"
#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"
#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"
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);
} 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;
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;
}
include art/build/Android.common_build.mk
LIBART_COMMON_SRC_FILES := \
- art_code.cc \
art_field.cc \
art_method.cc \
atomic.cc.arm \
oat_file.cc \
oat_file_assistant.cc \
oat_file_manager.cc \
+ oat_quick_method_header.cc \
object_lock.cc \
offsets.cc \
os_linux.cc \
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;
#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 {
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()));
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);
#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 {
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()));
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);
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.
// 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;
#include "context_mips.h"
-#include "art_method-inl.h"
#include "base/bit_utils.h"
#include "quick/quick_method_frame_info.h"
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()));
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);
#include "context_mips64.h"
-#include "art_method-inl.h"
#include "base/bit_utils.h"
#include "quick/quick_method_frame_info.h"
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()));
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);
#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 {
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.
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);
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,
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);
#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 {
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.
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);
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,
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);
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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_
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
namespace art {
union JValue;
+class OatQuickMethodHeader;
class ProfilingInfo;
class ScopedObjectAccessAlreadyRunnable;
class StringPiece;
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.
#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"
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);
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_;
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) {
#include "entrypoints/entrypoint_utils.h"
-#include "art_code.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/mutex.h"
#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"
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;
}
}
}
#include <jni.h>
#include <stdint.h>
-#include "art_code.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "dex_instruction.h"
class ArtField;
class ArtMethod;
+class OatQuickMethodHeader;
class ScopedObjectAccessAlreadyRunnable;
class Thread;
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_
* limitations under the License.
*/
-#include "art_code.h"
#include "art_method-inl.h"
#include "callee_save_frame.h"
#include "common_throws.h"
#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"
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 +
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());
return stack_map.GetDexPc(encoding);
}
} else {
- return GetCallingCodeFrom(caller_sp).ToDexPc(outer_pc);
+ return current_code->ToDexPc(*caller_sp, outer_pc);
}
}
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();
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;
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;
#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"
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));
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_));
#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"
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;
}
#include <sstream>
#include "arch/context.h"
-#include "art_code.h"
#include "art_method-inl.h"
#include "atomic.h"
#include "class_linker.h"
#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"
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.
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
#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 {
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_
#define ART_RUNTIME_OAT_FILE_INL_H_
#include "oat_file.h"
+#include "oat_quick_method_header.h"
namespace art {
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_
return fp_spill_mask_;
}
+ size_t GetReturnPcOffset() const {
+ return FrameSizeInBytes() - sizeof(void*);
+ }
+
private:
uint32_t frame_size_in_bytes_;
uint32_t core_spill_mask_;
#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"
#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"
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 {
// 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);
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?
}
// 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);
}
}
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.
// 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
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;
}
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.
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
#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"
#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"
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),
}
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());
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;
} 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);
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) {
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?
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);
}
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);
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)) {
// 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;
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);
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) &&
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);
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)) {
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);
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) &&
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;
}
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();
}
}
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
// 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);
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);
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.
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;
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_;
#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"
class Context;
class HandleScope;
class InlineInfo;
+class OatQuickMethodHeader;
class ScopedObjectAccess;
class ShadowFrame;
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;
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.
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.
#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"
#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"
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 {
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);
}
}
}
// 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());
}
}
} 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?
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) {
#include <unistd.h>
#include <memory>
-#include "art_code.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/stl_util.h"
#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"
}
#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) {
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 {
// 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.
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 {
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
// 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.
}
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
*/
#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"
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);
}
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);
}
*/
#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"
CHECK_EQ(value, 1u);
bool success = GetVReg(m, 2, kIntVReg, &value);
- if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (!IsCurrentFrameInInterpreter() && GetCurrentOatQuickMethodHeader()->IsOptimized()) {
CHECK(!success);
}
*/
#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"
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 {