diff options
| author | 2017-03-29 18:17:04 +0000 | |
|---|---|---|
| committer | 2017-03-29 18:17:05 +0000 | |
| commit | d07f2ba2c60cb8aa920d2b428e414628078e233e (patch) | |
| tree | e81cc276b4d7c460fa154537e86fd4310decd5c0 | |
| parent | 1e45a522ea1944d3470de971649ad0c3dc6f4884 (diff) | |
| parent | 4c0b4bc2653be370c7ba9f34a39e29e60382dff1 (diff) | |
Merge "Gracefully handle bogus profiling info for inline caches."
| -rw-r--r-- | compiler/optimizing/inliner.cc | 61 | ||||
| -rw-r--r-- | runtime/art_method-inl.h | 7 | ||||
| -rw-r--r-- | test/643-checker-bogus-ic/expected.txt | 0 | ||||
| -rw-r--r-- | test/643-checker-bogus-ic/info.txt | 1 | ||||
| -rw-r--r-- | test/643-checker-bogus-ic/profile | 2 | ||||
| -rw-r--r-- | test/643-checker-bogus-ic/run | 17 | ||||
| -rw-r--r-- | test/643-checker-bogus-ic/src/Main.java | 49 |
7 files changed, 119 insertions, 18 deletions
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 19f668dc1d..e1cf2485ab 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -672,6 +672,32 @@ HInstanceFieldGet* HInliner::BuildGetReceiverClass(ClassLinker* class_linker, return result; } +static ArtMethod* ResolveMethodFromInlineCache(Handle<mirror::Class> klass, + ArtMethod* resolved_method, + HInstruction* invoke_instruction, + PointerSize pointer_size) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (Runtime::Current()->IsAotCompiler()) { + // We can get unrelated types when working with profiles (corruption, + // systme updates, or anyone can write to it). So first check if the class + // actually implements the declaring class of the method that is being + // called in bytecode. + // Note: the lookup methods used below require to have assignable types. + if (!resolved_method->GetDeclaringClass()->IsAssignableFrom(klass.Get())) { + return nullptr; + } + } + + if (invoke_instruction->IsInvokeInterface()) { + resolved_method = klass->FindVirtualMethodForInterface(resolved_method, pointer_size); + } else { + DCHECK(invoke_instruction->IsInvokeVirtual()); + resolved_method = klass->FindVirtualMethodForVirtual(resolved_method, pointer_size); + } + DCHECK(resolved_method != nullptr); + return resolved_method; +} + bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction, ArtMethod* resolved_method, Handle<mirror::ObjectArray<mirror::Class>> classes) { @@ -690,20 +716,20 @@ bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction, ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker(); PointerSize pointer_size = class_linker->GetImagePointerSize(); - if (invoke_instruction->IsInvokeInterface()) { - resolved_method = GetMonomorphicType(classes)->FindVirtualMethodForInterface( - resolved_method, pointer_size); - } else { - DCHECK(invoke_instruction->IsInvokeVirtual()); - resolved_method = GetMonomorphicType(classes)->FindVirtualMethodForVirtual( - resolved_method, pointer_size); - } + Handle<mirror::Class> monomorphic_type = handles_->NewHandle(GetMonomorphicType(classes)); + resolved_method = ResolveMethodFromInlineCache( + monomorphic_type, resolved_method, invoke_instruction, pointer_size); + LOG_NOTE() << "Try inline monomorphic call to " << resolved_method->PrettyMethod(); - DCHECK(resolved_method != nullptr); + if (resolved_method == nullptr) { + // Bogus AOT profile, bail. + DCHECK(Runtime::Current()->IsAotCompiler()); + return false; + } + HInstruction* receiver = invoke_instruction->InputAt(0); HInstruction* cursor = invoke_instruction->GetPrevious(); HBasicBlock* bb_cursor = invoke_instruction->GetBlock(); - Handle<mirror::Class> monomorphic_type = handles_->NewHandle(GetMonomorphicType(classes)); if (!TryInlineAndReplace(invoke_instruction, resolved_method, ReferenceTypeInfo::Create(monomorphic_type, /* is_exact */ true), @@ -843,11 +869,14 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction, ArtMethod* method = nullptr; Handle<mirror::Class> handle = handles_->NewHandle(classes->Get(i)); - if (invoke_instruction->IsInvokeInterface()) { - method = handle->FindVirtualMethodForInterface(resolved_method, pointer_size); - } else { - DCHECK(invoke_instruction->IsInvokeVirtual()); - method = handle->FindVirtualMethodForVirtual(resolved_method, pointer_size); + method = ResolveMethodFromInlineCache( + handle, resolved_method, invoke_instruction, pointer_size); + if (method == nullptr) { + DCHECK(Runtime::Current()->IsAotCompiler()); + // AOT profile is bogus. This loop expects to iterate over all entries, + // so just just continue. + all_targets_inlined = false; + continue; } HInstruction* receiver = invoke_instruction->InputAt(0); @@ -892,7 +921,7 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction, } invoke_instruction->GetBlock()->RemoveInstruction(invoke_instruction); // Because the inline cache data can be populated concurrently, we force the end of the - // iteration. Otherhwise, we could see a new receiver type. + // iteration. Otherwise, we could see a new receiver type. break; } else { CreateDiamondPatternForPolymorphicInline(compare, return_replacement, invoke_instruction); diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index b47f8f0fc2..5cf0e0f90c 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -32,6 +32,7 @@ #include "mirror/dex_cache-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array.h" +#include "mirror/string.h" #include "oat.h" #include "obj_ptr-inl.h" #include "quick/quick_method_frame_info.h" @@ -56,8 +57,10 @@ inline mirror::Class* ArtMethod::GetDeclaringClass() { if (!IsRuntimeMethod()) { CHECK(result != nullptr) << this; if (kCheckDeclaringClassState) { - CHECK(result->IsIdxLoaded() || result->IsErroneous()) - << result->GetStatus() << " " << result->PrettyClass(); + if (!(result->IsIdxLoaded() || result->IsErroneous())) { + LOG(FATAL_WITHOUT_ABORT) << "Class status: " << result->GetStatus(); + LOG(FATAL) << result->PrettyClass(); + } } } else { CHECK(result == nullptr) << this; diff --git a/test/643-checker-bogus-ic/expected.txt b/test/643-checker-bogus-ic/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/643-checker-bogus-ic/expected.txt diff --git a/test/643-checker-bogus-ic/info.txt b/test/643-checker-bogus-ic/info.txt new file mode 100644 index 0000000000..d5dfff48e4 --- /dev/null +++ b/test/643-checker-bogus-ic/info.txt @@ -0,0 +1 @@ +Verify the compiler can handle a bogus inline cache in a profile. diff --git a/test/643-checker-bogus-ic/profile b/test/643-checker-bogus-ic/profile new file mode 100644 index 0000000000..cbf77961c7 --- /dev/null +++ b/test/643-checker-bogus-ic/profile @@ -0,0 +1,2 @@ +LMain;->inlineMonomorphic(LMain;)I+LUnrelated; +LMain;->inlinePolymorphic(LMain;)I+LUnrelated;,LMain; diff --git a/test/643-checker-bogus-ic/run b/test/643-checker-bogus-ic/run new file mode 100644 index 0000000000..146e180000 --- /dev/null +++ b/test/643-checker-bogus-ic/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright (C) 2017 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. + +exec ${RUN} $@ --profile -Xcompiler-option --compiler-filter=speed-profile diff --git a/test/643-checker-bogus-ic/src/Main.java b/test/643-checker-bogus-ic/src/Main.java new file mode 100644 index 0000000000..0aa84772a8 --- /dev/null +++ b/test/643-checker-bogus-ic/src/Main.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2017 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 Unrelated { +} + +public class Main { + + /// CHECK-START: int Main.inlineMonomorphic(Main) inliner (before) + /// CHECK: InvokeVirtual method_name:Main.getValue + + /// CHECK-START: int Main.inlineMonomorphic(Main) inliner (after) + /// CHECK: InvokeVirtual method_name:Main.getValue + + public static int inlineMonomorphic(Main a) { + return a.getValue(); + } + + /// CHECK-START: int Main.inlinePolymorphic(Main) inliner (before) + /// CHECK: InvokeVirtual method_name:Main.getValue + + /// CHECK-START: int Main.inlinePolymorphic(Main) inliner (after) + /// CHECK: InvokeVirtual method_name:Main.getValue + public static int inlinePolymorphic(Main a) { + return a.getValue(); + } + + public int getValue() { + return 42; + } + + public static void main(String[] args) { + inlineMonomorphic(new Main()); + } + +} |