diff options
| -rw-r--r-- | compiler/optimizing/graph_visualizer.cc | 3 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.cc | 44 | ||||
| -rw-r--r-- | test/675-checker-unverified-method/expected.txt | 1 | ||||
| -rw-r--r-- | test/675-checker-unverified-method/info.txt | 1 | ||||
| -rw-r--r-- | test/675-checker-unverified-method/smali/TestCase.smali | 55 | ||||
| -rw-r--r-- | test/675-checker-unverified-method/src/Main.java | 28 |
6 files changed, 119 insertions, 13 deletions
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 6144162f68..bbf8c26d59 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -445,6 +445,9 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { ? GetGraph()->GetDexFile().PrettyMethod(invoke->GetDexMethodIndex(), kWithSignature) : method->PrettyMethod(kWithSignature); StartAttributeStream("method_name") << method_name; + StartAttributeStream("always_throws") << std::boolalpha + << invoke->AlwaysThrows() + << std::noboolalpha; } void VisitInvokeUnresolved(HInvokeUnresolved* invoke) OVERRIDE { diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 035e5ce3e1..b9ae0ffb12 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -392,10 +392,33 @@ ArtMethod* HInliner::TryCHADevirtualization(ArtMethod* resolved_method) { return single_impl; } -static bool AlwaysThrows(ArtMethod* method) +static bool IsMethodUnverified(CompilerDriver* const compiler_driver, ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { - CodeItemDataAccessor accessor(method->DexInstructionData()); + if (!method->GetDeclaringClass()->IsVerified()) { + if (Runtime::Current()->UseJitCompilation()) { + // We're at runtime, we know this is cold code if the class + // is not verified, so don't bother analyzing. + return true; + } + uint16_t class_def_idx = method->GetDeclaringClass()->GetDexClassDefIndex(); + if (!compiler_driver->IsMethodVerifiedWithoutFailures( + method->GetDexMethodIndex(), class_def_idx, *method->GetDexFile())) { + // Method has soft or hard failures, don't analyze. + return true; + } + } + return false; +} + +static bool AlwaysThrows(CompilerDriver* const compiler_driver, ArtMethod* method) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK(method != nullptr); + // Skip non-compilable and unverified methods. + if (!method->IsCompilable() || IsMethodUnverified(compiler_driver, method)) { + return false; + } // Skip native methods, methods with try blocks, and methods that are too large. + CodeItemDataAccessor accessor(method->DexInstructionData()); if (!accessor.HasCodeItem() || accessor.TriesSize() != 0 || accessor.InsnsSizeInCodeUnits() > kMaximumNumberOfTotalInstructions) { @@ -478,7 +501,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { MaybeRecordStat(stats_, MethodCompilationStat::kInlinedInvokeVirtualOrInterface); } } - } else if (!cha_devirtualize && AlwaysThrows(actual_method)) { + } else if (!cha_devirtualize && AlwaysThrows(compiler_driver_, actual_method)) { // Set always throws property for non-inlined method call with single target // (unless it was obtained through CHA, because that would imply we have // to add the CHA dependency, which seems not worth it). @@ -1450,16 +1473,11 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, << " has soft failures un-handled by the compiler, so it cannot be inlined"; } - if (!method->GetDeclaringClass()->IsVerified()) { - uint16_t class_def_idx = method->GetDeclaringClass()->GetDexClassDefIndex(); - if (Runtime::Current()->UseJitCompilation() || - !compiler_driver_->IsMethodVerifiedWithoutFailures( - method->GetDexMethodIndex(), class_def_idx, *method->GetDexFile())) { - LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedNotVerified) - << "Method " << method->PrettyMethod() - << " couldn't be verified, so it cannot be inlined"; - return false; - } + if (IsMethodUnverified(compiler_driver_, method)) { + LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedNotVerified) + << "Method " << method->PrettyMethod() + << " couldn't be verified, so it cannot be inlined"; + return false; } if (invoke_instruction->IsInvokeStaticOrDirect() && diff --git a/test/675-checker-unverified-method/expected.txt b/test/675-checker-unverified-method/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/675-checker-unverified-method/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/675-checker-unverified-method/info.txt b/test/675-checker-unverified-method/info.txt new file mode 100644 index 0000000000..667211a2fa --- /dev/null +++ b/test/675-checker-unverified-method/info.txt @@ -0,0 +1 @@ +Make sure analysis of unverified method is skipped. diff --git a/test/675-checker-unverified-method/smali/TestCase.smali b/test/675-checker-unverified-method/smali/TestCase.smali new file mode 100644 index 0000000000..673b3f2708 --- /dev/null +++ b/test/675-checker-unverified-method/smali/TestCase.smali @@ -0,0 +1,55 @@ +# Copyright (C) 2018 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 public LTestCase; + +.super Ljava/lang/Object; + +# +# Ensure foo() does not analyze unverified bad() always-throws property. +# +## CHECK-START: void TestCase.foo(java.lang.Object) inliner (after) +## CHECK-DAG: InvokeStaticOrDirect method_name:TestCase.bar always_throws:true +## CHECK-DAG: InvokeStaticOrDirect method_name:TestCase.bad always_throws:false +.method public static foo(Ljava/lang/Object;)V + .registers 1 + if-nez v0, :Skip1 + invoke-static {}, LTestCase;->bar()V +:Skip1 + if-nez v0, :Skip2 + invoke-static {}, LTestCase;->bad()Lwont/be/Resolvable; +:Skip2 + return-void +.end method + +# +# Method bar() that verifies (but is never called). +# +.method public static bar()V + .registers 1 + new-instance v0, Ljava/lang/RuntimeException; + invoke-direct {v0}, Ljava/lang/RuntimeException;-><init>()V + throw v0 +.end method + +# +# Method bad() that fails to verify (but is never called). +# +.method public static bad()Lwont/be/Resolvable; + .registers 1 + invoke-static {}, LTestCase;->bar()Lwont/be/Resolvable; + move-result-object v0 + throw v0 +.end method + diff --git a/test/675-checker-unverified-method/src/Main.java b/test/675-checker-unverified-method/src/Main.java new file mode 100644 index 0000000000..0cdb2fe84b --- /dev/null +++ b/test/675-checker-unverified-method/src/Main.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 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. + */ + +/** + * Ensure unverified method is not analyzed. + */ +public class Main { + public static void main(String[] args) throws Exception { + Object o = new Object(); + Class<?> c = Class.forName("TestCase"); + Object[] arguments = { o }; + c.getMethod("foo", Object.class).invoke(null, arguments); + System.out.println("passed"); + } +} |