Revert "Revert "Do a second check for testing intrinsic types.""
This reverts commit a14b9fef395b94fa9a32147862c198fe7c22e3d7.
When an intrinsic with invoke-type virtual is recognized, replace
the instruction with a new HInvokeStaticOrDirect.
Minimal update for dex-cache rework. Fix includes.
Change-Id: I1c8e735a2fa7cda4419f76ca0717125ef236d332
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 075ec1e..41c239d 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -16,12 +16,17 @@
#include "intrinsics.h"
+#include "art_method.h"
+#include "class_linker.h"
#include "dex/quick/dex_file_method_inliner.h"
#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "driver/compiler_driver.h"
#include "invoke_type.h"
+#include "mirror/dex_cache-inl.h"
#include "nodes.h"
#include "quick/inline_method_analyser.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
#include "utils.h"
namespace art {
@@ -328,14 +333,23 @@
return Intrinsics::kNone;
}
-static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
+static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke, const DexFile& dex_file) {
// The DexFileMethodInliner should have checked whether the methods are agreeing with
// what we expect, i.e., static methods are called as such. Add another check here for
// our expectations:
- // Whenever the intrinsic is marked as static-or-direct, report an error if we find an
- // InvokeVirtual. The other direction is not possible: we have intrinsics for virtual
- // functions that will perform a check inline. If the precise type is known, however,
- // the instruction will be sharpened to an InvokeStaticOrDirect.
+ //
+ // Whenever the intrinsic is marked as static, report an error if we find an InvokeVirtual.
+ //
+ // Whenever the intrinsic is marked as direct and we find an InvokeVirtual, a devirtualization
+ // failure occured. We might be in a situation where we have inlined a method that calls an
+ // intrinsic, but that method is in a different dex file on which we do not have a
+ // verified_method that would have helped the compiler driver sharpen the call. In that case,
+ // make sure that the intrinsic is actually for some final method (or in a final class), as
+ // otherwise the intrinsics setup is broken.
+ //
+ // For the last direction, we have intrinsics for virtual functions that will perform a check
+ // inline. If the precise type is known, however, the instruction will be sharpened to an
+ // InvokeStaticOrDirect.
InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
invoke->AsInvokeStaticOrDirect()->GetInvokeType() :
@@ -343,8 +357,22 @@
switch (intrinsic_type) {
case kStatic:
return (invoke_type == kStatic);
+
case kDirect:
- return (invoke_type == kDirect);
+ if (invoke_type == kDirect) {
+ return true;
+ }
+ if (invoke_type == kVirtual) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ ScopedObjectAccess soa(Thread::Current());
+ ArtMethod* art_method =
+ class_linker->FindDexCache(soa.Self(), dex_file)->GetResolvedMethod(
+ invoke->GetDexMethodIndex(), class_linker->GetImagePointerSize());
+ return art_method != nullptr &&
+ (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
+ }
+ return false;
+
case kVirtual:
// Call might be devirtualized.
return (invoke_type == kVirtual || invoke_type == kDirect);
@@ -364,17 +392,18 @@
if (inst->IsInvoke()) {
HInvoke* invoke = inst->AsInvoke();
InlineMethod method;
- DexFileMethodInliner* inliner =
- driver_->GetMethodInlinerMap()->GetMethodInliner(&invoke->GetDexFile());
+ const DexFile& dex_file = invoke->GetDexFile();
+ DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(&dex_file);
DCHECK(inliner != nullptr);
if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
Intrinsics intrinsic = GetIntrinsic(method, graph_->GetInstructionSet());
if (intrinsic != Intrinsics::kNone) {
- if (!CheckInvokeType(intrinsic, invoke)) {
+ if (!CheckInvokeType(intrinsic, invoke, dex_file)) {
LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
- << intrinsic << " for "
- << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile());
+ << intrinsic << " for "
+ << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
+ << invoke->DebugName();
} else {
invoke->SetIntrinsic(intrinsic, NeedsEnvironmentOrCache(intrinsic));
}