diff options
Diffstat (limited to 'compiler/optimizing/intrinsics.cc')
| -rw-r--r-- | compiler/optimizing/intrinsics.cc | 83 |
1 files changed, 72 insertions, 11 deletions
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 075ec1ee2e..b71fdb8f1d 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 { @@ -120,6 +125,28 @@ static Intrinsics GetIntrinsic(InlineMethod method, InstructionSet instruction_s LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; UNREACHABLE(); } + case kIntrinsicRotateRight: + switch (GetType(method.d.data, true)) { + case Primitive::kPrimInt: + return Intrinsics::kIntegerRotateRight; + case Primitive::kPrimLong: + return Intrinsics::kLongRotateRight; + default: + LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; + UNREACHABLE(); + } + case kIntrinsicRotateLeft: + switch (GetType(method.d.data, true)) { + case Primitive::kPrimInt: + return Intrinsics::kIntegerRotateLeft; + case Primitive::kPrimLong: + return Intrinsics::kLongRotateLeft; + default: + LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; + UNREACHABLE(); + } + + // Misc data processing. case kIntrinsicNumberOfLeadingZeros: switch (GetType(method.d.data, true)) { case Primitive::kPrimInt: @@ -130,6 +157,16 @@ static Intrinsics GetIntrinsic(InlineMethod method, InstructionSet instruction_s LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; UNREACHABLE(); } + case kIntrinsicNumberOfTrailingZeros: + switch (GetType(method.d.data, true)) { + case Primitive::kPrimInt: + return Intrinsics::kIntegerNumberOfTrailingZeros; + case Primitive::kPrimLong: + return Intrinsics::kLongNumberOfTrailingZeros; + default: + LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; + UNREACHABLE(); + } // Abs. case kIntrinsicAbsDouble: @@ -328,14 +365,23 @@ static Intrinsics GetIntrinsic(InlineMethod method, InstructionSet instruction_s 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 +389,22 @@ static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) { 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 +424,18 @@ void IntrinsicsRecognizer::Run() { 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)); } |