summaryrefslogtreecommitdiff
path: root/compiler/optimizing/instruction_builder.cc
diff options
context:
space:
mode:
authorVladimir Marko <vmarko@google.com>2017-06-12 15:41:56 +0100
committerVladimir Marko <vmarko@google.com>2017-07-20 13:35:06 +0100
commitba118827465d12177f3996e50133960087b1c916 (patch)
treef39728cdafc7810004d51c0bef2728b98993daa9 /compiler/optimizing/instruction_builder.cc
parent64a102dde8c5daad83b991710decb418ce43aac5 (diff)
ART: Change method lookup to be more consistent to JLS and the RI.
The method lookup for different invoke types was previously widely different and didn't work well with the dex cache method array where we have only a single slot for each MethodId. The new behavior is to perform the same lookup for all cases, distinguishing only between interface and non-interface referencing class, and to further align the behavior with the JLS and the RI. Where the JLS conflicts with the RI, we follow the JLS semantics. The new lookup for class methods first searches the methods declared in the superclass chain (ignoring "copied" methods) and only then looks in the "copied" methods. If the search in the superclass chain finds a method that has not been inherited (i.e. either a private method or a package-access method where one of the classes in the chain does not belong to the same package, see JLS 8.4.8), we still search the "copied" methods as there may actually be a method inherited from an interface. This follows the JLS semantics where inherited methods are included in the search (JLS 15.12.2.1) but conflicts with the RI where the private or package-access method takes precedence over methods inherited from interfaces. Note that this search can find an accessible method that is not inherited by the qualifying type, either for a package access method when the referrer is in the same package but the qualifying type is in another package, or for a private method where the referrer is in the same class but the qualifying type is actually a subclass. For the moment we allow such calls and we shall consider whether to throw an IncompatibleClassChangeError in this situation in future to comply with JLS 15.12.4.3. The new lookup for interface methods searches the interface class, then all the superinterfaces and then the java.lang.Object class, see implicitly declared methods in interfaces, JLS 9.2. The search for the maximally-specific non-abstract superinterface method is not yet implemented, but the difference should be difficult to observe as the usual subsequent call to FindVirtualMethodForInterface() should yield the same result for any matching method. The new test 162-method-idx-clash exposes several cases where we previously completely messed up due to the effects of the DexCache, or where we were out of line with the RI. It also tests a case where the JLS and the RI disagree and we follow the JLS. Test: art/test/run-test --host --jvm 162-method-resolution Test: m test-art-host-gtest Test: testrunner.py --host Test: testrunner.py --host --interp-ac Test: Nexus 6P boots. Test: testrunner.py --target Bug: 62855082 Bug: 30627598 Change-Id: If450c8cff2751369011d649c25d28a482a2c61a3
Diffstat (limited to 'compiler/optimizing/instruction_builder.cc')
-rw-r--r--compiler/optimizing/instruction_builder.cc64
1 files changed, 24 insertions, 40 deletions
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 839f328a4f..8054140924 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -664,10 +664,7 @@ void HInstructionBuilder::BuildReturn(const Instruction& instruction,
// TODO: remove redundant constructor fences (b/36656456).
if (RequiresConstructorBarrier(dex_compilation_unit_, compiler_driver_)) {
// Compiling instance constructor.
- if (kIsDebugBuild) {
- std::string method_name = graph_->GetMethodName();
- CHECK_EQ(std::string("<init>"), method_name);
- }
+ DCHECK_STREQ("<init>", graph_->GetMethodName());
HInstruction* fence_target = current_this_parameter_;
DCHECK(fence_target != nullptr);
@@ -710,29 +707,18 @@ static InvokeType GetInvokeTypeFromOpCode(Instruction::Code opcode) {
ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType invoke_type) {
ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<2> hs(soa.Self());
ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker();
Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader();
- Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass()));
- // We fetch the referenced class eagerly (that is, the class pointed by in the MethodId
- // at method_idx), as `CanAccessResolvedMethod` expects it be be in the dex cache.
- Handle<mirror::Class> methods_class(hs.NewHandle(class_linker->ResolveReferencedClassOfMethod(
- method_idx, dex_compilation_unit_->GetDexCache(), class_loader)));
-
- if (UNLIKELY(methods_class == nullptr)) {
- // Clean up any exception left by type resolution.
- soa.Self()->ClearException();
- return nullptr;
- }
- ArtMethod* resolved_method = class_linker->ResolveMethod<ClassLinker::kForceICCECheck>(
- *dex_compilation_unit_->GetDexFile(),
- method_idx,
- dex_compilation_unit_->GetDexCache(),
- class_loader,
- /* referrer */ nullptr,
- invoke_type);
+ ArtMethod* resolved_method =
+ class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
+ *dex_compilation_unit_->GetDexFile(),
+ method_idx,
+ dex_compilation_unit_->GetDexCache(),
+ class_loader,
+ graph_->GetArtMethod(),
+ invoke_type);
if (UNLIKELY(resolved_method == nullptr)) {
// Clean up any exception left by type resolution.
@@ -740,17 +726,14 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in
return nullptr;
}
- // Check access. The class linker has a fast path for looking into the dex cache
- // and does not check the access if it hits it.
- if (compiling_class == nullptr) {
+ // The referrer may be unresolved for AOT if we're compiling a class that cannot be
+ // resolved because, for example, we don't find a superclass in the classpath.
+ if (graph_->GetArtMethod() == nullptr) {
+ // The class linker cannot check access without a referrer, so we have to do it.
+ // Fall back to HInvokeUnresolved if the method isn't public.
if (!resolved_method->IsPublic()) {
return nullptr;
}
- } else if (!compiling_class->CanAccessResolvedMethod(resolved_method->GetDeclaringClass(),
- resolved_method,
- dex_compilation_unit_->GetDexCache().Get(),
- method_idx)) {
- return nullptr;
}
// We have to special case the invoke-super case, as ClassLinker::ResolveMethod does not.
@@ -758,19 +741,26 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in
// make this an invoke-unresolved to handle cross-dex invokes or abstract super methods, both of
// which require runtime handling.
if (invoke_type == kSuper) {
+ ObjPtr<mirror::Class> compiling_class = GetCompilingClass();
if (compiling_class == nullptr) {
// We could not determine the method's class we need to wait until runtime.
DCHECK(Runtime::Current()->IsAotCompiler());
return nullptr;
}
- if (!methods_class->IsAssignableFrom(compiling_class.Get())) {
+ ObjPtr<mirror::Class> referenced_class = class_linker->LookupResolvedType(
+ *dex_compilation_unit_->GetDexFile(),
+ dex_compilation_unit_->GetDexFile()->GetMethodId(method_idx).class_idx_,
+ dex_compilation_unit_->GetDexCache().Get(),
+ class_loader.Get());
+ DCHECK(referenced_class != nullptr); // We have already resolved a method from this class.
+ if (!referenced_class->IsAssignableFrom(compiling_class)) {
// We cannot statically determine the target method. The runtime will throw a
// NoSuchMethodError on this one.
return nullptr;
}
ArtMethod* actual_method;
- if (methods_class->IsInterface()) {
- actual_method = methods_class->FindVirtualMethodForInterfaceSuper(
+ if (referenced_class->IsInterface()) {
+ actual_method = referenced_class->FindVirtualMethodForInterfaceSuper(
resolved_method, class_linker->GetImagePointerSize());
} else {
uint16_t vtable_index = resolved_method->GetMethodIndex();
@@ -797,12 +787,6 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in
resolved_method = actual_method;
}
- // Check for incompatible class changes. The class linker has a fast path for
- // looking into the dex cache and does not check incompatible class changes if it hits it.
- if (resolved_method->CheckIncompatibleClassChange(invoke_type)) {
- return nullptr;
- }
-
return resolved_method;
}