diff options
Diffstat (limited to 'compiler/optimizing/inliner.cc')
| -rw-r--r-- | compiler/optimizing/inliner.cc | 142 | 
1 files changed, 120 insertions, 22 deletions
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 2e79df1b84..35109fa538 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -296,9 +296,29 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) {    return false;  } +HInstanceFieldGet* HInliner::BuildGetReceiverClass(ClassLinker* class_linker, +                                                   HInstruction* receiver, +                                                   uint32_t dex_pc) const { +  ArtField* field = class_linker->GetClassRoot(ClassLinker::kJavaLangObject)->GetInstanceField(0); +  DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_"); +  return new (graph_->GetArena()) HInstanceFieldGet( +      receiver, +      Primitive::kPrimNot, +      field->GetOffset(), +      field->IsVolatile(), +      field->GetDexFieldIndex(), +      field->GetDeclaringClass()->GetDexClassDefIndex(), +      *field->GetDexFile(), +      handles_->NewHandle(field->GetDexCache()), +      dex_pc); +} +  bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction,                                          ArtMethod* resolved_method,                                          const InlineCache& ic) { +  DCHECK(invoke_instruction->IsInvokeVirtual() || invoke_instruction->IsInvokeInterface()) +      << invoke_instruction->DebugName(); +    const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();    uint32_t class_index = FindClassIndexIn(ic.GetMonomorphicType(), caller_dex_file);    if (class_index == DexFile::kDexNoIndex) { @@ -328,18 +348,8 @@ bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction,    }    // We successfully inlined, now add a guard. -  ArtField* field = class_linker->GetClassRoot(ClassLinker::kJavaLangObject)->GetInstanceField(0); -  DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_"); -  HInstanceFieldGet* field_get = new (graph_->GetArena()) HInstanceFieldGet( -      receiver, -      Primitive::kPrimNot, -      field->GetOffset(), -      field->IsVolatile(), -      field->GetDexFieldIndex(), -      field->GetDeclaringClass()->GetDexClassDefIndex(), -      *field->GetDexFile(), -      handles_->NewHandle(field->GetDexCache()), -      invoke_instruction->GetDexPc()); +  HInstanceFieldGet* receiver_class = BuildGetReceiverClass( +      class_linker, receiver, invoke_instruction->GetDexPc());    bool is_referrer =        (ic.GetMonomorphicType() == outermost_graph_->GetArtMethod()->GetDeclaringClass()); @@ -351,16 +361,16 @@ bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction,                                                                 /* needs_access_check */ false,                                                                 /* is_in_dex_cache */ true); -  HNotEqual* compare = new (graph_->GetArena()) HNotEqual(load_class, field_get); +  HNotEqual* compare = new (graph_->GetArena()) HNotEqual(load_class, receiver_class);    HDeoptimize* deoptimize = new (graph_->GetArena()) HDeoptimize(        compare, invoke_instruction->GetDexPc());    // TODO: Extend reference type propagation to understand the guard.    if (cursor != nullptr) { -    bb_cursor->InsertInstructionAfter(field_get, cursor); +    bb_cursor->InsertInstructionAfter(receiver_class, cursor);    } else { -    bb_cursor->InsertInstructionBefore(field_get, bb_cursor->GetFirstInstruction()); +    bb_cursor->InsertInstructionBefore(receiver_class, bb_cursor->GetFirstInstruction());    } -  bb_cursor->InsertInstructionAfter(load_class, field_get); +  bb_cursor->InsertInstructionAfter(load_class, receiver_class);    bb_cursor->InsertInstructionAfter(compare, load_class);    bb_cursor->InsertInstructionAfter(deoptimize, compare);    deoptimize->CopyEnvironmentFrom(invoke_instruction->GetEnvironment()); @@ -374,13 +384,101 @@ bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction,    return true;  } -bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction ATTRIBUTE_UNUSED, +bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction,                                          ArtMethod* resolved_method, -                                        const InlineCache& ic ATTRIBUTE_UNUSED) { -  // TODO -  VLOG(compiler) << "Unimplemented polymorphic inlining for " -                 << PrettyMethod(resolved_method); -  return false; +                                        const InlineCache& ic) { +  DCHECK(invoke_instruction->IsInvokeVirtual() || invoke_instruction->IsInvokeInterface()) +      << invoke_instruction->DebugName(); +  // This optimization only works under JIT for now. +  DCHECK(Runtime::Current()->UseJit()); +  if (graph_->GetInstructionSet() == kMips || graph_->GetInstructionSet() == kMips64) { +    // TODO: Support HClassTableGet for mips and mips64. +    return false; +  } +  ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker(); +  size_t pointer_size = class_linker->GetImagePointerSize(); + +  DCHECK(resolved_method != nullptr); +  ArtMethod* actual_method = nullptr; +  // Check whether we are actually calling the same method among +  // the different types seen. +  for (size_t i = 0; i < InlineCache::kIndividualCacheSize; ++i) { +    if (ic.GetTypeAt(i) == nullptr) { +      break; +    } +    ArtMethod* new_method = nullptr; +    if (invoke_instruction->IsInvokeInterface()) { +      new_method = ic.GetTypeAt(i)->FindVirtualMethodForInterface( +          resolved_method, pointer_size); +    } else { +      DCHECK(invoke_instruction->IsInvokeVirtual()); +      new_method = ic.GetTypeAt(i)->FindVirtualMethodForVirtual( +          resolved_method, pointer_size); +    } +    if (actual_method == nullptr) { +      actual_method = new_method; +    } else if (actual_method != new_method) { +      // Different methods, bailout. +      return false; +    } +  } + +  HInstruction* receiver = invoke_instruction->InputAt(0); +  HInstruction* cursor = invoke_instruction->GetPrevious(); +  HBasicBlock* bb_cursor = invoke_instruction->GetBlock(); + +  if (!TryInline(invoke_instruction, actual_method, /* do_rtp */ false)) { +    return false; +  } + +  // We successfully inlined, now add a guard. +  HInstanceFieldGet* receiver_class = BuildGetReceiverClass( +      class_linker, receiver, invoke_instruction->GetDexPc()); + +  size_t method_offset = invoke_instruction->IsInvokeVirtual() +      ? actual_method->GetVtableIndex() +      : invoke_instruction->AsInvokeInterface()->GetImtIndex(); + +  Primitive::Type type = Is64BitInstructionSet(graph_->GetInstructionSet()) +      ? Primitive::kPrimLong +      : Primitive::kPrimInt; +  HClassTableGet* class_table_get = new (graph_->GetArena()) HClassTableGet( +      receiver_class, +      type, +      invoke_instruction->IsInvokeVirtual() ? HClassTableGet::kVTable : HClassTableGet::kIMTable, +      method_offset, +      invoke_instruction->GetDexPc()); + +  HConstant* constant; +  if (type == Primitive::kPrimLong) { +    constant = graph_->GetLongConstant( +        reinterpret_cast<intptr_t>(actual_method), invoke_instruction->GetDexPc()); +  } else { +    constant = graph_->GetIntConstant( +        reinterpret_cast<intptr_t>(actual_method), invoke_instruction->GetDexPc()); +  } + +  HNotEqual* compare = new (graph_->GetArena()) HNotEqual(class_table_get, constant); +  HDeoptimize* deoptimize = new (graph_->GetArena()) HDeoptimize( +      compare, invoke_instruction->GetDexPc()); +  // 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(class_table_get, receiver_class); +  bb_cursor->InsertInstructionAfter(compare, class_table_get); +  bb_cursor->InsertInstructionAfter(deoptimize, compare); +  deoptimize->CopyEnvironmentFrom(invoke_instruction->GetEnvironment()); + +  // Run type propagation to get the guard typed. +  ReferenceTypePropagation rtp_fixup(graph_, handles_); +  rtp_fixup.Run(); + +  MaybeRecordStat(kInlinedPolymorphicCall); + +  return true;  }  bool HInliner::TryInline(HInvoke* invoke_instruction, ArtMethod* method, bool do_rtp) {  |