Re-enable OSR.
Fixes two bugs:
- Dealing with proxy methods, which the compiler and code cache
does not handle.
- Dealing with phi types, that may have been speculatively optimized
but do not hold once jumping to the compiled code.
Change-Id: I7dcd9976ef7b12128fff95d2b7ed3e69cc42e90a
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index d2bf6c0..3fe7861 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -203,6 +203,7 @@
}
bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method, bool osr) {
+ DCHECK(!method->IsProxyMethod());
TimingLogger logger("JIT compiler timing logger", true, VLOG_IS_ON(jit));
const uint64_t start_time = NanoTime();
StackHandleScope<2> hs(self);
@@ -220,20 +221,17 @@
bool success = false;
{
TimingLogger::ScopedTiming t2("Compiling", &logger);
- // If we get a request to compile a proxy method, we pass the actual Java method
- // of that proxy method, as the compiler does not expect a proxy method.
- ArtMethod* method_to_compile = method->GetInterfaceMethodIfProxy(sizeof(void*));
JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache();
- success = compiler_driver_->GetCompiler()->JitCompile(self, code_cache, method_to_compile, osr);
+ success = compiler_driver_->GetCompiler()->JitCompile(self, code_cache, method, osr);
if (success && (perf_file_ != nullptr)) {
- const void* ptr = method_to_compile->GetEntryPointFromQuickCompiledCode();
+ const void* ptr = method->GetEntryPointFromQuickCompiledCode();
std::ostringstream stream;
stream << std::hex
<< reinterpret_cast<uintptr_t>(ptr)
<< " "
<< code_cache->GetMemorySizeOfCodePointer(ptr)
<< " "
- << PrettyMethod(method_to_compile)
+ << PrettyMethod(method)
<< std::endl;
std::string str = stream.str();
bool res = perf_file_->WriteFully(str.c_str(), str.size());
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index fa6aae8..3740c40 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -378,7 +378,7 @@
// Run type propagation to get the guard typed, and eventually propagate the
// type of the receiver.
- ReferenceTypePropagation rtp_fixup(graph_, handles_);
+ ReferenceTypePropagation rtp_fixup(graph_, handles_, /* is_first_run */ false);
rtp_fixup.Run();
MaybeRecordStat(kInlinedMonomorphicCall);
@@ -420,6 +420,9 @@
actual_method = new_method;
} else if (actual_method != new_method) {
// Different methods, bailout.
+ VLOG(compiler) << "Call to " << PrettyMethod(resolved_method)
+ << " from inline cache is not inlined because it resolves"
+ << " to different methods";
return false;
}
}
@@ -474,7 +477,7 @@
deoptimize->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
// Run type propagation to get the guard typed.
- ReferenceTypePropagation rtp_fixup(graph_, handles_);
+ ReferenceTypePropagation rtp_fixup(graph_, handles_, /* is_first_run */ false);
rtp_fixup.Run();
MaybeRecordStat(kInlinedPolymorphicCall);
@@ -727,7 +730,7 @@
// dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
/* dex_pc */ 0);
if (iget->GetType() == Primitive::kPrimNot) {
- ReferenceTypePropagation rtp(graph_, handles_);
+ ReferenceTypePropagation rtp(graph_, handles_, /* is_first_run */ false);
rtp.Visit(iget);
}
return iget;
@@ -756,6 +759,7 @@
/* dex_pc */ 0);
return iput;
}
+
bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
HInvoke* invoke_instruction,
bool same_dex_file,
@@ -988,12 +992,18 @@
if (current->IsNewInstance() &&
(current->AsNewInstance()->GetEntrypoint() == kQuickAllocObjectWithAccessCheck)) {
+ VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+ << " could not be inlined because it is using an entrypoint"
+ << " with access checks";
// Allocation entrypoint does not handle inlined frames.
return false;
}
if (current->IsNewArray() &&
(current->AsNewArray()->GetEntrypoint() == kQuickAllocArrayWithAccessCheck)) {
+ VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+ << " could not be inlined because it is using an entrypoint"
+ << " with access checks";
// Allocation entrypoint does not handle inlined frames.
return false;
}
@@ -1003,6 +1013,9 @@
current->IsUnresolvedStaticFieldSet() ||
current->IsUnresolvedInstanceFieldSet()) {
// Entrypoint for unresolved fields does not handle inlined frames.
+ VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+ << " could not be inlined because it is using an unresolved"
+ << " entrypoint";
return false;
}
}
@@ -1044,13 +1057,13 @@
if (invoke_rti.IsStrictSupertypeOf(return_rti)
|| (return_rti.IsExact() && !invoke_rti.IsExact())
|| !return_replacement->CanBeNull()) {
- ReferenceTypePropagation(graph_, handles_).Run();
+ ReferenceTypePropagation(graph_, handles_, /* is_first_run */ false).Run();
}
}
} else if (return_replacement->IsInstanceOf()) {
if (do_rtp) {
// Inlining InstanceOf into an If may put a tighter bound on reference types.
- ReferenceTypePropagation(graph_, handles_).Run();
+ ReferenceTypePropagation(graph_, handles_, /* is_first_run */ false).Run();
}
}
}
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 1224a48..deaa415 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -55,10 +55,12 @@
public:
RTPVisitor(HGraph* graph,
HandleCache* handle_cache,
- ArenaVector<HInstruction*>* worklist)
+ ArenaVector<HInstruction*>* worklist,
+ bool is_first_run)
: HGraphDelegateVisitor(graph),
handle_cache_(handle_cache),
- worklist_(worklist) {}
+ worklist_(worklist),
+ is_first_run_(is_first_run) {}
void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
@@ -86,14 +88,17 @@
private:
HandleCache* handle_cache_;
ArenaVector<HInstruction*>* worklist_;
+ const bool is_first_run_;
};
ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
StackHandleScopeCollection* handles,
+ bool is_first_run,
const char* name)
: HOptimization(graph, name),
handle_cache_(handles),
- worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)) {
+ worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)),
+ is_first_run_(is_first_run) {
}
void ReferenceTypePropagation::ValidateTypes() {
@@ -125,7 +130,7 @@
}
void ReferenceTypePropagation::Visit(HInstruction* instruction) {
- RTPVisitor visitor(graph_, &handle_cache_, &worklist_);
+ RTPVisitor visitor(graph_, &handle_cache_, &worklist_, is_first_run_);
instruction->Accept(&visitor);
}
@@ -144,7 +149,7 @@
}
void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
- RTPVisitor visitor(graph_, &handle_cache_, &worklist_);
+ RTPVisitor visitor(graph_, &handle_cache_, &worklist_, is_first_run_);
// Handle Phis first as there might be instructions in the same block who depend on them.
for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
VisitPhi(it.Current()->AsPhi());
@@ -620,6 +625,7 @@
DCHECK_EQ(bound_type->InputAt(0), check_cast->InputAt(0));
if (class_rti.IsValid()) {
+ DCHECK(is_first_run_);
// This is the first run of RTP and class is resolved.
bound_type->SetUpperBound(class_rti, /* CheckCast succeeds for nulls. */ true);
} else {
@@ -636,6 +642,12 @@
}
if (phi->GetBlock()->IsLoopHeader()) {
+ if (!is_first_run_ && graph_->IsCompilingOsr()) {
+ // Don't update the type of a loop phi when compiling OSR: we may have done
+ // speculative optimizations dominating that phi, that do not hold at the
+ // point the interpreter jumps to that loop header.
+ return;
+ }
ScopedObjectAccess soa(Thread::Current());
// Set the initial type for the phi. Use the non back edge input for reaching
// a fixed point faster.
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index a7f10a6..028a6fc 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -33,6 +33,7 @@
public:
ReferenceTypePropagation(HGraph* graph,
StackHandleScopeCollection* handles,
+ bool is_first_run,
const char* name = kReferenceTypePropagationPassName);
// Visit a single instruction.
@@ -93,6 +94,8 @@
ArenaVector<HInstruction*> worklist_;
+ // Whether this reference type propagation is the first run we are doing.
+ const bool is_first_run_;
static constexpr size_t kDefaultWorklistSize = 8;
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 165d09d..c08e5dd 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -483,7 +483,7 @@
// 6) Compute type of reference type instructions. The pass assumes that
// NullConstant has been fixed up.
- ReferenceTypePropagation(GetGraph(), handles_).Run();
+ ReferenceTypePropagation(GetGraph(), handles_, /* is_first_run */ true).Run();
// 7) Step 1) duplicated ArrayGet instructions with ambiguous type (int/float
// or long/double) and marked ArraySets with ambiguous input type. Now that RTP