diff options
-rw-r--r-- | TEST_MAPPING | 6 | ||||
-rw-r--r-- | compiler/optimizing/inliner.cc | 51 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils.cc | 4 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 2 | ||||
-rw-r--r-- | test/450-checker-types/Android.bp | 2 | ||||
-rw-r--r-- | test/450-checker-types/src/Main.java | 2 | ||||
-rw-r--r-- | test/569-checker-pattern-replacement/src/Main.java | 12 | ||||
-rw-r--r-- | test/609-checker-inline-interface/src/Main.java | 16 | ||||
-rw-r--r-- | test/673-checker-throw-vmethod/src/Main.java | 8 | ||||
-rw-r--r-- | test/730-checker-inlining-super/expected-stderr.txt | 0 | ||||
-rw-r--r-- | test/730-checker-inlining-super/expected-stdout.txt | 0 | ||||
-rw-r--r-- | test/730-checker-inlining-super/info.txt | 2 | ||||
-rw-r--r-- | test/730-checker-inlining-super/src/Main.java | 44 | ||||
-rw-r--r-- | test/823-cha-inlining/src/Main.java | 2 | ||||
-rwxr-xr-x | test/utils/regen-test-files | 1 |
15 files changed, 102 insertions, 50 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING index 7848ec2555..d869991e00 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -530,9 +530,6 @@ "name": "art-run-test-449-checker-bce-rem[com.google.android.art.apex]" }, { - "name": "art-run-test-450-checker-types[com.google.android.art.apex]" - }, - { "name": "art-run-test-451-regression-add-float[com.google.android.art.apex]" }, { @@ -1387,9 +1384,6 @@ "name": "art-run-test-449-checker-bce-rem" }, { - "name": "art-run-test-450-checker-types" - }, - { "name": "art-run-test-451-regression-add-float" }, { diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 611c691ae1..f2518176b7 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1240,32 +1240,22 @@ void HInliner::MaybeRunReferenceTypePropagation(HInstruction* replacement, bool HInliner::TryDevirtualize(HInvoke* invoke_instruction, ArtMethod* method, HInvoke** replacement) { - DCHECK(!method->IsProxyMethod()); DCHECK(invoke_instruction != *replacement); - if (!invoke_instruction->IsInvokeInterface()) { - // TODO: Consider sharpening an invoke virtual once it is not dependent on the - // compiler driver. + if (!invoke_instruction->IsInvokeInterface() && !invoke_instruction->IsInvokeVirtual()) { return false; } - // Devirtualization by exact type uses a method in the vtable, so we should - // not see a default non-copied method. - DCHECK(!method->IsDefault() || method->IsCopied()); - // Turn an invoke-interface into an invoke-virtual. An invoke-virtual is always - // better than an invoke-interface because: - // 1) In the best case, the interface call has one more indirection (to fetch the IMT). - // 2) We will not go to the conflict trampoline with an invoke-virtual. - // TODO: Consider sharpening once it is not dependent on the compiler driver. - - if (kIsDebugBuild && method->IsDefaultConflicting()) { - ReferenceTypeInfo receiver_type = invoke_instruction->InputAt(0)->GetReferenceTypeInfo(); - // Devirtualization by exact type uses a method in the vtable, - // so it's OK to change this invoke into a HInvokeVirtual. - ObjPtr<mirror::Class> receiver_class = receiver_type.GetTypeHandle().Get(); - CHECK(!receiver_class->IsInterface()); - PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); - CHECK(method == receiver_class->GetVTableEntry(method->GetMethodIndex(), pointer_size)); - } + // Don't bother trying to call directly a default conflict method. It + // doesn't have a proper MethodReference, but also `GetCanonicalMethod` + // will return an actual default implementation. + if (method->IsDefaultConflicting()) { + return false; + } + DCHECK(!method->IsProxyMethod()); + ClassLinker* cl = Runtime::Current()->GetClassLinker(); + PointerSize pointer_size = cl->GetImagePointerSize(); + // The sharpening logic assumes the caller isn't passing a copied method. + method = method->GetCanonicalMethod(pointer_size); uint32_t dex_method_index = FindMethodIndexIn( method, *invoke_instruction->GetMethodReference().dex_file, @@ -1273,19 +1263,32 @@ bool HInliner::TryDevirtualize(HInvoke* invoke_instruction, if (dex_method_index == dex::kDexNoIndex) { return false; } - HInvokeVirtual* new_invoke = new (graph_->GetAllocator()) HInvokeVirtual( + HInvokeStaticOrDirect::DispatchInfo dispatch_info = + HSharpening::SharpenLoadMethod(method, + /* has_method_id= */ true, + /* for_interface_call= */ false, + codegen_); + DCHECK_NE(dispatch_info.code_ptr_location, CodePtrLocation::kCallCriticalNative); + HInvokeStaticOrDirect* new_invoke = new (graph_->GetAllocator()) HInvokeStaticOrDirect( graph_->GetAllocator(), invoke_instruction->GetNumberOfArguments(), invoke_instruction->GetType(), invoke_instruction->GetDexPc(), MethodReference(invoke_instruction->GetMethodReference().dex_file, dex_method_index), method, + dispatch_info, + kDirect, MethodReference(method->GetDexFile(), method->GetDexMethodIndex()), - method->GetMethodIndex()); + HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); HInputsRef inputs = invoke_instruction->GetInputs(); + DCHECK_EQ(inputs.size(), invoke_instruction->GetNumberOfArguments()); for (size_t index = 0; index != inputs.size(); ++index) { new_invoke->SetArgumentAt(index, inputs[index]); } + if (HInvokeStaticOrDirect::NeedsCurrentMethodInput(dispatch_info)) { + new_invoke->SetRawInputAt(new_invoke->GetCurrentMethodIndexUnchecked(), + graph_->GetCurrentMethod()); + } invoke_instruction->GetBlock()->InsertInstructionBefore(new_invoke, invoke_instruction); new_invoke->CopyEnvironmentFrom(invoke_instruction->GetEnvironment()); if (invoke_instruction->GetType() == DataType::Type::kReference) { diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index ef0c474026..1c0127a519 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -302,6 +302,10 @@ void MaybeUpdateBssMethodEntry(ArtMethod* callee, MethodReference callee_referen oat_file->GetBssMethods().data() + oat_file->GetBssMethods().size()); std::atomic<ArtMethod*>* atomic_entry = reinterpret_cast<std::atomic<ArtMethod*>*>(method_entry); + if (kIsDebugBuild) { + ArtMethod* existing = atomic_entry->load(std::memory_order_acquire); + CHECK(existing->IsRuntimeMethod() || existing == callee); + } static_assert(sizeof(*method_entry) == sizeof(*atomic_entry), "Size check."); atomic_entry->store(callee, std::memory_order_release); } diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index bc5a10db29..eaa9f4eebb 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -1357,7 +1357,7 @@ extern "C" const void* artQuickResolutionTrampoline( // odd situation where the ArtMethod being executed is unrelated to the // receiver of the method. called = called->GetCanonicalMethod(); - if (invoke_type == kSuper) { + if (invoke_type == kSuper || invoke_type == kInterface || invoke_type == kVirtual) { if (called->GetDexFile() == called_method.dex_file) { called_method.index = called->GetDexMethodIndex(); } else { diff --git a/test/450-checker-types/Android.bp b/test/450-checker-types/Android.bp index bf45226669..1173b5ab3e 100644 --- a/test/450-checker-types/Android.bp +++ b/test/450-checker-types/Android.bp @@ -15,7 +15,7 @@ package { java_test { name: "art-run-test-450-checker-types", defaults: ["art-run-test-defaults"], - test_config_template: ":art-run-test-target-template", + test_config_template: ":art-run-test-target-no-test-suite-tag-template", srcs: ["src/**/*.java"], data: [ ":art-run-test-450-checker-types-expected-stdout", diff --git a/test/450-checker-types/src/Main.java b/test/450-checker-types/src/Main.java index 9e3f951760..084a7131c9 100644 --- a/test/450-checker-types/src/Main.java +++ b/test/450-checker-types/src/Main.java @@ -686,7 +686,7 @@ public class Main { /// CHECK-DAG: <<Null:l\d+>> NullConstant /// CHECK-DAG: <<Phi:l\d+>> Phi [<<Arg>>,<<Null>>] klass:SubclassA /// CHECK-DAG: <<NCPhi:l\d+>> NullCheck [<<Phi>>] - /// CHECK-DAG: InvokeVirtual [<<NCPhi>>] method_name:java.lang.Object.hashCode + /// CHECK-DAG: InvokeStaticOrDirect [<<NCPhi>>] method_name:java.lang.Object.hashCode public void testThisArgumentMoreSpecific(boolean cond) { // Inlining method from Super will build it with `this` typed as Super. diff --git a/test/569-checker-pattern-replacement/src/Main.java b/test/569-checker-pattern-replacement/src/Main.java index bcf8cdd362..e2658a404b 100644 --- a/test/569-checker-pattern-replacement/src/Main.java +++ b/test/569-checker-pattern-replacement/src/Main.java @@ -209,10 +209,11 @@ public class Main { /// CHECK: {{d\d+}} InvokeVirtual /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (after) - /// CHECK: {{d\d+}} InvokeVirtual + /// CHECK: {{d\d+}} InvokeStaticOrDirect /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (after) /// CHECK-NOT: InstanceFieldGet + /// CHECK-NOT: InvokeVirtual public static double getDoubleFromParam(Second s) { return s.getInstanceDoubleFieldFromParam(s); @@ -222,11 +223,12 @@ public class Main { /// CHECK: {{i\d+}} InvokeVirtual /// CHECK-START: int Main.getStaticInt(Second) inliner (after) - /// CHECK: {{i\d+}} InvokeVirtual + /// CHECK: {{i\d+}} InvokeStaticOrDirect /// CHECK-START: int Main.getStaticInt(Second) inliner (after) /// CHECK-NOT: InstanceFieldGet /// CHECK-NOT: StaticFieldGet + /// CHECK-NOT: InvokeVirtual public static int getStaticInt(Second s) { return s.getStaticIntField(); @@ -287,10 +289,11 @@ public class Main { /// CHECK: InvokeVirtual /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (after) - /// CHECK: InvokeVirtual + /// CHECK: InvokeStaticOrDirect /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (after) /// CHECK-NOT: InstanceFieldSet + /// CHECK-NOT: InvokeVirtual public static long setLongThroughParam(Second s, long value) { s.setInstanceLongFieldThroughParam(s, value); @@ -301,11 +304,12 @@ public class Main { /// CHECK: InvokeVirtual /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (after) - /// CHECK: InvokeVirtual + /// CHECK: InvokeStaticOrDirect /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (after) /// CHECK-NOT: InstanceFieldSet /// CHECK-NOT: StaticFieldSet + /// CHECK-NOT: InvokeVirtual public static float setStaticFloat(Second s, float value) { s.setStaticFloatField(value); diff --git a/test/609-checker-inline-interface/src/Main.java b/test/609-checker-inline-interface/src/Main.java index 249b7781f0..07709ea216 100644 --- a/test/609-checker-inline-interface/src/Main.java +++ b/test/609-checker-inline-interface/src/Main.java @@ -32,7 +32,7 @@ public final class Main implements Interface { // Expected } try { - testInterfaceToVirtualCall(); + testInterfaceToDirectCall(); } catch (Error e) { // Expected. } @@ -53,19 +53,19 @@ public final class Main implements Interface { methodWithInvokeInterface(itf); } - /// CHECK-START: void Main.testInterfaceToVirtualCall() inliner (before) + /// CHECK-START: void Main.testInterfaceToDirectCall() inliner (before) /// CHECK: InvokeStaticOrDirect method_name:Main.methodWithInvokeInterface - /// CHECK-START: void Main.testInterfaceToVirtualCall() inliner (before) + /// CHECK-START: void Main.testInterfaceToDirectCall() inliner (before) /// CHECK-NOT: InvokeInterface - /// CHECK-START: void Main.testInterfaceToVirtualCall() inliner (after) - /// CHECK: InvokeVirtual method_name:Main.doCall + /// CHECK-START: void Main.testInterfaceToDirectCall() inliner (after) + /// CHECK: InvokeStaticOrDirect method_name:Main.doCall - /// CHECK-START: void Main.testInterfaceToVirtualCall() inliner (after) - /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-START: void Main.testInterfaceToDirectCall() inliner (after) + /// CHECK-NOT: InvokeVirtual /// CHECK-NOT: InvokeInterface - public static void testInterfaceToVirtualCall() { + public static void testInterfaceToDirectCall() { methodWithInvokeInterface(m); } diff --git a/test/673-checker-throw-vmethod/src/Main.java b/test/673-checker-throw-vmethod/src/Main.java index f62cfc85a7..39793001f0 100644 --- a/test/673-checker-throw-vmethod/src/Main.java +++ b/test/673-checker-throw-vmethod/src/Main.java @@ -81,7 +81,7 @@ public class Main { /// CHECK: If [<<Tst>>] /// CHECK: end_block /// CHECK: begin_block - /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>] method_name:Main.doThrow + /// CHECK: InvokeStaticOrDirect [{{l\d+}},<<Str>>] method_name:Main.doThrow /// CHECK: end_block // /// CHECK-START: void Main.doit2(int[]) code_sinking (after) @@ -91,7 +91,7 @@ public class Main { /// CHECK: end_block /// CHECK: begin_block /// CHECK: <<Str:l\d+>> LoadString - /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>] method_name:Main.doThrow + /// CHECK: InvokeStaticOrDirect [{{l\d+}},<<Str>>] method_name:Main.doThrow /// CHECK: end_block public void doit2(int[] a) { // Being in the boot image means we know the load string cannot throw. Create one that is @@ -142,7 +142,7 @@ public class Main { /// CHECK: If [<<Tst>>] /// CHECK: end_block /// CHECK: begin_block - /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>] method_name:Main.doThrow + /// CHECK: InvokeStaticOrDirect [{{l\d+}},<<Str>>] method_name:Main.doThrow /// CHECK: end_block // /// CHECK-START: void Main.doit4(int[]) code_sinking (after) @@ -152,7 +152,7 @@ public class Main { /// CHECK: end_block /// CHECK: begin_block /// CHECK: <<Str:l\d+>> LoadString - /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>] method_name:Main.doThrow + /// CHECK: InvokeStaticOrDirect [{{l\d+}},<<Str>>] method_name:Main.doThrow /// CHECK: end_block public void doit4(int[] a) { // Being in the boot image means we know the load string cannot throw. Create one that is diff --git a/test/730-checker-inlining-super/expected-stderr.txt b/test/730-checker-inlining-super/expected-stderr.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/730-checker-inlining-super/expected-stderr.txt diff --git a/test/730-checker-inlining-super/expected-stdout.txt b/test/730-checker-inlining-super/expected-stdout.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/730-checker-inlining-super/expected-stdout.txt diff --git a/test/730-checker-inlining-super/info.txt b/test/730-checker-inlining-super/info.txt new file mode 100644 index 0000000000..d34596a574 --- /dev/null +++ b/test/730-checker-inlining-super/info.txt @@ -0,0 +1,2 @@ +Test that an invoke-virtual devirtualized by the compiler uses the right bss +slot at runtime. diff --git a/test/730-checker-inlining-super/src/Main.java b/test/730-checker-inlining-super/src/Main.java new file mode 100644 index 0000000000..5a1b574a5a --- /dev/null +++ b/test/730-checker-inlining-super/src/Main.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class SuperClass { + public int doInvoke() { + synchronized (this) { + return 42; + } + } +} + +public class Main extends SuperClass { + + public static void main(String[] args) { + Main m = new Main(); + int value = doInvokeTypedSuperClass(m); + if (value != 43) { + throw new Error("Expected 43, got " + value); + } + } + + public static int doInvokeTypedSuperClass(SuperClass sc) { + return sc.doInvoke(); + } + + public int doInvoke() { + synchronized (this) { + return super.doInvoke() + 1; + } + } +} diff --git a/test/823-cha-inlining/src/Main.java b/test/823-cha-inlining/src/Main.java index e25047d47e..c683e6b2ab 100644 --- a/test/823-cha-inlining/src/Main.java +++ b/test/823-cha-inlining/src/Main.java @@ -92,7 +92,7 @@ public class Main implements Itf, Itf2 { $noinline$doCallDefaultConflictItf3(); throw new Error("Expected IncompatibleClassChangeError"); } catch (Exception e) { - throw new Error("Unexpected exception"); + throw new Error("Unexpected exception " + e); } catch (IncompatibleClassChangeError e) { // Expected. } diff --git a/test/utils/regen-test-files b/test/utils/regen-test-files index cd9de74246..1d81e316f8 100755 --- a/test/utils/regen-test-files +++ b/test/utils/regen-test-files @@ -114,6 +114,7 @@ known_failing_tests = [ "177-visibly-initialized-deadlock", "178-app-image-native-method", "179-nonvirtual-jni", + "450-checker-types", "1900-track-alloc", "1901-get-bytecodes", "1902-suspend", |