diff options
Diffstat (limited to 'compiler/optimizing/inliner.cc')
| -rw-r--r-- | compiler/optimizing/inliner.cc | 123 |
1 files changed, 83 insertions, 40 deletions
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index fe4662abb1..e5d05e9e6d 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -344,6 +344,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { if (actual_method != nullptr) { bool result = TryInlineAndReplace(invoke_instruction, actual_method, + ReferenceTypeInfo::CreateInvalid(), /* do_rtp */ true, cha_devirtualize); if (result && !invoke_instruction->IsInvokeStaticOrDirect()) { @@ -428,13 +429,13 @@ HInstanceFieldGet* HInliner::BuildGetReceiverClass(ClassLinker* class_linker, DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_"); HInstanceFieldGet* result = new (graph_->GetArena()) HInstanceFieldGet( receiver, + field, Primitive::kPrimNot, field->GetOffset(), field->IsVolatile(), field->GetDexFieldIndex(), field->GetDeclaringClass()->GetDexClassDefIndex(), *field->GetDexFile(), - handles_->NewHandle(field->GetDexCache()), dex_pc); // The class of a field is effectively final, and does not have any memory dependencies. result->SetSideEffects(SideEffects::None()); @@ -471,22 +472,21 @@ bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction, HInstruction* receiver = invoke_instruction->InputAt(0); HInstruction* cursor = invoke_instruction->GetPrevious(); HBasicBlock* bb_cursor = invoke_instruction->GetBlock(); - + Handle<mirror::Class> handle = handles_->NewHandle(GetMonomorphicType(classes)); if (!TryInlineAndReplace(invoke_instruction, resolved_method, + ReferenceTypeInfo::Create(handle, /* is_exact */ true), /* do_rtp */ false, /* cha_devirtualize */ false)) { return false; } // We successfully inlined, now add a guard. - bool is_referrer = - (GetMonomorphicType(classes) == outermost_graph_->GetArtMethod()->GetDeclaringClass()); AddTypeGuard(receiver, cursor, bb_cursor, class_index, - is_referrer, + GetMonomorphicType(classes), invoke_instruction, /* with_deoptimization */ true); @@ -506,52 +506,62 @@ void HInliner::AddCHAGuard(HInstruction* invoke_instruction, uint32_t dex_pc, HInstruction* cursor, HBasicBlock* bb_cursor) { - HInstruction* deopt_flag = new (graph_->GetArena()) HShouldDeoptimizeFlag(dex_pc); - HInstruction* should_deopt = new (graph_->GetArena()) HNotEqual( + HShouldDeoptimizeFlag* deopt_flag = new (graph_->GetArena()) + HShouldDeoptimizeFlag(graph_->GetArena(), dex_pc); + HInstruction* compare = new (graph_->GetArena()) HNotEqual( deopt_flag, graph_->GetIntConstant(0, dex_pc)); - HInstruction* deopt = new (graph_->GetArena()) HDeoptimize(should_deopt, dex_pc); + HInstruction* deopt = new (graph_->GetArena()) HDeoptimize(compare, dex_pc); if (cursor != nullptr) { bb_cursor->InsertInstructionAfter(deopt_flag, cursor); } else { bb_cursor->InsertInstructionBefore(deopt_flag, bb_cursor->GetFirstInstruction()); } - bb_cursor->InsertInstructionAfter(should_deopt, deopt_flag); - bb_cursor->InsertInstructionAfter(deopt, should_deopt); + bb_cursor->InsertInstructionAfter(compare, deopt_flag); + bb_cursor->InsertInstructionAfter(deopt, compare); + + // Add receiver as input to aid CHA guard optimization later. + deopt_flag->AddInput(invoke_instruction->InputAt(0)); + DCHECK_EQ(deopt_flag->InputCount(), 1u); deopt->CopyEnvironmentFrom(invoke_instruction->GetEnvironment()); + outermost_graph_->IncrementNumberOfCHAGuards(); } HInstruction* HInliner::AddTypeGuard(HInstruction* receiver, HInstruction* cursor, HBasicBlock* bb_cursor, dex::TypeIndex class_index, - bool is_referrer, + mirror::Class* klass, HInstruction* invoke_instruction, bool with_deoptimization) { + ScopedAssertNoThreadSuspension sants("Adding compiler type guard"); + ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker(); HInstanceFieldGet* receiver_class = BuildGetReceiverClass( class_linker, receiver, invoke_instruction->GetDexPc()); + if (cursor != nullptr) { + bb_cursor->InsertInstructionAfter(receiver_class, cursor); + } else { + bb_cursor->InsertInstructionBefore(receiver_class, bb_cursor->GetFirstInstruction()); + } const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile(); + bool is_referrer = (klass == outermost_graph_->GetArtMethod()->GetDeclaringClass()); // Note that we will just compare the classes, so we don't need Java semantics access checks. - // Also, the caller of `AddTypeGuard` must have guaranteed that the class is in the dex cache. + // Note that the type index and the dex file are relative to the method this type guard is + // inlined into. HLoadClass* load_class = new (graph_->GetArena()) HLoadClass(graph_->GetCurrentMethod(), class_index, caller_dex_file, is_referrer, invoke_instruction->GetDexPc(), - /* needs_access_check */ false, - /* is_in_dex_cache */ true, - /* is_in_boot_image */ false); + /* needs_access_check */ false); + bb_cursor->InsertInstructionAfter(load_class, receiver_class); + // Sharpen after adding the instruction, as the sharpening may remove inputs. + HSharpening::SharpenClass(load_class, klass, handles_, codegen_, compiler_driver_); - HNotEqual* compare = new (graph_->GetArena()) HNotEqual(load_class, receiver_class); // TODO: Extend reference type propagation to understand the guard. - if (cursor != nullptr) { - bb_cursor->InsertInstructionAfter(receiver_class, cursor); - } else { - bb_cursor->InsertInstructionBefore(receiver_class, bb_cursor->GetFirstInstruction()); - } - bb_cursor->InsertInstructionAfter(load_class, receiver_class); + HNotEqual* compare = new (graph_->GetArena()) HNotEqual(load_class, receiver_class); bb_cursor->InsertInstructionAfter(compare, load_class); if (with_deoptimization) { HDeoptimize* deoptimize = new (graph_->GetArena()) HDeoptimize( @@ -583,13 +593,13 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction, break; } ArtMethod* method = nullptr; + + Handle<mirror::Class> handle = handles_->NewHandle(classes->Get(i)); if (invoke_instruction->IsInvokeInterface()) { - method = classes->Get(i)->FindVirtualMethodForInterface( - resolved_method, pointer_size); + method = handle->FindVirtualMethodForInterface(resolved_method, pointer_size); } else { DCHECK(invoke_instruction->IsInvokeVirtual()); - method = classes->Get(i)->FindVirtualMethodForVirtual( - resolved_method, pointer_size); + method = handle->FindVirtualMethodForVirtual(resolved_method, pointer_size); } HInstruction* receiver = invoke_instruction->InputAt(0); @@ -597,14 +607,19 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction, HBasicBlock* bb_cursor = invoke_instruction->GetBlock(); dex::TypeIndex class_index = FindClassIndexIn( - classes->Get(i), caller_dex_file, caller_compilation_unit_.GetDexCache()); + handle.Get(), caller_dex_file, caller_compilation_unit_.GetDexCache()); HInstruction* return_replacement = nullptr; if (!class_index.IsValid() || - !TryBuildAndInline(invoke_instruction, method, &return_replacement)) { + !TryBuildAndInline(invoke_instruction, + method, + ReferenceTypeInfo::Create(handle, /* is_exact */ true), + &return_replacement)) { all_targets_inlined = false; } else { one_target_inlined = true; - bool is_referrer = (classes->Get(i) == outermost_graph_->GetArtMethod()->GetDeclaringClass()); + + VLOG(compiler) << "Polymorphic call to " << ArtMethod::PrettyMethod(resolved_method) + << " has inlined " << ArtMethod::PrettyMethod(method); // If we have inlined all targets before, and this receiver is the last seen, // we deoptimize instead of keeping the original invoke instruction. @@ -616,8 +631,13 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction, // We do not support HDeoptimize in OSR methods. deoptimize = false; } - HInstruction* compare = AddTypeGuard( - receiver, cursor, bb_cursor, class_index, is_referrer, invoke_instruction, deoptimize); + HInstruction* compare = AddTypeGuard(receiver, + cursor, + bb_cursor, + class_index, + handle.Get(), + invoke_instruction, + deoptimize); if (deoptimize) { if (return_replacement != nullptr) { invoke_instruction->ReplaceWith(return_replacement); @@ -638,6 +658,7 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction, << " of its targets could be inlined"; return false; } + MaybeRecordStat(kInlinedPolymorphicCall); // Run type propagation to get the guards typed. @@ -780,7 +801,10 @@ bool HInliner::TryInlinePolymorphicCallToSameTarget( HBasicBlock* bb_cursor = invoke_instruction->GetBlock(); HInstruction* return_replacement = nullptr; - if (!TryBuildAndInline(invoke_instruction, actual_method, &return_replacement)) { + if (!TryBuildAndInline(invoke_instruction, + actual_method, + ReferenceTypeInfo::CreateInvalid(), + &return_replacement)) { return false; } @@ -845,13 +869,14 @@ bool HInliner::TryInlinePolymorphicCallToSameTarget( bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction, ArtMethod* method, + ReferenceTypeInfo receiver_type, bool do_rtp, bool cha_devirtualize) { HInstruction* return_replacement = nullptr; uint32_t dex_pc = invoke_instruction->GetDexPc(); HInstruction* cursor = invoke_instruction->GetPrevious(); HBasicBlock* bb_cursor = invoke_instruction->GetBlock(); - if (!TryBuildAndInline(invoke_instruction, method, &return_replacement)) { + if (!TryBuildAndInline(invoke_instruction, method, receiver_type, &return_replacement)) { if (invoke_instruction->IsInvokeInterface()) { // Turn an invoke-interface into an invoke-virtual. An invoke-virtual is always // better than an invoke-interface because: @@ -909,6 +934,7 @@ bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction, bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, ArtMethod* method, + ReferenceTypeInfo receiver_type, HInstruction** return_replacement) { if (method->IsProxyMethod()) { VLOG(compiler) << "Method " << method->PrettyMethod() @@ -985,7 +1011,8 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, return false; } - if (!TryBuildAndInlineHelper(invoke_instruction, method, same_dex_file, return_replacement)) { + if (!TryBuildAndInlineHelper( + invoke_instruction, method, receiver_type, same_dex_file, return_replacement)) { return false; } @@ -1138,13 +1165,13 @@ HInstanceFieldGet* HInliner::CreateInstanceFieldGet(Handle<mirror::DexCache> dex DCHECK(resolved_field != nullptr); HInstanceFieldGet* iget = new (graph_->GetArena()) HInstanceFieldGet( obj, + resolved_field, resolved_field->GetTypeAsPrimitiveType(), resolved_field->GetOffset(), resolved_field->IsVolatile(), field_index, resolved_field->GetDeclaringClass()->GetDexClassDefIndex(), *dex_cache->GetDexFile(), - dex_cache, // Read barrier generates a runtime call in slow path and we need a valid // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537. /* dex_pc */ 0); @@ -1167,13 +1194,13 @@ HInstanceFieldSet* HInliner::CreateInstanceFieldSet(Handle<mirror::DexCache> dex HInstanceFieldSet* iput = new (graph_->GetArena()) HInstanceFieldSet( obj, value, + resolved_field, resolved_field->GetTypeAsPrimitiveType(), resolved_field->GetOffset(), resolved_field->IsVolatile(), field_index, resolved_field->GetDeclaringClass()->GetDexClassDefIndex(), *dex_cache->GetDexFile(), - dex_cache, // Read barrier generates a runtime call in slow path and we need a valid // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537. /* dex_pc */ 0); @@ -1182,8 +1209,10 @@ HInstanceFieldSet* HInliner::CreateInstanceFieldSet(Handle<mirror::DexCache> dex bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, ArtMethod* resolved_method, + ReferenceTypeInfo receiver_type, bool same_dex_file, HInstruction** return_replacement) { + DCHECK(!(resolved_method->IsStatic() && receiver_type.IsValid())); ScopedObjectAccess soa(Thread::Current()); const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); const DexFile& callee_dex_file = *resolved_method->GetDexFile(); @@ -1274,12 +1303,13 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, } size_t parameter_index = 0; + bool run_rtp = false; for (HInstructionIterator instructions(callee_graph->GetEntryBlock()->GetInstructions()); !instructions.Done(); instructions.Advance()) { HInstruction* current = instructions.Current(); if (current->IsParameterValue()) { - HInstruction* argument = invoke_instruction->InputAt(parameter_index++); + HInstruction* argument = invoke_instruction->InputAt(parameter_index); if (argument->IsNullConstant()) { current->ReplaceWith(callee_graph->GetNullConstant()); } else if (argument->IsIntConstant()) { @@ -1293,15 +1323,21 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, current->ReplaceWith( callee_graph->GetDoubleConstant(argument->AsDoubleConstant()->GetValue())); } else if (argument->GetType() == Primitive::kPrimNot) { - current->SetReferenceTypeInfo(argument->GetReferenceTypeInfo()); + if (!resolved_method->IsStatic() && parameter_index == 0 && receiver_type.IsValid()) { + run_rtp = true; + current->SetReferenceTypeInfo(receiver_type); + } else { + current->SetReferenceTypeInfo(argument->GetReferenceTypeInfo()); + } current->AsParameterValue()->SetCanBeNull(argument->CanBeNull()); } + ++parameter_index; } } // We have replaced formal arguments with actual arguments. If actual types // are more specific than the declared ones, run RTP again on the inner graph. - if (ArgumentTypesMoreSpecific(invoke_instruction, resolved_method)) { + if (run_rtp || ArgumentTypesMoreSpecific(invoke_instruction, resolved_method)) { ReferenceTypePropagation(callee_graph, dex_compilation_unit.GetDexCache(), handles_, @@ -1490,7 +1526,7 @@ static bool IsReferenceTypeRefinement(ReferenceTypeInfo declared_rti, ReferenceTypeInfo actual_rti = actual_obj->GetReferenceTypeInfo(); return (actual_rti.IsExact() && !declared_rti.IsExact()) || - declared_rti.IsStrictSupertypeOf(actual_rti); + declared_rti.IsStrictSupertypeOf(actual_rti); } ReferenceTypeInfo HInliner::GetClassRTI(mirror::Class* klass) { @@ -1547,6 +1583,13 @@ bool HInliner::ReturnTypeMoreSpecific(HInvoke* invoke_instruction, /* declared_can_be_null */ true, return_replacement)) { return true; + } else if (return_replacement->IsInstanceFieldGet()) { + HInstanceFieldGet* field_get = return_replacement->AsInstanceFieldGet(); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + if (field_get->GetFieldInfo().GetField() == + class_linker->GetClassRoot(ClassLinker::kJavaLangObject)->GetInstanceField(0)) { + return true; + } } } else if (return_replacement->IsInstanceOf()) { // Inlining InstanceOf into an If may put a tighter bound on reference types. |