summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSameer Abu Asal <sasal@google.com>2013-04-29 11:31:03 -0700
committerSameer Abu Asal <sasal@google.com>2013-04-29 13:06:07 -0700
commit31d4b8e0058b33e2c5ce792a69e5e897583652e2 (patch)
tree8b981aa8c0dcb2e540f5ba26951302f720299f8e /src
parent88fc036842eb3c48acd5d3b01e75b3012c996d90 (diff)
downloadart-31d4b8e0058b33e2c5ce792a69e5e897583652e2.tar.gz
art-31d4b8e0058b33e2c5ce792a69e5e897583652e2.tar.bz2
art-31d4b8e0058b33e2c5ce792a69e5e897583652e2.zip
Supporting de-virtualization for precise types.
Sharpening invoke-virtual and invoke-interface calls to invoke-direct for cases where the type of "this" pointer in the invoke- params is precisely known. Instructions that have an invoke opcode are marked as interesting, for each invoke-virtual/interface we come across with a precise type for "this" we mark the location as a candidate for sharpening, resolve the concrete method and save its method reference <DexFile, DexMethodIndex> to be sharpened in CompilerDriver::ComputeInvokeInfo(). Added a new entry to AOT statistics showing the percentage of sharpened calls that were based on type analysis. Fix a minor bug in type creation for GetSuperClass(). Previously super class of a precise reference had precise types created which is not necessarily the case. Fixed DCHECK in Class::FindVirtualMethodForVirtual to handle cases for Miranda methods. Change-Id: I0626d5cd1bc70a685db71abec067370ebdaf6edc
Diffstat (limited to 'src')
-rw-r--r--src/compiler/dex/mir_dataflow.cc10
-rw-r--r--src/compiler/dex/quick/gen_invoke.cc2
-rw-r--r--src/compiler/driver/compiler_driver.cc51
-rw-r--r--src/compiler/driver/compiler_driver.h7
-rw-r--r--src/compiler/llvm/gbc_expander.cc4
-rw-r--r--src/mirror/class-inl.h2
-rw-r--r--src/verifier/instruction_flags.cc2
-rw-r--r--src/verifier/instruction_flags.h16
-rw-r--r--src/verifier/method_verifier.cc138
-rw-r--r--src/verifier/method_verifier.h16
-rw-r--r--src/verifier/reg_type.cc5
11 files changed, 221 insertions, 32 deletions
diff --git a/src/compiler/dex/mir_dataflow.cc b/src/compiler/dex/mir_dataflow.cc
index 23bf24889..444874dce 100644
--- a/src/compiler/dex/mir_dataflow.cc
+++ b/src/compiler/dex/mir_dataflow.cc
@@ -1249,11 +1249,13 @@ bool MIRGraph::InvokeUsesMethodStar(MIR* mir)
int vtable_idx;
uintptr_t direct_code;
uintptr_t direct_method;
+ uint32_t current_offset = static_cast<uint32_t>(current_offset_);
bool fast_path =
- cu_->compiler_driver->ComputeInvokeInfo(dex_method_idx, &m_unit, type,
- vtable_idx, direct_code,
- direct_method) &&
- !(cu_->enable_debug & (1 << kDebugSlowInvokePath));
+ cu_->compiler_driver->ComputeInvokeInfo(dex_method_idx, current_offset,
+ &m_unit, type,
+ vtable_idx, direct_code,
+ direct_method) &&
+ !(cu_->enable_debug & (1 << kDebugSlowInvokePath));
return (((type == kDirect) || (type == kStatic)) &&
fast_path && ((direct_code == 0) || (direct_method == 0)));
}
diff --git a/src/compiler/dex/quick/gen_invoke.cc b/src/compiler/dex/quick/gen_invoke.cc
index 2eab673e2..efacff0ab 100644
--- a/src/compiler/dex/quick/gen_invoke.cc
+++ b/src/compiler/dex/quick/gen_invoke.cc
@@ -1329,7 +1329,7 @@ void Mir2Lir::GenInvoke(CallInfo* info)
uintptr_t direct_method;
bool skip_this;
bool fast_path = cu_->compiler_driver->ComputeInvokeInfo(
- dex_method_idx, mir_graph_->GetCurrentDexCompilationUnit(), info->type, vtable_idx,
+ dex_method_idx, current_dalvik_offset_, mir_graph_->GetCurrentDexCompilationUnit(), info->type, vtable_idx,
direct_code, direct_method) && !SLOW_INVOKE_PATH;
if (info->type == kInterface) {
if (fast_path) {
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index 1660914ce..bed9ac141 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -71,7 +71,8 @@ class AOTCompilationStats {
strings_in_dex_cache_(0), strings_not_in_dex_cache_(0),
resolved_types_(0), unresolved_types_(0),
resolved_instance_fields_(0), unresolved_instance_fields_(0),
- resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0) {
+ resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0),
+ type_based_devirtualization_(0) {
for (size_t i = 0; i <= kMaxInvokeType; i++) {
resolved_methods_[i] = 0;
unresolved_methods_[i] = 0;
@@ -90,6 +91,8 @@ class AOTCompilationStats {
"static fields resolved");
DumpStat(resolved_local_static_fields_, resolved_static_fields_ + unresolved_static_fields_,
"static fields local to a class");
+ DumpStat(type_based_devirtualization_,virtual_made_direct_[kInterface] + virtual_made_direct_[kVirtual]
+ - type_based_devirtualization_, "sharpened calls based on type information");
for (size_t i = 0; i <= kMaxInvokeType; i++) {
std::ostringstream oss;
@@ -181,6 +184,11 @@ class AOTCompilationStats {
unresolved_static_fields_++;
}
+ void PreciseTypeDevirtualization() {
+ STATS_LOCK();
+ type_based_devirtualization_++;
+ }
+
void ResolvedMethod(InvokeType type) {
DCHECK_LE(type, kMaxInvokeType);
STATS_LOCK();
@@ -229,6 +237,8 @@ class AOTCompilationStats {
size_t resolved_local_static_fields_;
size_t resolved_static_fields_;
size_t unresolved_static_fields_;
+ // Type based devirtualization for invoke interface and virtual.
+ size_t type_based_devirtualization_;
size_t resolved_methods_[kMaxInvokeType + 1];
size_t unresolved_methods_[kMaxInvokeType + 1];
@@ -805,15 +815,24 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s
}
}
-bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx, const DexCompilationUnit* mUnit,
- InvokeType& type, int& vtable_idx, uintptr_t& direct_code,
+bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx,const uint32_t dex_pc,
+ const DexCompilationUnit* mUnit, InvokeType& type,
+ int& vtable_idx, uintptr_t& direct_code,
uintptr_t& direct_method) {
ScopedObjectAccess soa(Thread::Current());
+
+ const bool kEnableVerifierBasedSharpening = true;
+ const CompilerDriver::MethodReference ref_caller(mUnit->GetDexFile(), mUnit->GetDexMethodIndex());
+ const CompilerDriver::MethodReference* ref_sharpen = verifier::MethodVerifier::GetDevirtMap(ref_caller, dex_pc);
+ bool can_devirtualize = (dex_pc != art::kDexPCNotReady) && (ref_sharpen != NULL);
+
vtable_idx = -1;
direct_code = 0;
direct_method = 0;
mirror::AbstractMethod* resolved_method =
ComputeMethodReferencedFromCompilingMethod(soa, mUnit, method_idx, type);
+
+
if (resolved_method != NULL) {
// Don't try to fast-path if we don't understand the caller's class or this appears to be an
// Incompatible Class Change Error.
@@ -836,8 +855,10 @@ bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx, const DexCompilation
}
if (referrer_class->CanAccess(methods_class) &&
referrer_class->CanAccessMember(methods_class, resolved_method->GetAccessFlags())) {
+
vtable_idx = resolved_method->GetMethodIndex();
const bool kEnableSharpening = true;
+
// Sharpen a virtual call into a direct call when the target is known.
bool can_sharpen = type == kVirtual && (resolved_method->IsFinal() ||
methods_class->IsFinal());
@@ -846,6 +867,7 @@ bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx, const DexCompilation
referrer_class->IsSubClass(methods_class) &&
vtable_idx < methods_class->GetVTable()->GetLength() &&
methods_class->GetVTable()->Get(vtable_idx) == resolved_method);
+
if (kEnableSharpening && can_sharpen) {
stats_->ResolvedMethod(type);
// Sharpen a virtual call into a direct call. The method_idx is into referrer's
@@ -857,7 +879,28 @@ bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx, const DexCompilation
direct_code, direct_method);
type = kDirect;
return true;
- } else if (type == kSuper) {
+
+ } else if(can_devirtualize && kEnableSharpening && kEnableVerifierBasedSharpening) {
+ // If traditional sharpening fails, try the sharpening based on type information (Devirtualization)
+ mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*ref_sharpen->first);
+ mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
+ mirror::AbstractMethod* concrete_method = mUnit->GetClassLinker()->ResolveMethod(
+ *ref_sharpen->first, ref_sharpen->second, dex_cache, class_loader, NULL, kVirtual);
+ CHECK(concrete_method != NULL);
+ CHECK(!concrete_method->IsAbstract());
+ // TODO: fix breakage in image patching to be able to devirtualize cases with different
+ // resolved and concrete methods.
+ if(resolved_method == concrete_method) {
+ GetCodeAndMethodForDirectCall(type, kDirect, referrer_class, concrete_method, direct_code, direct_method);
+ type = kDirect;
+ stats_->VirtualMadeDirect(type);
+ stats_->PreciseTypeDevirtualization();
+ }
+ stats_->ResolvedMethod(type);
+
+ return true;
+ }
+ else if (type == kSuper) {
// Unsharpened super calls are suspicious so go slow-path.
} else {
stats_->ResolvedMethod(type);
diff --git a/src/compiler/driver/compiler_driver.h b/src/compiler/driver/compiler_driver.h
index a20e5ef58..e28955827 100644
--- a/src/compiler/driver/compiler_driver.h
+++ b/src/compiler/driver/compiler_driver.h
@@ -39,6 +39,8 @@ class ParallelCompilationManager;
class DexCompilationUnit;
class TimingLogger;
+const uint32_t kDexPCNotReady = 0xFFFFFF;
+
enum CompilerBackend {
kQuick,
kPortable,
@@ -149,8 +151,9 @@ class CompilerDriver {
// Can we fastpath a interface, super class or virtual method call? Computes method's vtable
// index.
- bool ComputeInvokeInfo(uint32_t method_idx, const DexCompilationUnit* mUnit, InvokeType& type,
- int& vtable_idx, uintptr_t& direct_code, uintptr_t& direct_method)
+ bool ComputeInvokeInfo(uint32_t method_idx, uint32_t dex_pc,
+ const DexCompilationUnit* mUnit, InvokeType& type, int& vtable_idx,
+ uintptr_t& direct_code, uintptr_t& direct_method)
LOCKS_EXCLUDED(Locks::mutator_lock_);
// Record patch information for later fix up.
diff --git a/src/compiler/llvm/gbc_expander.cc b/src/compiler/llvm/gbc_expander.cc
index 94eb74103..c1e35a69a 100644
--- a/src/compiler/llvm/gbc_expander.cc
+++ b/src/compiler/llvm/gbc_expander.cc
@@ -785,8 +785,10 @@ llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) {
int vtable_idx = -1;
uintptr_t direct_code = 0;
uintptr_t direct_method = 0;
+ // TODO: pass actual value of dex PC (instead of kDexPCNotready) needed by verifier based
+ // sharpening after LLVM re-factoring is finished.
bool is_fast_path = driver_->
- ComputeInvokeInfo(callee_method_idx, dex_compilation_unit_,
+ ComputeInvokeInfo(callee_method_idx, art::kDexPCNotReady, dex_compilation_unit_,
invoke_type, vtable_idx, direct_code, direct_method);
// Load the method object
diff --git a/src/mirror/class-inl.h b/src/mirror/class-inl.h
index d7afed6cd..62740bed2 100644
--- a/src/mirror/class-inl.h
+++ b/src/mirror/class-inl.h
@@ -225,7 +225,7 @@ inline AbstractMethod* Class::FindVirtualMethodForInterface(AbstractMethod* meth
inline AbstractMethod* Class::FindVirtualMethodForVirtual(AbstractMethod* method) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK(!method->GetDeclaringClass()->IsInterface());
+ DCHECK(!method->GetDeclaringClass()->IsInterface() || method->IsMiranda());
// The argument method may from a super class.
// Use the index to a potentially overridden one for this instance's class.
return GetVTable()->Get(method->GetMethodIndex());
diff --git a/src/verifier/instruction_flags.cc b/src/verifier/instruction_flags.cc
index 823edde9f..358791ddf 100644
--- a/src/verifier/instruction_flags.cc
+++ b/src/verifier/instruction_flags.cc
@@ -29,7 +29,7 @@ std::string InstructionFlags::ToString() const {
strncpy(encoding, "-----", sizeof(encoding));
if (IsInTry()) encoding[kInTry] = 'T';
if (IsBranchTarget()) encoding[kBranchTarget] = 'B';
- if (IsGcPoint()) encoding[kGcPoint] = 'G';
+ if (IsCompileTimeInfoPoint()) encoding[kCompileTimeInfoPoint] = 'G';
if (IsVisited()) encoding[kVisited] = 'V';
if (IsChanged()) encoding[kChanged] = 'C';
}
diff --git a/src/verifier/instruction_flags.h b/src/verifier/instruction_flags.h
index 7f0d24041..9dc3ea7a7 100644
--- a/src/verifier/instruction_flags.h
+++ b/src/verifier/instruction_flags.h
@@ -59,15 +59,14 @@ class InstructionFlags {
bool IsBranchTarget() const {
return (flags_ & (1 << kBranchTarget)) != 0;
}
-
- void SetGcPoint() {
- flags_ |= 1 << kGcPoint;
+ void SetCompileTimeInfoPoint() {
+ flags_ |= 1 << kCompileTimeInfoPoint;
}
- void ClearGcPoint() {
- flags_ &= ~(1 << kGcPoint);
+ void ClearCompileTimeInfoPoint() {
+ flags_ &= ~(1 << kCompileTimeInfoPoint);
}
- bool IsGcPoint() const {
- return (flags_ & (1 << kGcPoint)) != 0;
+ bool IsCompileTimeInfoPoint() const {
+ return (flags_ & (1 << kCompileTimeInfoPoint)) != 0;
}
void SetVisited() {
@@ -100,7 +99,8 @@ class InstructionFlags {
enum {
kInTry,
kBranchTarget,
- kGcPoint,
+ kCompileTimeInfoPoint, // Location of interest to the compiler for GC maps and
+ // verifier based method sharpening.
kVisited,
kChanged,
};
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 2b70e265d..a3132df7a 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -56,8 +56,8 @@ void PcToRegisterLineTable::Init(RegisterTrackingMode mode, InstructionFlags* fl
case kTrackRegsAll:
interesting = flags[i].IsOpcode();
break;
- case kTrackRegsGcPoints:
- interesting = flags[i].IsGcPoint() || flags[i].IsBranchTarget();
+ case kTrackCompilerInterestPoints:
+ interesting = flags[i].IsCompileTimeInfoPoint() || flags[i].IsBranchTarget() ;
break;
case kTrackRegsBranches:
interesting = flags[i].IsBranchTarget();
@@ -496,7 +496,7 @@ bool MethodVerifier::VerifyInstructions() {
/* Flag the start of the method as a branch target, and a GC point due to stack overflow errors */
insn_flags_[0].SetBranchTarget();
- insn_flags_[0].SetGcPoint();
+ insn_flags_[0].SetCompileTimeInfoPoint();
uint32_t insns_size = code_item_->insns_size_in_code_units_;
for (uint32_t dex_pc = 0; dex_pc < insns_size;) {
@@ -505,8 +505,10 @@ bool MethodVerifier::VerifyInstructions() {
return false;
}
/* Flag instructions that are garbage collection points */
+ // All invoke points are marked as "Throw" points already.
+ // We are relying on this to also count all the invokes as interesting.
if (inst->IsBranch() || inst->IsSwitch() || inst->IsThrow() || inst->IsReturn()) {
- insn_flags_[dex_pc].SetGcPoint();
+ insn_flags_[dex_pc].SetCompileTimeInfoPoint();
}
dex_pc += inst->SizeInCodeUnits();
inst = inst->Next();
@@ -918,7 +920,8 @@ bool MethodVerifier::VerifyCodeFlow() {
<< " insns_size=" << insns_size << ")";
}
/* Create and initialize table holding register status */
- reg_table_.Init(kTrackRegsGcPoints, insn_flags_.get(), insns_size, registers_size, this);
+ reg_table_.Init(kTrackCompilerInterestPoints, insn_flags_.get(), insns_size, registers_size, this);
+
work_line_.reset(new RegisterLine(registers_size, this));
saved_line_.reset(new RegisterLine(registers_size, this));
@@ -952,6 +955,10 @@ bool MethodVerifier::VerifyCodeFlow() {
const std::vector<uint8_t>* dex_gc_map = CreateLengthPrefixedDexGcMap(*(map.get()));
verifier::MethodVerifier::SetDexGcMap(ref, *dex_gc_map);
+ MethodVerifier::PcToConreteMethod* pc_to_conrete_method = GenerateDevirtMap();
+ if(pc_to_conrete_method != NULL ) {
+ SetDevirtMap(ref, pc_to_conrete_method);
+ }
return true;
}
@@ -3137,7 +3144,7 @@ void MethodVerifier::ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bit
size_t max_insn = 0;
size_t max_ref_reg = -1;
for (size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) {
- if (insn_flags_[i].IsGcPoint()) {
+ if (insn_flags_[i].IsCompileTimeInfoPoint()) {
local_gc_points++;
max_insn = i;
RegisterLine* line = reg_table_.GetLine(i);
@@ -3153,6 +3160,72 @@ void MethodVerifier::ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bit
*log2_max_gc_pc = i;
}
+MethodVerifier::PcToConreteMethod* MethodVerifier::GenerateDevirtMap() {
+
+ PcToConreteMethod* pc_to_concrete_method = new PcToConreteMethod();
+ uint32_t dex_pc = 0;
+ const uint16_t* insns = code_item_->insns_ ;
+ const Instruction* inst = Instruction::At(insns);
+
+ for (; dex_pc < code_item_->insns_size_in_code_units_;
+ dex_pc += insn_flags_[dex_pc].GetLengthInCodeUnits(), inst = inst->Next()) {
+
+ bool is_virtual = (inst->Opcode() == Instruction::INVOKE_VIRTUAL) ||
+ (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE);
+ bool is_interface = (inst->Opcode() == Instruction::INVOKE_INTERFACE) ||
+ (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
+
+ if(!(is_interface || is_virtual))
+ continue;
+
+ // Check if vC ("this" pointer in the instruction) has a precise type.
+ RegisterLine* line = reg_table_.GetLine(dex_pc);
+ DecodedInstruction dec_insn(inst);
+ const RegType& reg_type(line->GetRegisterType(dec_insn.vC));
+
+ if (!reg_type.IsPreciseReference()) {
+ continue;
+ }
+
+ CHECK(!(reg_type.GetClass()->IsInterface()));
+ // If the class is an array class, it can be both Abstract and final and so
+ // the reg_type will be created as precise.
+ CHECK(!(reg_type.GetClass()->IsAbstract()) || reg_type.GetClass()->IsArrayClass());
+ // Find the abstract method.
+ // vB has the method index.
+ mirror::AbstractMethod* abstract_method = NULL ;
+ abstract_method = dex_cache_->GetResolvedMethod(dec_insn.vB);
+ if(abstract_method == NULL) {
+ // If the method is not found in the cache this means that it was never found
+ // by ResolveMethodAndCheckAccess() called when verifying invoke_*.
+ continue;
+ }
+ // Find the concrete method.
+ mirror::AbstractMethod* concrete_method = NULL;
+ if (is_interface) {
+ concrete_method = reg_type.GetClass()->FindVirtualMethodForInterface(abstract_method);
+ }
+ if (is_virtual) {
+ concrete_method = reg_type.GetClass()->FindVirtualMethodForVirtual(abstract_method);
+ }
+ CHECK(concrete_method != NULL);
+ CHECK(!concrete_method->IsAbstract()) << PrettyMethod(concrete_method);
+ // Build method reference.
+ CompilerDriver::MethodReference concrete_ref(
+ concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
+ concrete_method->GetDexMethodIndex());
+ // Now Save the current PC and the concrete method reference to be used
+ // in compiler driver.
+ pc_to_concrete_method->Put(dex_pc, concrete_ref );
+ }
+
+ if (pc_to_concrete_method->size() == 0) {
+ delete pc_to_concrete_method;
+ return NULL ;
+ }
+ return pc_to_concrete_method;
+}
+
const std::vector<uint8_t>* MethodVerifier::GenerateGcMap() {
size_t num_entries, ref_bitmap_bits, pc_bits;
ComputeGcMapSizes(&num_entries, &ref_bitmap_bits, &pc_bits);
@@ -3199,7 +3272,7 @@ const std::vector<uint8_t>* MethodVerifier::GenerateGcMap() {
table->push_back((num_entries >> 8) & 0xFF);
// Write table data
for (size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) {
- if (insn_flags_[i].IsGcPoint()) {
+ if (insn_flags_[i].IsCompileTimeInfoPoint()) {
table->push_back(i & 0xFF);
if (pc_bytes == 2) {
table->push_back((i >> 8) & 0xFF);
@@ -3219,7 +3292,7 @@ void MethodVerifier::VerifyGcMap(const std::vector<uint8_t>& data) {
size_t map_index = 0;
for (size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) {
const uint8_t* reg_bitmap = map.FindBitMap(i, false);
- if (insn_flags_[i].IsGcPoint()) {
+ if (insn_flags_[i].IsCompileTimeInfoPoint()) {
CHECK_LT(map_index, map.NumEntries());
CHECK_EQ(map.GetDexPc(map_index), i);
CHECK_EQ(map.GetBitMap(map_index), reg_bitmap);
@@ -3254,6 +3327,21 @@ void MethodVerifier::SetDexGcMap(CompilerDriver::MethodReference ref, const std:
CHECK(GetDexGcMap(ref) != NULL);
}
+
+void MethodVerifier::SetDevirtMap(CompilerDriver::MethodReference ref, const PcToConreteMethod* devirt_map) {
+
+ MutexLock mu(Thread::Current(), *devirt_maps_lock_);
+ DevirtualizationMapTable::iterator it = devirt_maps_->find(ref);
+ if (it != devirt_maps_->end()) {
+ delete it->second;
+ devirt_maps_->erase(it);
+ }
+
+ devirt_maps_->Put(ref, devirt_map);
+ CHECK(devirt_maps_->find(ref) != devirt_maps_->end());
+}
+
+
const std::vector<uint8_t>* MethodVerifier::GetDexGcMap(CompilerDriver::MethodReference ref) {
MutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
DexGcMapTable::const_iterator it = dex_gc_maps_->find(ref);
@@ -3265,6 +3353,22 @@ const std::vector<uint8_t>* MethodVerifier::GetDexGcMap(CompilerDriver::MethodRe
return it->second;
}
+const CompilerDriver::MethodReference* MethodVerifier::GetDevirtMap(CompilerDriver::MethodReference ref, uint32_t pc) {
+ MutexLock mu(Thread::Current(), *devirt_maps_lock_);
+ DevirtualizationMapTable::const_iterator it = devirt_maps_->find(ref);
+ if (it == devirt_maps_->end()) {
+ return NULL;
+ }
+
+ // Look up the PC in the map, get the concrete method to execute and return its reference.
+ MethodVerifier::PcToConreteMethod::const_iterator pc_to_concrete_method = it->second->find(pc);
+ if(pc_to_concrete_method != it->second->end()) {
+ return &(pc_to_concrete_method->second);
+ } else {
+ return NULL;
+ }
+}
+
std::vector<int32_t> MethodVerifier::DescribeVRegs(uint32_t dex_pc) {
RegisterLine* line = reg_table_.GetLine(dex_pc);
std::vector<int32_t> result;
@@ -3312,6 +3416,9 @@ std::vector<int32_t> MethodVerifier::DescribeVRegs(uint32_t dex_pc) {
Mutex* MethodVerifier::dex_gc_maps_lock_ = NULL;
MethodVerifier::DexGcMapTable* MethodVerifier::dex_gc_maps_ = NULL;
+Mutex* MethodVerifier::devirt_maps_lock_ = NULL;
+MethodVerifier::DevirtualizationMapTable* MethodVerifier::devirt_maps_ = NULL;
+
Mutex* MethodVerifier::rejected_classes_lock_ = NULL;
MethodVerifier::RejectedClassesTable* MethodVerifier::rejected_classes_ = NULL;
@@ -3323,6 +3430,12 @@ void MethodVerifier::Init() {
dex_gc_maps_ = new MethodVerifier::DexGcMapTable;
}
+ devirt_maps_lock_ = new Mutex("verifier Devirtualization lock");
+ {
+ MutexLock mu(self, *devirt_maps_lock_);
+ devirt_maps_ = new MethodVerifier::DevirtualizationMapTable();
+ }
+
rejected_classes_lock_ = new Mutex("verifier rejected classes lock");
{
MutexLock mu(self, *rejected_classes_lock_);
@@ -3343,6 +3456,15 @@ void MethodVerifier::Shutdown() {
dex_gc_maps_lock_ = NULL;
{
+ MutexLock mu(self, *devirt_maps_lock_);
+ STLDeleteValues(devirt_maps_);
+ delete devirt_maps_;
+ devirt_maps_ = NULL;
+ }
+ delete devirt_maps_lock_;
+ devirt_maps_lock_ = NULL;
+
+ {
MutexLock mu(self, *rejected_classes_lock_);
delete rejected_classes_;
rejected_classes_ = NULL;
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index 7570b50db..02d79955b 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -101,7 +101,7 @@ const int kVerifyErrorRefTypeShift = 6;
// type-precise register analysis).
enum RegisterTrackingMode {
kTrackRegsBranches,
- kTrackRegsGcPoints,
+ kTrackCompilerInterestPoints,
kTrackRegsAll,
};
@@ -187,6 +187,9 @@ class MethodVerifier {
static const std::vector<uint8_t>* GetDexGcMap(CompilerDriver::MethodReference ref)
LOCKS_EXCLUDED(dex_gc_maps_lock_);
+ static const CompilerDriver::MethodReference* GetDevirtMap(CompilerDriver::MethodReference ref, uint32_t pc)
+ LOCKS_EXCLUDED(devirt_maps_lock_);
+
// Fills 'monitor_enter_dex_pcs' with the dex pcs of the monitor-enter instructions corresponding
// to the locks held at 'dex_pc' in 'm'.
static void FindLocksAtDexPc(mirror::AbstractMethod* m, uint32_t dex_pc,
@@ -577,6 +580,17 @@ class MethodVerifier {
static void SetDexGcMap(CompilerDriver::MethodReference ref, const std::vector<uint8_t>& dex_gc_map)
LOCKS_EXCLUDED(dex_gc_maps_lock_);
+
+ // Devirtualization map.
+ typedef SafeMap<const uint32_t, CompilerDriver::MethodReference> PcToConreteMethod;
+ typedef SafeMap<const CompilerDriver::MethodReference, const PcToConreteMethod*> DevirtualizationMapTable;
+ MethodVerifier::PcToConreteMethod* GenerateDevirtMap();
+
+ static Mutex* devirt_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ static DevirtualizationMapTable* devirt_maps_ GUARDED_BY(devirt_maps_lock_);
+ static void SetDevirtMap(CompilerDriver::MethodReference ref, const PcToConreteMethod* pc_method_map);
+ LOCKS_EXCLUDED(devirt_maps_lock_);
+
typedef std::set<CompilerDriver::ClassReference> RejectedClassesTable;
static Mutex* rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
static RejectedClassesTable* rejected_classes_;
diff --git a/src/verifier/reg_type.cc b/src/verifier/reg_type.cc
index 774c2b29e..82aa6c679 100644
--- a/src/verifier/reg_type.cc
+++ b/src/verifier/reg_type.cc
@@ -494,6 +494,7 @@ ReferenceType::ReferenceType(mirror::Class* klass, std::string& descriptor, uint
PreciseReferenceType::PreciseReferenceType(mirror::Class* klass, std::string& descriptor,
uint16_t cache_id)
: RegType(klass, descriptor, cache_id) {
+ DCHECK(!klass->IsAbstract() || klass->IsArrayClass());
}
UnresolvedUninitialisedThisRefType::UnresolvedUninitialisedThisRefType(std::string& descriptor,
@@ -609,7 +610,9 @@ const RegType& RegType::GetSuperClass(RegTypeCache* cache) const {
if (!IsUnresolvedTypes()) {
mirror::Class* super_klass = GetClass()->GetSuperClass();
if (super_klass != NULL) {
- return cache->FromClass(super_klass, IsPreciseReference());
+ // A super class of a precise type isn't precise as a precise type indicates the register
+ // holds exactly that type.
+ return cache->FromClass(super_klass, false);
} else {
return cache->Zero();
}