Pass a full MethodReference of the invoke in HInvoke nodes.
Cleanup to ensure we don't make mistakes when passing a dex method index
to the HInvoke constructor, and we know which dex file it relates to.
Test: test.py
Change-Id: I625949add88a6b97e1dafeb7aed37961e105d6aa
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 4530f1d..b9f40a0 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -173,8 +173,8 @@
if (call != nullptr && call->GetIntrinsic() == Intrinsics::kNone) {
if (honor_noinline_directives) {
// Debugging case: directives in method names control or assert on inlining.
- std::string callee_name = outer_compilation_unit_.GetDexFile()->PrettyMethod(
- call->GetDexMethodIndex(), /* with_signature= */ false);
+ std::string callee_name =
+ call->GetMethodReference().PrettyMethod(/* with_signature= */ false);
// Tests prevent inlining by having $noinline$ in their method names.
if (callee_name.find("$noinline$") == std::string::npos) {
if (TryInline(call)) {
@@ -209,8 +209,9 @@
* the actual runtime target of an interface or virtual call.
* Return nullptr if the runtime target cannot be proven.
*/
-static ArtMethod* FindVirtualOrInterfaceTarget(HInvoke* invoke, ArtMethod* resolved_method)
+static ArtMethod* FindVirtualOrInterfaceTarget(HInvoke* invoke)
REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* resolved_method = invoke->GetResolvedMethod();
if (IsMethodOrDeclaringClassFinal(resolved_method)) {
// No need to lookup further, the resolved method will be the target.
return resolved_method;
@@ -438,19 +439,16 @@
}
ArtMethod* HInliner::FindActualCallTarget(HInvoke* invoke_instruction, bool* cha_devirtualize) {
- ArtMethod* resolved_method = invoke_instruction->GetResolvedMethod();
- DCHECK(resolved_method != nullptr);
-
ArtMethod* actual_method = nullptr;
if (invoke_instruction->IsInvokeStaticOrDirect()) {
- actual_method = resolved_method;
+ actual_method = invoke_instruction->GetResolvedMethod();
} else {
// Check if we can statically find the method.
- actual_method = FindVirtualOrInterfaceTarget(invoke_instruction, resolved_method);
+ actual_method = FindVirtualOrInterfaceTarget(invoke_instruction);
}
if (actual_method == nullptr) {
- ArtMethod* method = TryCHADevirtualization(resolved_method);
+ ArtMethod* method = TryCHADevirtualization(invoke_instruction->GetResolvedMethod());
if (method != nullptr) {
*cha_devirtualize = true;
actual_method = method;
@@ -478,9 +476,7 @@
}
ScopedObjectAccess soa(Thread::Current());
- uint32_t method_index = invoke_instruction->GetDexMethodIndex();
- const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
- LOG_TRY() << caller_dex_file.PrettyMethod(method_index);
+ LOG_TRY() << invoke_instruction->GetMethodReference().PrettyMethod();
ArtMethod* resolved_method = invoke_instruction->GetResolvedMethod();
if (resolved_method == nullptr) {
@@ -496,8 +492,7 @@
// If we didn't find a method, see if we can inline from the inline caches.
if (actual_method == nullptr) {
DCHECK(!invoke_instruction->IsInvokeStaticOrDirect());
-
- return TryInlineFromInlineCache(caller_dex_file, invoke_instruction, resolved_method);
+ return TryInlineFromInlineCache(invoke_instruction);
}
// Single target.
@@ -574,9 +569,7 @@
// We may come from the interpreter and it may have seen different receiver types.
return Runtime::Current()->IsAotCompiler() || outermost_graph_->IsCompilingOsr();
}
-bool HInliner::TryInlineFromInlineCache(const DexFile& caller_dex_file,
- HInvoke* invoke_instruction,
- ArtMethod* resolved_method)
+bool HInliner::TryInlineFromInlineCache(HInvoke* invoke_instruction)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (Runtime::Current()->IsAotCompiler() && !kUseAOTInlineCaches) {
return false;
@@ -588,21 +581,21 @@
// for it.
InlineCacheType inline_cache_type =
(Runtime::Current()->IsAotCompiler() || Runtime::Current()->IsZygote())
- ? GetInlineCacheAOT(caller_dex_file, invoke_instruction, &hs, &inline_cache)
+ ? GetInlineCacheAOT(invoke_instruction, &hs, &inline_cache)
: GetInlineCacheJIT(invoke_instruction, &hs, &inline_cache);
switch (inline_cache_type) {
case kInlineCacheNoData: {
LOG_FAIL_NO_STAT()
<< "No inline cache information for call to "
- << caller_dex_file.PrettyMethod(invoke_instruction->GetDexMethodIndex());
+ << invoke_instruction->GetMethodReference().PrettyMethod();
return false;
}
case kInlineCacheUninitialized: {
LOG_FAIL_NO_STAT()
<< "Interface or virtual call to "
- << caller_dex_file.PrettyMethod(invoke_instruction->GetDexMethodIndex())
+ << invoke_instruction->GetMethodReference().PrettyMethod()
<< " is not hit and not inlined";
return false;
}
@@ -610,21 +603,21 @@
case kInlineCacheMonomorphic: {
MaybeRecordStat(stats_, MethodCompilationStat::kMonomorphicCall);
if (UseOnlyPolymorphicInliningWithNoDeopt()) {
- return TryInlinePolymorphicCall(invoke_instruction, resolved_method, inline_cache);
+ return TryInlinePolymorphicCall(invoke_instruction, inline_cache);
} else {
- return TryInlineMonomorphicCall(invoke_instruction, resolved_method, inline_cache);
+ return TryInlineMonomorphicCall(invoke_instruction, inline_cache);
}
}
case kInlineCachePolymorphic: {
MaybeRecordStat(stats_, MethodCompilationStat::kPolymorphicCall);
- return TryInlinePolymorphicCall(invoke_instruction, resolved_method, inline_cache);
+ return TryInlinePolymorphicCall(invoke_instruction, inline_cache);
}
case kInlineCacheMegamorphic: {
LOG_FAIL_NO_STAT()
<< "Interface or virtual call to "
- << caller_dex_file.PrettyMethod(invoke_instruction->GetDexMethodIndex())
+ << invoke_instruction->GetMethodReference().PrettyMethod()
<< " is megamorphic and not inlined";
MaybeRecordStat(stats_, MethodCompilationStat::kMegamorphicCall);
return false;
@@ -633,7 +626,7 @@
case kInlineCacheMissingTypes: {
LOG_FAIL_NO_STAT()
<< "Interface or virtual call to "
- << caller_dex_file.PrettyMethod(invoke_instruction->GetDexMethodIndex())
+ << invoke_instruction->GetMethodReference().PrettyMethod()
<< " is missing types and not inlined";
return false;
}
@@ -671,7 +664,6 @@
}
HInliner::InlineCacheType HInliner::GetInlineCacheAOT(
- const DexFile& caller_dex_file,
HInvoke* invoke_instruction,
StackHandleScope<1>* hs,
/*out*/Handle<mirror::ObjectArray<mirror::Class>>* inline_cache)
@@ -683,7 +675,7 @@
std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_profile =
pci->GetHotMethodInfo(MethodReference(
- &caller_dex_file, caller_compilation_unit_.GetDexMethodIndex()));
+ caller_compilation_unit_.GetDexFile(), caller_compilation_unit_.GetDexMethodIndex()));
if (offline_profile == nullptr) {
return kInlineCacheNoData; // no profile information for this invocation.
}
@@ -762,8 +754,8 @@
inline_cache->Set(ic_index++, clazz);
} else {
VLOG(compiler) << "Could not resolve class from inline cache in AOT mode "
- << caller_compilation_unit_.GetDexFile()->PrettyMethod(
- invoke_instruction->GetDexMethodIndex()) << " : "
+ << invoke_instruction->GetMethodReference().PrettyMethod()
+ << " : "
<< caller_compilation_unit_
.GetDexFile()->StringByTypeIdx(class_ref.type_index);
return kInlineCacheMissingTypes;
@@ -793,10 +785,10 @@
}
static ArtMethod* ResolveMethodFromInlineCache(Handle<mirror::Class> klass,
- ArtMethod* resolved_method,
- HInstruction* invoke_instruction,
+ HInvoke* invoke_instruction,
PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* resolved_method = invoke_instruction->GetResolvedMethod();
if (Runtime::Current()->IsAotCompiler()) {
// We can get unrelated types when working with profiles (corruption,
// systme updates, or anyone can write to it). So first check if the class
@@ -819,7 +811,6 @@
}
bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction,
- ArtMethod* resolved_method,
Handle<mirror::ObjectArray<mirror::Class>> classes) {
DCHECK(invoke_instruction->IsInvokeVirtual() || invoke_instruction->IsInvokeInterface())
<< invoke_instruction->DebugName();
@@ -828,7 +819,7 @@
GetMonomorphicType(classes), caller_compilation_unit_);
if (!class_index.IsValid()) {
LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedDexCache)
- << "Call to " << ArtMethod::PrettyMethod(resolved_method)
+ << "Call to " << ArtMethod::PrettyMethod(invoke_instruction->GetResolvedMethod())
<< " from inline cache is not inlined because its class is not"
<< " accessible to the caller";
return false;
@@ -838,8 +829,8 @@
PointerSize pointer_size = class_linker->GetImagePointerSize();
Handle<mirror::Class> monomorphic_type =
graph_->GetHandleCache()->NewHandle(GetMonomorphicType(classes));
- resolved_method = ResolveMethodFromInlineCache(
- monomorphic_type, resolved_method, invoke_instruction, pointer_size);
+ ArtMethod* resolved_method = ResolveMethodFromInlineCache(
+ monomorphic_type, invoke_instruction, pointer_size);
LOG_NOTE() << "Try inline monomorphic call to " << resolved_method->PrettyMethod();
if (resolved_method == nullptr) {
@@ -980,12 +971,11 @@
}
bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction,
- ArtMethod* resolved_method,
Handle<mirror::ObjectArray<mirror::Class>> classes) {
DCHECK(invoke_instruction->IsInvokeVirtual() || invoke_instruction->IsInvokeInterface())
<< invoke_instruction->DebugName();
- if (TryInlinePolymorphicCallToSameTarget(invoke_instruction, resolved_method, classes)) {
+ if (TryInlinePolymorphicCallToSameTarget(invoke_instruction, classes)) {
return true;
}
@@ -1001,8 +991,7 @@
ArtMethod* method = nullptr;
Handle<mirror::Class> handle = graph_->GetHandleCache()->NewHandle(classes->Get(i));
- method = ResolveMethodFromInlineCache(
- handle, resolved_method, invoke_instruction, pointer_size);
+ method = ResolveMethodFromInlineCache(handle, invoke_instruction, pointer_size);
if (method == nullptr) {
DCHECK(Runtime::Current()->IsAotCompiler());
// AOT profile is bogus. This loop expects to iterate over all entries,
@@ -1027,7 +1016,8 @@
} else {
one_target_inlined = true;
- LOG_SUCCESS() << "Polymorphic call to " << ArtMethod::PrettyMethod(resolved_method)
+ LOG_SUCCESS() << "Polymorphic call to "
+ << invoke_instruction->GetMethodReference().PrettyMethod()
<< " has inlined " << ArtMethod::PrettyMethod(method);
// If we have inlined all targets before, and this receiver is the last seen,
@@ -1060,7 +1050,7 @@
if (!one_target_inlined) {
LOG_FAIL_NO_STAT()
- << "Call to " << ArtMethod::PrettyMethod(resolved_method)
+ << "Call to " << invoke_instruction->GetMethodReference().PrettyMethod()
<< " from inline cache is not inlined because none"
<< " of its targets could be inlined";
return false;
@@ -1155,7 +1145,6 @@
bool HInliner::TryInlinePolymorphicCallToSameTarget(
HInvoke* invoke_instruction,
- ArtMethod* resolved_method,
Handle<mirror::ObjectArray<mirror::Class>> classes) {
// This optimization only works under JIT for now.
if (!codegen_->GetCompilerOptions().IsJitCompiler()) {
@@ -1165,7 +1154,6 @@
ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
PointerSize pointer_size = class_linker->GetImagePointerSize();
- DCHECK(resolved_method != nullptr);
ArtMethod* actual_method = nullptr;
size_t method_index = invoke_instruction->IsInvokeVirtual()
? invoke_instruction->AsInvokeVirtual()->GetVTableIndex()
@@ -1300,7 +1288,7 @@
invoke_instruction->GetNumberOfArguments(),
invoke_instruction->GetType(),
invoke_instruction->GetDexPc(),
- invoke_instruction->GetDexMethodIndex(), // Use interface method's dex method index.
+ invoke_instruction->GetMethodReference(), // Use interface method's reference.
method,
method->GetMethodIndex());
DCHECK_NE(new_invoke->GetIntrinsic(), Intrinsics::kNone);
@@ -1338,9 +1326,10 @@
return false;
}
- const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
uint32_t dex_method_index = FindMethodIndexIn(
- method, caller_dex_file, invoke_instruction->GetDexMethodIndex());
+ method,
+ *invoke_instruction->GetMethodReference().dex_file,
+ invoke_instruction->GetMethodReference().index);
if (dex_method_index == dex::kDexNoIndex) {
return false;
}
@@ -1349,7 +1338,7 @@
invoke_instruction->GetNumberOfArguments(),
invoke_instruction->GetType(),
invoke_instruction->GetDexPc(),
- dex_method_index,
+ MethodReference(invoke_instruction->GetMethodReference().dex_file, dex_method_index),
method,
method->GetMethodIndex());
HInputsRef inputs = invoke_instruction->GetInputs();
@@ -1568,10 +1557,10 @@
// Try to recognize known simple patterns and replace invoke call with appropriate instructions.
bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction,
- ArtMethod* resolved_method,
+ ArtMethod* method,
HInstruction** return_replacement) {
InlineMethod inline_method;
- if (!InlineMethodAnalyser::AnalyseMethodCode(resolved_method, &inline_method)) {
+ if (!InlineMethodAnalyser::AnalyseMethodCode(method, &inline_method)) {
return false;
}
@@ -1585,7 +1574,7 @@
inline_method.d.return_data.arg);
break;
case kInlineOpNonWideConst:
- if (resolved_method->GetShorty()[0] == 'L') {
+ if (method->GetShorty()[0] == 'L') {
DCHECK_EQ(inline_method.d.data, 0u);
*return_replacement = graph_->GetNullConstant();
} else {
@@ -1599,7 +1588,7 @@
return false;
}
HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, data.object_arg);
- HInstanceFieldGet* iget = CreateInstanceFieldGet(data.field_idx, resolved_method, obj);
+ HInstanceFieldGet* iget = CreateInstanceFieldGet(data.field_idx, method, obj);
DCHECK_EQ(iget->GetFieldOffset().Uint32Value(), data.field_offset);
DCHECK_EQ(iget->IsVolatile() ? 1u : 0u, data.is_volatile);
invoke_instruction->GetBlock()->InsertInstructionBefore(iget, invoke_instruction);
@@ -1614,7 +1603,7 @@
}
HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, data.object_arg);
HInstruction* value = GetInvokeInputForArgVRegIndex(invoke_instruction, data.src_arg);
- HInstanceFieldSet* iput = CreateInstanceFieldSet(data.field_idx, resolved_method, obj, value);
+ HInstanceFieldSet* iput = CreateInstanceFieldSet(data.field_idx, method, obj, value);
DCHECK_EQ(iput->GetFieldOffset().Uint32Value(), data.field_offset);
DCHECK_EQ(iput->IsVolatile() ? 1u : 0u, data.is_volatile);
invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction);
@@ -1657,7 +1646,7 @@
uint16_t field_index = iput_field_indexes[i];
bool is_final;
HInstanceFieldSet* iput =
- CreateInstanceFieldSet(field_index, resolved_method, obj, value, &is_final);
+ CreateInstanceFieldSet(field_index, method, obj, value, &is_final);
invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction);
// Check whether the field is final. If it is, we need to add a barrier.