diff options
Diffstat (limited to 'compiler')
48 files changed, 1216 insertions, 585 deletions
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc index fc6a717aa6..e41371855d 100644 --- a/compiler/compiled_method.cc +++ b/compiler/compiled_method.cc @@ -26,8 +26,8 @@ CompiledCode::CompiledCode(CompilerDriver* compiler_driver,                             InstructionSet instruction_set,                             const ArrayRef<const uint8_t>& quick_code)      : compiler_driver_(compiler_driver), -      instruction_set_(instruction_set), -      quick_code_(compiler_driver_->GetCompiledMethodStorage()->DeduplicateCode(quick_code)) { +      quick_code_(compiler_driver_->GetCompiledMethodStorage()->DeduplicateCode(quick_code)), +      packed_fields_(InstructionSetField::Encode(instruction_set)) {  }  CompiledCode::~CompiledCode() { @@ -48,7 +48,7 @@ bool CompiledCode::operator==(const CompiledCode& rhs) const {  }  size_t CompiledCode::AlignCode(size_t offset) const { -  return AlignCode(offset, instruction_set_); +  return AlignCode(offset, GetInstructionSet());  }  size_t CompiledCode::AlignCode(size_t offset, InstructionSet instruction_set) { @@ -56,7 +56,7 @@ size_t CompiledCode::AlignCode(size_t offset, InstructionSet instruction_set) {  }  size_t CompiledCode::CodeDelta() const { -  return CodeDelta(instruction_set_); +  return CodeDelta(GetInstructionSet());  }  size_t CompiledCode::CodeDelta(InstructionSet instruction_set) { diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index 892bc592db..acdce260e5 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -22,6 +22,8 @@  #include <vector>  #include "arch/instruction_set.h" +#include "base/bit_field.h" +#include "base/bit_utils.h"  namespace art { @@ -44,7 +46,7 @@ class CompiledCode {    virtual ~CompiledCode();    InstructionSet GetInstructionSet() const { -    return instruction_set_; +    return GetPackedField<InstructionSetField>();    }    ArrayRef<const uint8_t> GetQuickCode() const; @@ -68,6 +70,11 @@ class CompiledCode {    static const void* CodePointer(const void* code_pointer, InstructionSet instruction_set);   protected: +  static constexpr size_t kInstructionSetFieldSize = +      MinimumBitsToStore(static_cast<size_t>(InstructionSet::kLast)); +  static constexpr size_t kNumberOfCompiledCodePackedBits = kInstructionSetFieldSize; +  static constexpr size_t kMaxNumberOfPackedBits = sizeof(uint32_t) * kBitsPerByte; +    template <typename T>    static ArrayRef<const T> GetArray(const LengthPrefixedArray<T>* array); @@ -75,13 +82,26 @@ class CompiledCode {      return compiler_driver_;    } +  template <typename BitFieldType> +  typename BitFieldType::value_type GetPackedField() const { +    return BitFieldType::Decode(packed_fields_); +  } + +  template <typename BitFieldType> +  void SetPackedField(typename BitFieldType::value_type value) { +    DCHECK(IsUint<BitFieldType::size>(static_cast<uintptr_t>(value))); +    packed_fields_ = BitFieldType::Update(value, packed_fields_); +  } +   private: -  CompilerDriver* const compiler_driver_; +  using InstructionSetField = BitField<InstructionSet, 0u, kInstructionSetFieldSize>; -  const InstructionSet instruction_set_; +  CompilerDriver* const compiler_driver_; -  // Used to store the PIC code for Quick. +  // Used to store the compiled code.    const LengthPrefixedArray<uint8_t>* const quick_code_; + +  uint32_t packed_fields_;  };  class CompiledMethod FINAL : public CompiledCode { @@ -116,6 +136,18 @@ class CompiledMethod FINAL : public CompiledCode {    static void ReleaseSwapAllocatedCompiledMethod(CompilerDriver* driver, CompiledMethod* m); +  bool IsIntrinsic() const { +    return GetPackedField<IsIntrinsicField>(); +  } + +  // Marks the compiled method as being generated using an intrinsic codegen. +  // Such methods have no relationships to their code items. +  // This affects debug information generated at link time. +  void MarkAsIntrinsic() { +    DCHECK(!IsIntrinsic()); +    SetPackedField<IsIntrinsicField>(/* value */ true); +  } +    size_t GetFrameSizeInBytes() const {      return frame_size_in_bytes_;    } @@ -137,6 +169,14 @@ class CompiledMethod FINAL : public CompiledCode {    ArrayRef<const linker::LinkerPatch> GetPatches() const;   private: +  static constexpr size_t kIsIntrinsicLsb = kNumberOfCompiledCodePackedBits; +  static constexpr size_t kIsIntrinsicSize = 1u; +  static constexpr size_t kNumberOfCompiledMethodPackedBits = kIsIntrinsicLsb + kIsIntrinsicSize; +  static_assert(kNumberOfCompiledMethodPackedBits <= CompiledCode::kMaxNumberOfPackedBits, +                "Too many packed fields."); + +  using IsIntrinsicField = BitField<bool, kIsIntrinsicLsb, kIsIntrinsicSize>; +    // For quick code, the size of the activation used by the code.    const size_t frame_size_in_bytes_;    // For quick code, a bit mask describing spilled GPR callee-save registers. diff --git a/compiler/compiler.h b/compiler/compiler.h index 3aa84f8e2b..85abd6654c 100644 --- a/compiler/compiler.h +++ b/compiler/compiler.h @@ -65,7 +65,8 @@ class Compiler {    virtual CompiledMethod* JniCompile(uint32_t access_flags,                                       uint32_t method_idx, -                                     const DexFile& dex_file) const = 0; +                                     const DexFile& dex_file, +                                     Handle<mirror::DexCache> dex_cache) const = 0;    virtual bool JitCompile(Thread* self ATTRIBUTE_UNUSED,                            jit::JitCodeCache* code_cache ATTRIBUTE_UNUSED, diff --git a/compiler/debug/dwarf/dwarf_test.cc b/compiler/debug/dwarf/dwarf_test.cc index 866bf4394d..933034f593 100644 --- a/compiler/debug/dwarf/dwarf_test.cc +++ b/compiler/debug/dwarf/dwarf_test.cc @@ -125,7 +125,7 @@ TEST_F(DwarfTest, DebugFrame) {    WriteCIE(is64bit, Reg(is64bit ? 16 : 8),             initial_opcodes, kCFIFormat, &debug_frame_data_);    std::vector<uintptr_t> debug_frame_patches; -  std::vector<uintptr_t> expected_patches { 28 };  // NOLINT +  std::vector<uintptr_t> expected_patches = { 28 };    WriteFDE(is64bit, 0, 0, 0x01000000, 0x01000000, ArrayRef<const uint8_t>(*opcodes.data()),             kCFIFormat, 0, &debug_frame_data_, &debug_frame_patches); @@ -140,7 +140,7 @@ TEST_F(DwarfTest, DebugFrame64) {             initial_opcodes, kCFIFormat, &debug_frame_data_);    DebugFrameOpCodeWriter<> opcodes;    std::vector<uintptr_t> debug_frame_patches; -  std::vector<uintptr_t> expected_patches { 32 };  // NOLINT +  std::vector<uintptr_t> expected_patches = { 32 };    WriteFDE(is64bit, 0, 0, 0x0100000000000000, 0x0200000000000000,             ArrayRef<const uint8_t>(*opcodes.data()),                       kCFIFormat, 0, &debug_frame_data_, &debug_frame_patches); @@ -237,7 +237,7 @@ TEST_F(DwarfTest, DebugLine) {    DW_CHECK_NEXT("1\t0\t1000\t2000\tfile.c");    std::vector<uintptr_t> debug_line_patches; -  std::vector<uintptr_t> expected_patches { 87 };  // NOLINT +  std::vector<uintptr_t> expected_patches = { 87 };    WriteDebugLineTable(include_directories, files, opcodes,                        0, &debug_line_data_, &debug_line_patches); @@ -275,7 +275,7 @@ TEST_F(DwarfTest, DebugLineSpecialOpcodes) {    EXPECT_LT(opcodes.data()->size(), num_rows * 3);    std::vector<std::string> directories; -  std::vector<FileEntry> files { { "file.c", 0, 1000, 2000 } };  // NOLINT +  std::vector<FileEntry> files = { { "file.c", 0, 1000, 2000 } };    std::vector<uintptr_t> debug_line_patches;    WriteDebugLineTable(directories, files, opcodes,                        0, &debug_line_data_, &debug_line_patches); @@ -333,7 +333,7 @@ TEST_F(DwarfTest, DebugInfo) {    DW_CHECK("3      DW_TAG_compile_unit    [no children]");    std::vector<uintptr_t> debug_info_patches; -  std::vector<uintptr_t> expected_patches { 16, 20, 29, 33, 42, 46 };  // NOLINT +  std::vector<uintptr_t> expected_patches = { 16, 20, 29, 33, 42, 46 };    dwarf::WriteDebugInfoCU(0 /* debug_abbrev_offset */, info,                            0, &debug_info_data_, &debug_info_patches); diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h index 2b617273b5..37c2d32091 100644 --- a/compiler/debug/elf_debug_info_writer.h +++ b/compiler/debug/elf_debug_info_writer.h @@ -202,7 +202,7 @@ class ElfCompilationUnitWriter {        // Decode dex register locations for all stack maps.        // It might be expensive, so do it just once and reuse the result.        std::vector<DexRegisterMap> dex_reg_maps; -      if (mi->code_info != nullptr) { +      if (dex_code != nullptr && mi->code_info != nullptr) {          const CodeInfo code_info(mi->code_info);          CodeInfoEncoding encoding = code_info.ExtractEncoding();          for (size_t s = 0; s < code_info.GetNumberOfStackMaps(encoding); ++s) { diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index f4700d4040..726401d09e 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -516,7 +516,8 @@ static void CompileMethod(Thread* self,        access_flags |= annotations::GetNativeMethodAnnotationAccessFlags(            dex_file, dex_file.GetClassDef(class_def_idx), method_idx); -      compiled_method = driver->GetCompiler()->JniCompile(access_flags, method_idx, dex_file); +      compiled_method = driver->GetCompiler()->JniCompile( +          access_flags, method_idx, dex_file, dex_cache);        CHECK(compiled_method != nullptr);      }    } else if ((access_flags & kAccAbstract) != 0) { diff --git a/compiler/driver/compiler_options_map-storage.h b/compiler/driver/compiler_options_map-storage.h index 756598de05..01f32e0c9c 100644 --- a/compiler/driver/compiler_options_map-storage.h +++ b/compiler/driver/compiler_options_map-storage.h @@ -36,7 +36,7 @@  #define COMPILER_OPTIONS_KEY(Type, Name, ...) \    template <typename Base, template <typename TV> class KeyType> \ -  const KeyType<Type> CompilerOptionsMap<Base, KeyType>::Name {__VA_ARGS__};  // NOLINT [readability/braces] [4] +  const KeyType<Type> CompilerOptionsMap<Base, KeyType>::Name {__VA_ARGS__};  #include <driver/compiler_options_map.def>  template struct CompilerOptionsMap<COMPILER_OPTIONS_MAP_TYPE, COMPILER_OPTIONS_MAP_KEY_TYPE>; diff --git a/compiler/optimizing/block_builder.cc b/compiler/optimizing/block_builder.cc index 2432f13044..a6687fe258 100644 --- a/compiler/optimizing/block_builder.cc +++ b/compiler/optimizing/block_builder.cc @@ -40,20 +40,20 @@ bool HBasicBlockBuilder::CreateBranchTargets() {    // Create the first block for the dex instructions, single successor of the entry block.    MaybeCreateBlockAt(0u); -  if (code_item_.tries_size_ != 0) { +  if (code_item_->tries_size_ != 0) {      // Create branch targets at the start/end of the TryItem range. These are      // places where the program might fall through into/out of the a block and      // where TryBoundary instructions will be inserted later. Other edges which      // enter/exit the try blocks are a result of branches/switches. -    for (size_t idx = 0; idx < code_item_.tries_size_; ++idx) { -      const DexFile::TryItem* try_item = DexFile::GetTryItems(code_item_, idx); +    for (size_t idx = 0; idx < code_item_->tries_size_; ++idx) { +      const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item_, idx);        uint32_t dex_pc_start = try_item->start_addr_;        uint32_t dex_pc_end = dex_pc_start + try_item->insn_count_;        MaybeCreateBlockAt(dex_pc_start); -      if (dex_pc_end < code_item_.insns_size_in_code_units_) { +      if (dex_pc_end < code_item_->insns_size_in_code_units_) {          // TODO: Do not create block if the last instruction cannot fall through.          MaybeCreateBlockAt(dex_pc_end); -      } else if (dex_pc_end == code_item_.insns_size_in_code_units_) { +      } else if (dex_pc_end == code_item_->insns_size_in_code_units_) {          // The TryItem spans until the very end of the CodeItem and therefore          // cannot have any code afterwards.        } else { @@ -63,7 +63,7 @@ bool HBasicBlockBuilder::CreateBranchTargets() {      }      // Create branch targets for exception handlers. -    const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(code_item_, 0); +    const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);      uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);      for (uint32_t idx = 0; idx < handlers_size; ++idx) {        CatchHandlerIterator iterator(handlers_ptr); @@ -76,7 +76,7 @@ bool HBasicBlockBuilder::CreateBranchTargets() {    // Iterate over all instructions and find branching instructions. Create blocks for    // the locations these instructions branch to. -  IterationRange<DexInstructionIterator> instructions = code_item_.Instructions(); +  IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();    for (const DexInstructionPcPair& pair : instructions) {      const uint32_t dex_pc = pair.DexPc();      const Instruction& instruction = pair.Inst(); @@ -127,7 +127,7 @@ void HBasicBlockBuilder::ConnectBasicBlocks() {    bool is_throwing_block = false;    // Calculate the qucikening index here instead of CreateBranchTargets since it's easier to    // calculate in dex_pc order. -  for (const DexInstructionPcPair& pair : code_item_.Instructions()) { +  for (const DexInstructionPcPair& pair : code_item_->Instructions()) {      const uint32_t dex_pc = pair.DexPc();      const Instruction& instruction = pair.Inst(); @@ -229,7 +229,7 @@ bool HBasicBlockBuilder::MightHaveLiveNormalPredecessors(HBasicBlock* catch_bloc      }    } -  const Instruction& first = code_item_.InstructionAt(catch_block->GetDexPc()); +  const Instruction& first = code_item_->InstructionAt(catch_block->GetDexPc());    if (first.Opcode() == Instruction::MOVE_EXCEPTION) {      // Verifier guarantees that if a catch block begins with MOVE_EXCEPTION then      // it has no live normal predecessors. @@ -247,7 +247,7 @@ bool HBasicBlockBuilder::MightHaveLiveNormalPredecessors(HBasicBlock* catch_bloc  }  void HBasicBlockBuilder::InsertTryBoundaryBlocks() { -  if (code_item_.tries_size_ == 0) { +  if (code_item_->tries_size_ == 0) {      return;    } @@ -269,12 +269,12 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() {      // loop for synchronized blocks.      if (ContainsElement(throwing_blocks_, block)) {        // Try to find a TryItem covering the block. -      const int32_t try_item_idx = DexFile::FindTryItem(DexFile::GetTryItems(code_item_, 0u), -                                                        code_item_.tries_size_, +      const int32_t try_item_idx = DexFile::FindTryItem(DexFile::GetTryItems(*code_item_, 0u), +                                                        code_item_->tries_size_,                                                          block->GetDexPc());        if (try_item_idx != -1) {          // Block throwing and in a TryItem. Store the try block information. -        try_block_info.Put(block->GetBlockId(), DexFile::GetTryItems(code_item_, try_item_idx)); +        try_block_info.Put(block->GetBlockId(), DexFile::GetTryItems(*code_item_, try_item_idx));        }      }    } @@ -285,7 +285,7 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() {    // Iterate over catch blocks, create artifical landing pads if necessary to    // simplify the CFG, and set metadata. -  const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(code_item_, 0); +  const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);    uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);    for (uint32_t idx = 0; idx < handlers_size; ++idx) {      CatchHandlerIterator iterator(handlers_ptr); @@ -333,7 +333,7 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() {          HTryBoundary* try_entry = new (allocator_) HTryBoundary(              HTryBoundary::BoundaryKind::kEntry, try_block->GetDexPc());          try_block->CreateImmediateDominator()->AddInstruction(try_entry); -        LinkToCatchBlocks(try_entry, code_item_, try_item, catch_blocks); +        LinkToCatchBlocks(try_entry, *code_item_, try_item, catch_blocks);          break;        }      } @@ -361,12 +361,13 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() {        HTryBoundary* try_exit =            new (allocator_) HTryBoundary(HTryBoundary::BoundaryKind::kExit, successor->GetDexPc());        graph_->SplitEdge(try_block, successor)->AddInstruction(try_exit); -      LinkToCatchBlocks(try_exit, code_item_, try_item, catch_blocks); +      LinkToCatchBlocks(try_exit, *code_item_, try_item, catch_blocks);      }    }  }  bool HBasicBlockBuilder::Build() { +  DCHECK(code_item_ != nullptr);    DCHECK(graph_->GetBlocks().empty());    graph_->SetEntryBlock(new (allocator_) HBasicBlock(graph_, kNoDexPc)); @@ -383,6 +384,27 @@ bool HBasicBlockBuilder::Build() {    return true;  } +void HBasicBlockBuilder::BuildIntrinsic() { +  DCHECK(code_item_ == nullptr); +  DCHECK(graph_->GetBlocks().empty()); + +  // Create blocks. +  HBasicBlock* entry_block = new (allocator_) HBasicBlock(graph_, kNoDexPc); +  HBasicBlock* exit_block = new (allocator_) HBasicBlock(graph_, kNoDexPc); +  HBasicBlock* body = MaybeCreateBlockAt(/* semantic_dex_pc */ kNoDexPc, /* store_dex_pc */ 0u); + +  // Add blocks to the graph. +  graph_->AddBlock(entry_block); +  graph_->AddBlock(body); +  graph_->AddBlock(exit_block); +  graph_->SetEntryBlock(entry_block); +  graph_->SetExitBlock(exit_block); + +  // Connect blocks. +  entry_block->AddSuccessor(body); +  body->AddSuccessor(exit_block); +} +  size_t HBasicBlockBuilder::GetQuickenIndex(uint32_t dex_pc) const {    return quicken_index_for_dex_pc_.Get(dex_pc);  } diff --git a/compiler/optimizing/block_builder.h b/compiler/optimizing/block_builder.h index 79f7a7bc81..7d0f56db34 100644 --- a/compiler/optimizing/block_builder.h +++ b/compiler/optimizing/block_builder.h @@ -28,14 +28,15 @@ class HBasicBlockBuilder : public ValueObject {   public:    HBasicBlockBuilder(HGraph* graph,                       const DexFile* const dex_file, -                     const DexFile::CodeItem& code_item, +                     const DexFile::CodeItem* code_item,                       ScopedArenaAllocator* local_allocator)        : allocator_(graph->GetAllocator()),          graph_(graph),          dex_file_(dex_file),          code_item_(code_item),          local_allocator_(local_allocator), -        branch_targets_(code_item.insns_size_in_code_units_, +        branch_targets_(code_item != nullptr ? code_item->insns_size_in_code_units_ +                                             : /* fake dex_pc=0 for intrinsic graph */ 1u,                          nullptr,                          local_allocator->Adapter(kArenaAllocGraphBuilder)),          throwing_blocks_(kDefaultNumberOfThrowingBlocks, @@ -50,6 +51,9 @@ class HBasicBlockBuilder : public ValueObject {    // exits a try block.    bool Build(); +  // Creates basic blocks in `graph_` for compiling an intrinsic. +  void BuildIntrinsic(); +    size_t GetNumberOfBranches() const { return number_of_branches_; }    HBasicBlock* GetBlockAt(uint32_t dex_pc) const { return branch_targets_[dex_pc]; } @@ -79,7 +83,7 @@ class HBasicBlockBuilder : public ValueObject {    HGraph* const graph_;    const DexFile* const dex_file_; -  const DexFile::CodeItem& code_item_; +  const DexFile::CodeItem* const code_item_;  // null for intrinsic graph.    ScopedArenaAllocator* const local_allocator_;    ScopedArenaVector<HBasicBlock*> branch_targets_; diff --git a/compiler/optimizing/bounds_check_elimination.h b/compiler/optimizing/bounds_check_elimination.h index 6dc53207ea..79c67a8c7a 100644 --- a/compiler/optimizing/bounds_check_elimination.h +++ b/compiler/optimizing/bounds_check_elimination.h @@ -28,8 +28,9 @@ class BoundsCheckElimination : public HOptimization {   public:    BoundsCheckElimination(HGraph* graph,                           const SideEffectsAnalysis& side_effects, -                         HInductionVarAnalysis* induction_analysis) -      : HOptimization(graph, kBoundsCheckEliminationPassName), +                         HInductionVarAnalysis* induction_analysis, +                         const char* name = kBoundsCheckEliminationPassName) +      : HOptimization(graph, name),          side_effects_(side_effects),          induction_analysis_(induction_analysis) {} diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 4ed1612220..d73ef1f3a1 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -24,6 +24,7 @@  #include "data_type-inl.h"  #include "dex/verified_method.h"  #include "driver/compiler_options.h" +#include "driver/dex_compilation_unit.h"  #include "instruction_builder.h"  #include "mirror/class_loader.h"  #include "mirror/dex_cache.h" @@ -36,6 +37,7 @@  namespace art {  HGraphBuilder::HGraphBuilder(HGraph* graph, +                             const DexFile::CodeItem* code_item,                               const DexCompilationUnit* dex_compilation_unit,                               const DexCompilationUnit* outer_compilation_unit,                               CompilerDriver* driver, @@ -45,7 +47,7 @@ HGraphBuilder::HGraphBuilder(HGraph* graph,                               VariableSizedHandleScope* handles)      : graph_(graph),        dex_file_(&graph->GetDexFile()), -      code_item_(*dex_compilation_unit->GetCodeItem()), +      code_item_(code_item),        dex_compilation_unit_(dex_compilation_unit),        outer_compilation_unit_(outer_compilation_unit),        compiler_driver_(driver), @@ -67,23 +69,21 @@ bool HGraphBuilder::SkipCompilation(size_t number_of_branches) {      return false;    } -  if (compiler_options.IsHugeMethod(code_item_.insns_size_in_code_units_)) { +  if (compiler_options.IsHugeMethod(code_item_->insns_size_in_code_units_)) {      VLOG(compiler) << "Skip compilation of huge method "                     << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) -                   << ": " << code_item_.insns_size_in_code_units_ << " code units"; -    MaybeRecordStat(compilation_stats_, -                    MethodCompilationStat::kNotCompiledHugeMethod); +                   << ": " << code_item_->insns_size_in_code_units_ << " code units"; +    MaybeRecordStat(compilation_stats_, MethodCompilationStat::kNotCompiledHugeMethod);      return true;    }    // If it's large and contains no branches, it's likely to be machine generated initialization. -  if (compiler_options.IsLargeMethod(code_item_.insns_size_in_code_units_) +  if (compiler_options.IsLargeMethod(code_item_->insns_size_in_code_units_)        && (number_of_branches == 0)) {      VLOG(compiler) << "Skip compilation of large method with no branch "                     << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) -                   << ": " << code_item_.insns_size_in_code_units_ << " code units"; -    MaybeRecordStat(compilation_stats_, -                    MethodCompilationStat::kNotCompiledLargeMethodNoBranches); +                   << ": " << code_item_->insns_size_in_code_units_ << " code units"; +    MaybeRecordStat(compilation_stats_, MethodCompilationStat::kNotCompiledLargeMethodNoBranches);      return true;    } @@ -91,12 +91,13 @@ bool HGraphBuilder::SkipCompilation(size_t number_of_branches) {  }  GraphAnalysisResult HGraphBuilder::BuildGraph() { +  DCHECK(code_item_ != nullptr);    DCHECK(graph_->GetBlocks().empty()); -  graph_->SetNumberOfVRegs(code_item_.registers_size_); -  graph_->SetNumberOfInVRegs(code_item_.ins_size_); -  graph_->SetMaximumNumberOfOutVRegs(code_item_.outs_size_); -  graph_->SetHasTryCatch(code_item_.tries_size_ != 0); +  graph_->SetNumberOfVRegs(code_item_->registers_size_); +  graph_->SetNumberOfInVRegs(code_item_->ins_size_); +  graph_->SetMaximumNumberOfOutVRegs(code_item_->outs_size_); +  graph_->SetHasTryCatch(code_item_->tries_size_ != 0);    // Use ScopedArenaAllocator for all local allocations.    ScopedArenaAllocator local_allocator(graph_->GetArenaStack()); @@ -148,4 +149,61 @@ GraphAnalysisResult HGraphBuilder::BuildGraph() {    return ssa_builder.BuildSsa();  } +void HGraphBuilder::BuildIntrinsicGraph(ArtMethod* method) { +  DCHECK(code_item_ == nullptr); +  DCHECK(graph_->GetBlocks().empty()); + +  // Determine the number of arguments and associated vregs. +  uint32_t method_idx = dex_compilation_unit_->GetDexMethodIndex(); +  const char* shorty = dex_file_->GetMethodShorty(dex_file_->GetMethodId(method_idx)); +  size_t num_args = strlen(shorty + 1); +  size_t num_wide_args = std::count(shorty + 1, shorty + 1 + num_args, 'J') + +                         std::count(shorty + 1, shorty + 1 + num_args, 'D'); +  size_t num_arg_vregs = num_args + num_wide_args + (dex_compilation_unit_->IsStatic() ? 0u : 1u); + +  // For simplicity, reserve 2 vregs (the maximum) for return value regardless of the return type. +  size_t return_vregs = 2u; +  graph_->SetNumberOfVRegs(return_vregs + num_arg_vregs); +  graph_->SetNumberOfInVRegs(num_arg_vregs); +  graph_->SetMaximumNumberOfOutVRegs(num_arg_vregs); +  graph_->SetHasTryCatch(false); + +  // Use ScopedArenaAllocator for all local allocations. +  ScopedArenaAllocator local_allocator(graph_->GetArenaStack()); +  HBasicBlockBuilder block_builder(graph_, dex_file_, /* code_item */ nullptr, &local_allocator); +  SsaBuilder ssa_builder(graph_, +                         dex_compilation_unit_->GetClassLoader(), +                         dex_compilation_unit_->GetDexCache(), +                         handles_, +                         &local_allocator); +  HInstructionBuilder instruction_builder(graph_, +                                          &block_builder, +                                          &ssa_builder, +                                          dex_file_, +                                          /* code_item */ nullptr, +                                          return_type_, +                                          dex_compilation_unit_, +                                          outer_compilation_unit_, +                                          compiler_driver_, +                                          code_generator_, +                                          interpreter_metadata_, +                                          compilation_stats_, +                                          handles_, +                                          &local_allocator); + +  // 1) Create basic blocks for the intrinsic and link them together. +  block_builder.BuildIntrinsic(); + +  // 2) Build the trivial dominator tree. +  GraphAnalysisResult bdt_result = graph_->BuildDominatorTree(); +  DCHECK_EQ(bdt_result, kAnalysisSuccess); + +  // 3) Populate basic blocks with instructions for the intrinsic. +  instruction_builder.BuildIntrinsic(method); + +  // 4) Type the graph (no dead/redundant phis to eliminate). +  GraphAnalysisResult build_ssa_result = ssa_builder.BuildSsa(); +  DCHECK_EQ(build_ssa_result, kAnalysisSuccess); +} +  }  // namespace art diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 5a860f1e43..0bb3a051f7 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -21,17 +21,19 @@  #include "dex_file-inl.h"  #include "dex_file.h"  #include "driver/compiler_driver.h" -#include "driver/dex_compilation_unit.h"  #include "nodes.h"  namespace art { +class ArtMethod;  class CodeGenerator; +class DexCompilationUnit;  class OptimizingCompilerStats;  class HGraphBuilder : public ValueObject {   public:    HGraphBuilder(HGraph* graph, +                const DexFile::CodeItem* code_item,                  const DexCompilationUnit* dex_compilation_unit,                  const DexCompilationUnit* outer_compilation_unit,                  CompilerDriver* driver, @@ -47,8 +49,8 @@ class HGraphBuilder : public ValueObject {                  VariableSizedHandleScope* handles,                  DataType::Type return_type = DataType::Type::kInt32)        : graph_(graph), -        dex_file_(dex_compilation_unit->GetDexFile()), -        code_item_(code_item), +        dex_file_(&graph->GetDexFile()), +        code_item_(&code_item),          dex_compilation_unit_(dex_compilation_unit),          outer_compilation_unit_(nullptr),          compiler_driver_(nullptr), @@ -59,6 +61,7 @@ class HGraphBuilder : public ValueObject {          return_type_(return_type) {}    GraphAnalysisResult BuildGraph(); +  void BuildIntrinsicGraph(ArtMethod* method);    static constexpr const char* kBuilderPassName = "builder"; @@ -67,7 +70,7 @@ class HGraphBuilder : public ValueObject {    HGraph* const graph_;    const DexFile* const dex_file_; -  const DexFile::CodeItem& code_item_; +  const DexFile::CodeItem* const code_item_;  // null for intrinsic graph.    // The compilation unit of the current method being compiled. Note that    // it can be an inlined method. diff --git a/compiler/optimizing/cha_guard_optimization.h b/compiler/optimizing/cha_guard_optimization.h index ba0cdb81fd..f14e07bd6c 100644 --- a/compiler/optimizing/cha_guard_optimization.h +++ b/compiler/optimizing/cha_guard_optimization.h @@ -26,8 +26,9 @@ namespace art {   */  class CHAGuardOptimization : public HOptimization {   public: -  explicit CHAGuardOptimization(HGraph* graph) -      : HOptimization(graph, kCHAGuardOptimizationPassName) {} +  explicit CHAGuardOptimization(HGraph* graph, +                                const char* name = kCHAGuardOptimizationPassName) +      : HOptimization(graph, name) {}    void Run() OVERRIDE; diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 015a6a04d3..0bd3ce937a 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -946,12 +946,12 @@ static void CheckLoopEntriesCanBeUsedForOsr(const HGraph& graph,  void CodeGenerator::BuildStackMaps(MemoryRegion stack_map_region,                                     MemoryRegion method_info_region, -                                   const DexFile::CodeItem& code_item) { +                                   const DexFile::CodeItem* code_item_for_osr_check) {    StackMapStream* stack_map_stream = GetStackMapStream();    stack_map_stream->FillInCodeInfo(stack_map_region);    stack_map_stream->FillInMethodInfo(method_info_region); -  if (kIsDebugBuild) { -    CheckLoopEntriesCanBeUsedForOsr(*graph_, CodeInfo(stack_map_region), code_item); +  if (kIsDebugBuild && code_item_for_osr_check != nullptr) { +    CheckLoopEntriesCanBeUsedForOsr(*graph_, CodeInfo(stack_map_region), *code_item_for_osr_check);    }  } diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 18ad60db87..08e4462356 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -346,7 +346,7 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> {    void BuildStackMaps(MemoryRegion stack_map_region,                        MemoryRegion method_info_region, -                      const DexFile::CodeItem& code_item); +                      const DexFile::CodeItem* code_item_for_osr_check);    void ComputeStackMapAndMethodInfoSize(size_t* stack_map_size, size_t* method_info_size);    size_t GetNumberOfJitRoots() const; diff --git a/compiler/optimizing/code_sinking.h b/compiler/optimizing/code_sinking.h index 59cda52a8c..836d9d4f67 100644 --- a/compiler/optimizing/code_sinking.h +++ b/compiler/optimizing/code_sinking.h @@ -28,8 +28,10 @@ namespace art {   */  class CodeSinking : public HOptimization {   public: -  CodeSinking(HGraph* graph, OptimizingCompilerStats* stats) -      : HOptimization(graph, kCodeSinkingPassName, stats) {} +  CodeSinking(HGraph* graph, +              OptimizingCompilerStats* stats, +              const char* name = kCodeSinkingPassName) +      : HOptimization(graph, name, stats) {}    void Run() OVERRIDE; diff --git a/compiler/optimizing/constructor_fence_redundancy_elimination.h b/compiler/optimizing/constructor_fence_redundancy_elimination.h index d89210cd1c..f4b06d5544 100644 --- a/compiler/optimizing/constructor_fence_redundancy_elimination.h +++ b/compiler/optimizing/constructor_fence_redundancy_elimination.h @@ -48,12 +48,13 @@ namespace art {  class ConstructorFenceRedundancyElimination : public HOptimization {   public:    ConstructorFenceRedundancyElimination(HGraph* graph, -                                        OptimizingCompilerStats* stats) -      : HOptimization(graph, kPassName, stats) {} +                                        OptimizingCompilerStats* stats, +                                        const char* name = kCFREPassName) +      : HOptimization(graph, name, stats) {}    void Run() OVERRIDE; -  static constexpr const char* kPassName = "constructor_fence_redundancy_elimination"; +  static constexpr const char* kCFREPassName = "constructor_fence_redundancy_elimination";   private:    DISALLOW_COPY_AND_ASSIGN(ConstructorFenceRedundancyElimination); diff --git a/compiler/optimizing/induction_var_analysis.cc b/compiler/optimizing/induction_var_analysis.cc index e2747afd85..ad29ba56ab 100644 --- a/compiler/optimizing/induction_var_analysis.cc +++ b/compiler/optimizing/induction_var_analysis.cc @@ -97,8 +97,8 @@ static DataType::Type ImplicitConversion(DataType::Type type) {  // Class methods.  // -HInductionVarAnalysis::HInductionVarAnalysis(HGraph* graph) -    : HOptimization(graph, kInductionPassName), +HInductionVarAnalysis::HInductionVarAnalysis(HGraph* graph, const char* name) +    : HOptimization(graph, name),        global_depth_(0),        stack_(graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)),        map_(std::less<HInstruction*>(), diff --git a/compiler/optimizing/induction_var_analysis.h b/compiler/optimizing/induction_var_analysis.h index a2d302ae81..8737b890d9 100644 --- a/compiler/optimizing/induction_var_analysis.h +++ b/compiler/optimizing/induction_var_analysis.h @@ -35,7 +35,7 @@ namespace art {   */  class HInductionVarAnalysis : public HOptimization {   public: -  explicit HInductionVarAnalysis(HGraph* graph); +  explicit HInductionVarAnalysis(HGraph* graph, const char* name = kInductionPassName);    void Run() OVERRIDE; diff --git a/compiler/optimizing/induction_var_analysis_test.cc b/compiler/optimizing/induction_var_analysis_test.cc index f87b46d4ee..4c11ad4643 100644 --- a/compiler/optimizing/induction_var_analysis_test.cc +++ b/compiler/optimizing/induction_var_analysis_test.cc @@ -14,7 +14,7 @@   * limitations under the License.   */ -#include <regex>  // NOLINT [build/c++11] [5] +#include <regex>  #include "base/arena_allocator.h"  #include "builder.h" diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 7adb196d14..3f4a3d8b8e 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1667,6 +1667,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction,      }    }    HGraphBuilder builder(callee_graph, +                        code_item,                          &dex_compilation_unit,                          &outer_compilation_unit_,                          compiler_driver_, diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h index c4b3a32d91..042eee3204 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -44,8 +44,9 @@ class HInliner : public HOptimization {             size_t total_number_of_dex_registers,             size_t total_number_of_instructions,             HInliner* parent, -           size_t depth = 0) -      : HOptimization(outer_graph, kInlinerPassName, stats), +           size_t depth = 0, +           const char* name = kInlinerPassName) +      : HOptimization(outer_graph, name, stats),          outermost_graph_(outermost_graph),          outer_compilation_unit_(outer_compilation_unit),          caller_compilation_unit_(caller_compilation_unit), diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 8e9b818722..61840cc20f 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -272,6 +272,7 @@ static bool IsBlockPopulated(HBasicBlock* block) {  }  bool HInstructionBuilder::Build() { +  DCHECK(code_item_ != nullptr);    locals_for_.resize(        graph_->GetBlocks().size(),        ScopedArenaVector<HInstruction*>(local_allocator_->Adapter(kArenaAllocGraphBuilder))); @@ -321,7 +322,7 @@ bool HInstructionBuilder::Build() {        quicken_index = block_builder_->GetQuickenIndex(block_dex_pc);      } -    for (const DexInstructionPcPair& pair : code_item_.Instructions(block_dex_pc)) { +    for (const DexInstructionPcPair& pair : code_item_->Instructions(block_dex_pc)) {        if (current_block_ == nullptr) {          // The previous instruction ended this block.          break; @@ -364,6 +365,73 @@ bool HInstructionBuilder::Build() {    return true;  } +void HInstructionBuilder::BuildIntrinsic(ArtMethod* method) { +  DCHECK(code_item_ == nullptr); +  DCHECK(method->IsIntrinsic()); + +  locals_for_.resize( +      graph_->GetBlocks().size(), +      ScopedArenaVector<HInstruction*>(local_allocator_->Adapter(kArenaAllocGraphBuilder))); + +  // Fill the entry block. Do not add suspend check, we do not want a suspend +  // check in intrinsics; intrinsic methods are supposed to be fast. +  current_block_ = graph_->GetEntryBlock(); +  InitializeBlockLocals(); +  InitializeParameters(); +  AppendInstruction(new (allocator_) HGoto(0u)); + +  // Fill the body. +  current_block_ = current_block_->GetSingleSuccessor(); +  InitializeBlockLocals(); +  DCHECK(!IsBlockPopulated(current_block_)); + +  // Add the invoke and return instruction. Use HInvokeStaticOrDirect even +  // for methods that would normally use an HInvokeVirtual (sharpen the call). +  size_t in_vregs = graph_->GetNumberOfInVRegs(); +  size_t number_of_arguments = +      in_vregs - std::count(current_locals_->end() - in_vregs, current_locals_->end(), nullptr); +  uint32_t method_idx = dex_compilation_unit_->GetDexMethodIndex(); +  MethodReference target_method(dex_file_, method_idx); +  HInvokeStaticOrDirect::DispatchInfo dispatch_info = { +      HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall, +      HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod, +      /* method_load_data */ 0u +  }; +  InvokeType invoke_type = dex_compilation_unit_->IsStatic() ? kStatic : kDirect; +  HInvokeStaticOrDirect* invoke = new (allocator_) HInvokeStaticOrDirect( +      allocator_, +      number_of_arguments, +      return_type_, +      kNoDexPc, +      method_idx, +      method, +      dispatch_info, +      invoke_type, +      target_method, +      HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); +  HandleInvoke(invoke, +               in_vregs, +               /* args */ nullptr, +               graph_->GetNumberOfVRegs() - in_vregs, +               /* is_range */ true, +               dex_file_->GetMethodShorty(method_idx), +               /* clinit_check */ nullptr, +               /* is_unresolved */ false); + +  // Add the return instruction. +  if (return_type_ == DataType::Type::kVoid) { +    AppendInstruction(new (allocator_) HReturnVoid()); +  } else { +    AppendInstruction(new (allocator_) HReturn(invoke)); +  } + +  // Fill the exit block. +  DCHECK_EQ(current_block_->GetSingleSuccessor(), graph_->GetExitBlock()); +  current_block_ = graph_->GetExitBlock(); +  InitializeBlockLocals(); +  AppendInstruction(new (allocator_) HExit()); +} +  ArenaBitVector* HInstructionBuilder::FindNativeDebugInfoLocations() {    // The callback gets called when the line number changes.    // In other words, it marks the start of new java statement. @@ -373,15 +441,15 @@ ArenaBitVector* HInstructionBuilder::FindNativeDebugInfoLocations() {        return false;      }    }; -  const uint32_t num_instructions = code_item_.insns_size_in_code_units_; +  const uint32_t num_instructions = code_item_->insns_size_in_code_units_;    ArenaBitVector* locations = ArenaBitVector::Create(local_allocator_,                                                       num_instructions,                                                       /* expandable */ false,                                                       kArenaAllocGraphBuilder);    locations->ClearAllBits(); -  dex_file_->DecodeDebugPositionInfo(&code_item_, Callback::Position, locations); +  dex_file_->DecodeDebugPositionInfo(code_item_, Callback::Position, locations);    // Instruction-specific tweaks. -  IterationRange<DexInstructionIterator> instructions = code_item_.Instructions(); +  IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();    for (const DexInstructionPcPair& inst : instructions) {      switch (inst->Opcode()) {        case Instruction::MOVE_EXCEPTION: { @@ -1641,7 +1709,7 @@ void HInstructionBuilder::BuildFillArrayData(const Instruction& instruction, uin    int32_t payload_offset = instruction.VRegB_31t() + dex_pc;    const Instruction::ArrayDataPayload* payload = -      reinterpret_cast<const Instruction::ArrayDataPayload*>(code_item_.insns_ + payload_offset); +      reinterpret_cast<const Instruction::ArrayDataPayload*>(code_item_->insns_ + payload_offset);    const uint8_t* data = payload->data;    uint32_t element_count = payload->element_count; diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h index 058b711687..f551ac4280 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -50,7 +50,7 @@ class HInstructionBuilder : public ValueObject {                        HBasicBlockBuilder* block_builder,                        SsaBuilder* ssa_builder,                        const DexFile* dex_file, -                      const DexFile::CodeItem& code_item, +                      const DexFile::CodeItem* code_item,                        DataType::Type return_type,                        const DexCompilationUnit* dex_compilation_unit,                        const DexCompilationUnit* outer_compilation_unit, @@ -85,6 +85,7 @@ class HInstructionBuilder : public ValueObject {    }    bool Build(); +  void BuildIntrinsic(ArtMethod* method);   private:    void InitializeBlockLocals(); @@ -327,7 +328,7 @@ class HInstructionBuilder : public ValueObject {    // The dex file where the method being compiled is, and the bytecode data.    const DexFile* const dex_file_; -  const DexFile::CodeItem& code_item_; +  const DexFile::CodeItem* const code_item_;  // null for intrinsic graph.    // The return type of the method being compiled.    const DataType::Type return_type_; diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h index 707ff3408e..818d7f63a3 100644 --- a/compiler/optimizing/intrinsics.h +++ b/compiler/optimizing/intrinsics.h @@ -37,8 +37,10 @@ static constexpr uint64_t kNanDouble = 0x7ff8000000000000;  // Recognize intrinsics from HInvoke nodes.  class IntrinsicsRecognizer : public HOptimization {   public: -  IntrinsicsRecognizer(HGraph* graph, OptimizingCompilerStats* stats) -      : HOptimization(graph, kIntrinsicsRecognizerPassName, stats) {} +  IntrinsicsRecognizer(HGraph* graph, +                       OptimizingCompilerStats* stats, +                       const char* name = kIntrinsicsRecognizerPassName) +      : HOptimization(graph, name, stats) {}    void Run() OVERRIDE; diff --git a/compiler/optimizing/licm.h b/compiler/optimizing/licm.h index bf56f53d46..ee567aeb20 100644 --- a/compiler/optimizing/licm.h +++ b/compiler/optimizing/licm.h @@ -26,8 +26,11 @@ class SideEffectsAnalysis;  class LICM : public HOptimization {   public: -  LICM(HGraph* graph, const SideEffectsAnalysis& side_effects, OptimizingCompilerStats* stats) -      : HOptimization(graph, kLoopInvariantCodeMotionPassName, stats), +  LICM(HGraph* graph, +       const SideEffectsAnalysis& side_effects, +       OptimizingCompilerStats* stats, +       const char* name = kLoopInvariantCodeMotionPassName) +      : HOptimization(graph, name, stats),          side_effects_(side_effects) {}    void Run() OVERRIDE; diff --git a/compiler/optimizing/load_store_analysis.h b/compiler/optimizing/load_store_analysis.h index aa8b5bbdc9..437e6be418 100644 --- a/compiler/optimizing/load_store_analysis.h +++ b/compiler/optimizing/load_store_analysis.h @@ -564,8 +564,8 @@ class HeapLocationCollector : public HGraphVisitor {  class LoadStoreAnalysis : public HOptimization {   public: -  explicit LoadStoreAnalysis(HGraph* graph) -    : HOptimization(graph, kLoadStoreAnalysisPassName), +  explicit LoadStoreAnalysis(HGraph* graph, const char* name = kLoadStoreAnalysisPassName) +    : HOptimization(graph, name),        heap_location_collector_(graph) {}    const HeapLocationCollector& GetHeapLocationCollector() const { diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 605fdae0f8..89ad85e0b4 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -199,6 +199,12 @@ class LSEVisitor : public HGraphDelegateVisitor {      if (predecessors.size() == 0) {        return;      } +    if (block->IsExitBlock()) { +      // Exit block doesn't really merge values since the control flow ends in +      // its predecessors. Each predecessor needs to make sure stores are kept +      // if necessary. +      return; +    }      ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[block->GetBlockId()];      for (size_t i = 0; i < heap_values.size(); i++) { @@ -233,15 +239,23 @@ class LSEVisitor : public HGraphDelegateVisitor {          }        } -      if (merged_value == kUnknownHeapValue || ref_info->IsSingletonAndNonRemovable()) { -        // There are conflicting heap values from different predecessors, -        // or the heap value may be needed after method return or deoptimization. -        // Keep the last store in each predecessor since future loads cannot be eliminated. -        for (HBasicBlock* predecessor : predecessors) { -          ScopedArenaVector<HInstruction*>& pred_values = -              heap_values_for_[predecessor->GetBlockId()]; -          KeepIfIsStore(pred_values[i]); +      if (ref_info->IsSingleton()) { +        if (ref_info->IsSingletonAndNonRemovable() || +            (merged_value == kUnknownHeapValue && +             !block->IsSingleReturnOrReturnVoidAllowingPhis())) { +          // The heap value may be needed after method return or deoptimization, +          // or there are conflicting heap values from different predecessors and +          // this block is not a single return, +          // keep the last store in each predecessor since future loads may not +          // be eliminated. +          for (HBasicBlock* predecessor : predecessors) { +            ScopedArenaVector<HInstruction*>& pred_values = +                heap_values_for_[predecessor->GetBlockId()]; +            KeepIfIsStore(pred_values[i]); +          }          } +      } else { +        // Currenctly we don't eliminate stores to non-singletons.        }        if ((merged_value == nullptr) || !from_all_predecessors) { @@ -549,6 +563,31 @@ class LSEVisitor : public HGraphDelegateVisitor {      }    } +  // Keep necessary stores before exiting a method via return/throw. +  void HandleExit(HBasicBlock* block) { +    const ScopedArenaVector<HInstruction*>& heap_values = +        heap_values_for_[block->GetBlockId()]; +    for (size_t i = 0; i < heap_values.size(); i++) { +      HInstruction* heap_value = heap_values[i]; +      ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo(); +      if (!ref_info->IsSingletonAndRemovable()) { +        KeepIfIsStore(heap_value); +      } +    } +  } + +  void VisitReturn(HReturn* instruction) OVERRIDE { +    HandleExit(instruction->GetBlock()); +  } + +  void VisitReturnVoid(HReturnVoid* return_void) OVERRIDE { +    HandleExit(return_void->GetBlock()); +  } + +  void VisitThrow(HThrow* throw_instruction) OVERRIDE { +    HandleExit(throw_instruction->GetBlock()); +  } +    void HandleInvoke(HInstruction* instruction) {      SideEffects side_effects = instruction->GetSideEffects();      ScopedArenaVector<HInstruction*>& heap_values = diff --git a/compiler/optimizing/load_store_elimination.h b/compiler/optimizing/load_store_elimination.h index 20a8a769c0..7153541baf 100644 --- a/compiler/optimizing/load_store_elimination.h +++ b/compiler/optimizing/load_store_elimination.h @@ -29,8 +29,9 @@ class LoadStoreElimination : public HOptimization {    LoadStoreElimination(HGraph* graph,                         const SideEffectsAnalysis& side_effects,                         const LoadStoreAnalysis& lsa, -                       OptimizingCompilerStats* stats) -      : HOptimization(graph, kLoadStoreEliminationPassName, stats), +                       OptimizingCompilerStats* stats, +                       const char* name = kLoadStoreEliminationPassName) +      : HOptimization(graph, name, stats),          side_effects_(side_effects),          lsa_(lsa) {} diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc index fcc59ea3f9..1ca096035e 100644 --- a/compiler/optimizing/loop_optimization.cc +++ b/compiler/optimizing/loop_optimization.cc @@ -448,8 +448,9 @@ static bool CheckInductionSetFullyRemoved(ScopedArenaSet<HInstruction*>* iset) {  HLoopOptimization::HLoopOptimization(HGraph* graph,                                       CompilerDriver* compiler_driver,                                       HInductionVarAnalysis* induction_analysis, -                                     OptimizingCompilerStats* stats) -    : HOptimization(graph, kLoopOptimizationPassName, stats), +                                     OptimizingCompilerStats* stats, +                                     const char* name) +    : HOptimization(graph, name, stats),        compiler_driver_(compiler_driver),        induction_range_(induction_analysis),        loop_allocator_(nullptr), diff --git a/compiler/optimizing/loop_optimization.h b/compiler/optimizing/loop_optimization.h index 51e0a986b8..a707ad1358 100644 --- a/compiler/optimizing/loop_optimization.h +++ b/compiler/optimizing/loop_optimization.h @@ -37,7 +37,8 @@ class HLoopOptimization : public HOptimization {    HLoopOptimization(HGraph* graph,                      CompilerDriver* compiler_driver,                      HInductionVarAnalysis* induction_analysis, -                    OptimizingCompilerStats* stats); +                    OptimizingCompilerStats* stats, +                    const char* name = kLoopOptimizationPassName);    void Run() OVERRIDE; diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index f4f6434678..fff61f5727 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -1810,6 +1810,11 @@ bool HBasicBlock::IsSingleReturn() const {    return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsReturn();  } +bool HBasicBlock::IsSingleReturnOrReturnVoidAllowingPhis() const { +  return (GetFirstInstruction() == GetLastInstruction()) && +         (GetLastInstruction()->IsReturn() || GetLastInstruction()->IsReturnVoid()); +} +  bool HBasicBlock::IsSingleTryBoundary() const {    return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsTryBoundary();  } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 29c78a1e34..6672901781 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -968,6 +968,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> {    bool IsSingleGoto() const;    bool IsSingleReturn() const; +  bool IsSingleReturnOrReturnVoidAllowingPhis() const;    bool IsSingleTryBoundary() const;    // Returns true if this block emits nothing but a jump. diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc index 1e68ca2802..7edb642c5b 100644 --- a/compiler/optimizing/optimization.cc +++ b/compiler/optimizing/optimization.cc @@ -16,5 +16,317 @@  #include "optimization.h" +#ifdef ART_ENABLE_CODEGEN_arm +#include "instruction_simplifier_arm.h" +#endif +#ifdef ART_ENABLE_CODEGEN_arm64 +#include "instruction_simplifier_arm64.h" +#endif +#ifdef ART_ENABLE_CODEGEN_mips +#include "instruction_simplifier_mips.h" +#include "pc_relative_fixups_mips.h" +#endif +#ifdef ART_ENABLE_CODEGEN_x86 +#include "pc_relative_fixups_x86.h" +#endif +#if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64) +#include "x86_memory_gen.h" +#endif + +#include "bounds_check_elimination.h" +#include "cha_guard_optimization.h" +#include "code_sinking.h" +#include "constant_folding.h" +#include "constructor_fence_redundancy_elimination.h" +#include "dead_code_elimination.h" +#include "driver/dex_compilation_unit.h" +#include "gvn.h" +#include "induction_var_analysis.h" +#include "inliner.h" +#include "instruction_simplifier.h" +#include "intrinsics.h" +#include "licm.h" +#include "load_store_analysis.h" +#include "load_store_elimination.h" +#include "loop_optimization.h" +#include "scheduler.h" +#include "select_generator.h" +#include "sharpening.h" +#include "side_effects_analysis.h" + +// Decide between default or alternative pass name. +  namespace art { + +const char* OptimizationPassName(OptimizationPass pass) { +  switch (pass) { +    case OptimizationPass::kSideEffectsAnalysis: +      return SideEffectsAnalysis::kSideEffectsAnalysisPassName; +    case OptimizationPass::kInductionVarAnalysis: +      return HInductionVarAnalysis::kInductionPassName; +    case OptimizationPass::kLoadStoreAnalysis: +      return LoadStoreAnalysis::kLoadStoreAnalysisPassName; +    case OptimizationPass::kGlobalValueNumbering: +      return GVNOptimization::kGlobalValueNumberingPassName; +    case OptimizationPass::kInvariantCodeMotion: +      return LICM::kLoopInvariantCodeMotionPassName; +    case OptimizationPass::kLoopOptimization: +      return HLoopOptimization::kLoopOptimizationPassName; +    case OptimizationPass::kBoundsCheckElimination: +      return BoundsCheckElimination::kBoundsCheckEliminationPassName; +    case OptimizationPass::kLoadStoreElimination: +      return LoadStoreElimination::kLoadStoreEliminationPassName; +    case OptimizationPass::kConstantFolding: +      return HConstantFolding::kConstantFoldingPassName; +    case OptimizationPass::kDeadCodeElimination: +      return HDeadCodeElimination::kDeadCodeEliminationPassName; +    case OptimizationPass::kInliner: +      return HInliner::kInlinerPassName; +    case OptimizationPass::kSharpening: +      return HSharpening::kSharpeningPassName; +    case OptimizationPass::kSelectGenerator: +      return HSelectGenerator::kSelectGeneratorPassName; +    case OptimizationPass::kInstructionSimplifier: +      return InstructionSimplifier::kInstructionSimplifierPassName; +    case OptimizationPass::kIntrinsicsRecognizer: +      return IntrinsicsRecognizer::kIntrinsicsRecognizerPassName; +    case OptimizationPass::kCHAGuardOptimization: +      return CHAGuardOptimization::kCHAGuardOptimizationPassName; +    case OptimizationPass::kCodeSinking: +      return CodeSinking::kCodeSinkingPassName; +    case OptimizationPass::kConstructorFenceRedundancyElimination: +      return ConstructorFenceRedundancyElimination::kCFREPassName; +    case OptimizationPass::kScheduling: +      return HInstructionScheduling::kInstructionSchedulingPassName; +#ifdef ART_ENABLE_CODEGEN_arm +    case OptimizationPass::kInstructionSimplifierArm: +      return arm::InstructionSimplifierArm::kInstructionSimplifierArmPassName; +#endif +#ifdef ART_ENABLE_CODEGEN_arm64 +    case OptimizationPass::kInstructionSimplifierArm64: +      return arm64::InstructionSimplifierArm64::kInstructionSimplifierArm64PassName; +#endif +#ifdef ART_ENABLE_CODEGEN_mips +    case OptimizationPass::kPcRelativeFixupsMips: +      return mips::PcRelativeFixups::kPcRelativeFixupsMipsPassName; +    case OptimizationPass::kInstructionSimplifierMips: +      return mips::InstructionSimplifierMips::kInstructionSimplifierMipsPassName; +#endif +#ifdef ART_ENABLE_CODEGEN_x86 +    case OptimizationPass::kPcRelativeFixupsX86: +      return x86::PcRelativeFixups::kPcRelativeFixupsX86PassName; +#endif +#if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64) +    case OptimizationPass::kX86MemoryOperandGeneration: +      return x86::X86MemoryOperandGeneration::kX86MemoryOperandGenerationPassName; +#endif +  } +} + +#define X(x) if (name == OptimizationPassName((x))) return (x) + +OptimizationPass OptimizationPassByName(const std::string& name) { +  X(OptimizationPass::kBoundsCheckElimination); +  X(OptimizationPass::kCHAGuardOptimization); +  X(OptimizationPass::kCodeSinking); +  X(OptimizationPass::kConstantFolding); +  X(OptimizationPass::kConstructorFenceRedundancyElimination); +  X(OptimizationPass::kDeadCodeElimination); +  X(OptimizationPass::kGlobalValueNumbering); +  X(OptimizationPass::kInductionVarAnalysis); +  X(OptimizationPass::kInliner); +  X(OptimizationPass::kInstructionSimplifier); +  X(OptimizationPass::kIntrinsicsRecognizer); +  X(OptimizationPass::kInvariantCodeMotion); +  X(OptimizationPass::kLoadStoreAnalysis); +  X(OptimizationPass::kLoadStoreElimination); +  X(OptimizationPass::kLoopOptimization); +  X(OptimizationPass::kScheduling); +  X(OptimizationPass::kSelectGenerator); +  X(OptimizationPass::kSharpening); +  X(OptimizationPass::kSideEffectsAnalysis); +#ifdef ART_ENABLE_CODEGEN_arm +  X(OptimizationPass::kInstructionSimplifierArm); +#endif +#ifdef ART_ENABLE_CODEGEN_arm64 +  X(OptimizationPass::kInstructionSimplifierArm64); +#endif +#ifdef ART_ENABLE_CODEGEN_mips +  X(OptimizationPass::kPcRelativeFixupsMips); +  X(OptimizationPass::kInstructionSimplifierMips); +#endif +#ifdef ART_ENABLE_CODEGEN_x86 +  X(OptimizationPass::kPcRelativeFixupsX86); +  X(OptimizationPass::kX86MemoryOperandGeneration); +#endif +  LOG(FATAL) << "Cannot find optimization " << name; +  UNREACHABLE(); +} + +#undef X + +ArenaVector<HOptimization*> ConstructOptimizations( +    const OptimizationDef definitions[], +    size_t length, +    ArenaAllocator* allocator, +    HGraph* graph, +    OptimizingCompilerStats* stats, +    CodeGenerator* codegen, +    CompilerDriver* driver, +    const DexCompilationUnit& dex_compilation_unit, +    VariableSizedHandleScope* handles) { +  ArenaVector<HOptimization*> optimizations(allocator->Adapter()); + +  // Some optimizations require SideEffectsAnalysis or HInductionVarAnalysis +  // instances. This method uses the nearest instance preceeding it in the pass +  // name list or fails fatally if no such analysis can be found. +  SideEffectsAnalysis* most_recent_side_effects = nullptr; +  HInductionVarAnalysis* most_recent_induction = nullptr; +  LoadStoreAnalysis* most_recent_lsa = nullptr; + +  // Loop over the requested optimizations. +  for (size_t i = 0; i < length; i++) { +    OptimizationPass pass = definitions[i].first; +    const char* alt_name = definitions[i].second; +    const char* name = alt_name != nullptr +        ? alt_name +        : OptimizationPassName(pass); +    HOptimization* opt = nullptr; + +    switch (pass) { +      // +      // Analysis passes (kept in most recent for subsequent passes). +      // +      case OptimizationPass::kSideEffectsAnalysis: +        opt = most_recent_side_effects = new (allocator) SideEffectsAnalysis(graph, name); +        break; +      case OptimizationPass::kInductionVarAnalysis: +        opt = most_recent_induction = new (allocator) HInductionVarAnalysis(graph, name); +        break; +      case OptimizationPass::kLoadStoreAnalysis: +        opt = most_recent_lsa = new (allocator) LoadStoreAnalysis(graph, name); +        break; +      // +      // Passes that need prior analysis. +      // +      case OptimizationPass::kGlobalValueNumbering: +        CHECK(most_recent_side_effects != nullptr); +        opt = new (allocator) GVNOptimization(graph, *most_recent_side_effects, name); +        break; +      case OptimizationPass::kInvariantCodeMotion: +        CHECK(most_recent_side_effects != nullptr); +        opt = new (allocator) LICM(graph, *most_recent_side_effects, stats, name); +        break; +      case OptimizationPass::kLoopOptimization: +        CHECK(most_recent_induction != nullptr); +        opt = new (allocator) HLoopOptimization(graph, driver, most_recent_induction, stats, name); +        break; +      case OptimizationPass::kBoundsCheckElimination: +        CHECK(most_recent_side_effects != nullptr && most_recent_induction != nullptr); +        opt = new (allocator) BoundsCheckElimination( +            graph, *most_recent_side_effects, most_recent_induction, name); +        break; +      case OptimizationPass::kLoadStoreElimination: +        CHECK(most_recent_side_effects != nullptr && most_recent_induction != nullptr); +        opt = new (allocator) LoadStoreElimination( +            graph, *most_recent_side_effects, *most_recent_lsa, stats, name); +        break; +      // +      // Regular passes. +      // +      case OptimizationPass::kConstantFolding: +        opt = new (allocator) HConstantFolding(graph, name); +        break; +      case OptimizationPass::kDeadCodeElimination: +        opt = new (allocator) HDeadCodeElimination(graph, stats, name); +        break; +      case OptimizationPass::kInliner: { +        size_t number_of_dex_registers = dex_compilation_unit.GetCodeItem()->registers_size_; +        opt = new (allocator) HInliner(graph,                   // outer_graph +                                       graph,                   // outermost_graph +                                       codegen, +                                       dex_compilation_unit,    // outer_compilation_unit +                                       dex_compilation_unit,    // outermost_compilation_unit +                                       driver, +                                       handles, +                                       stats, +                                       number_of_dex_registers, +                                       /* total_number_of_instructions */ 0, +                                       /* parent */ nullptr, +                                       /* depth */ 0, +                                       name); +        break; +      } +      case OptimizationPass::kSharpening: +        opt = new (allocator) HSharpening( +            graph, codegen, dex_compilation_unit, driver, handles, name); +        break; +      case OptimizationPass::kSelectGenerator: +        opt = new (allocator) HSelectGenerator(graph, handles, stats, name); +        break; +      case OptimizationPass::kInstructionSimplifier: +        opt = new (allocator) InstructionSimplifier(graph, codegen, driver, stats, name); +        break; +      case OptimizationPass::kIntrinsicsRecognizer: +        opt = new (allocator) IntrinsicsRecognizer(graph, stats, name); +        break; +      case OptimizationPass::kCHAGuardOptimization: +        opt = new (allocator) CHAGuardOptimization(graph, name); +        break; +      case OptimizationPass::kCodeSinking: +        opt = new (allocator) CodeSinking(graph, stats, name); +        break; +      case OptimizationPass::kConstructorFenceRedundancyElimination: +        opt = new (allocator) ConstructorFenceRedundancyElimination(graph, stats, name); +        break; +      case OptimizationPass::kScheduling: +        opt = new (allocator) HInstructionScheduling( +            graph, driver->GetInstructionSet(), codegen, name); +        break; +      // +      // Arch-specific passes. +      // +#ifdef ART_ENABLE_CODEGEN_arm +      case OptimizationPass::kInstructionSimplifierArm: +        DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; +        opt = new (allocator) arm::InstructionSimplifierArm(graph, stats); +        break; +#endif +#ifdef ART_ENABLE_CODEGEN_arm64 +      case OptimizationPass::kInstructionSimplifierArm64: +        DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; +        opt = new (allocator) arm64::InstructionSimplifierArm64(graph, stats); +        break; +#endif +#ifdef ART_ENABLE_CODEGEN_mips +      case OptimizationPass::kPcRelativeFixupsMips: +        DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; +        opt = new (allocator) mips::PcRelativeFixups(graph, codegen, stats); +        break; +      case OptimizationPass::kInstructionSimplifierMips: +        DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; +        opt = new (allocator) mips::InstructionSimplifierMips(graph, codegen, stats); +        break; +#endif +#ifdef ART_ENABLE_CODEGEN_x86 +      case OptimizationPass::kPcRelativeFixupsX86: +        DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; +        opt = new (allocator) x86::PcRelativeFixups(graph, codegen, stats); +        break; +      case OptimizationPass::kX86MemoryOperandGeneration: +        DCHECK(alt_name == nullptr) << "arch-specific pass does not support alternative name"; +        opt = new (allocator) x86::X86MemoryOperandGeneration(graph, codegen, stats); +        break; +#endif +    }  // switch + +    // Add each next optimization to result vector. +    CHECK(opt != nullptr); +    DCHECK_STREQ(name, opt->GetPassName());  // sanity +    optimizations.push_back(opt); +  } + +  return optimizations; +} +  }  // namespace art diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h index ce41a2e512..c170f155fa 100644 --- a/compiler/optimizing/optimization.h +++ b/compiler/optimizing/optimization.h @@ -23,6 +23,10 @@  namespace art { +class CodeGenerator; +class CompilerDriver; +class DexCompilationUnit; +  /**   * Abstraction to implement an optimization pass.   */ @@ -58,6 +62,81 @@ class HOptimization : public ArenaObject<kArenaAllocOptimization> {    DISALLOW_COPY_AND_ASSIGN(HOptimization);  }; +// Optimization passes that can be constructed by the helper method below. An enum +// field is preferred over a string lookup at places where performance matters. +// TODO: generate this table and lookup methods below automatically? +enum class OptimizationPass { +  kBoundsCheckElimination, +  kCHAGuardOptimization, +  kCodeSinking, +  kConstantFolding, +  kConstructorFenceRedundancyElimination, +  kDeadCodeElimination, +  kGlobalValueNumbering, +  kInductionVarAnalysis, +  kInliner, +  kInstructionSimplifier, +  kIntrinsicsRecognizer, +  kInvariantCodeMotion, +  kLoadStoreAnalysis, +  kLoadStoreElimination, +  kLoopOptimization, +  kScheduling, +  kSelectGenerator, +  kSharpening, +  kSideEffectsAnalysis, +#ifdef ART_ENABLE_CODEGEN_arm +  kInstructionSimplifierArm, +#endif +#ifdef ART_ENABLE_CODEGEN_arm64 +  kInstructionSimplifierArm64, +#endif +#ifdef ART_ENABLE_CODEGEN_mips +  kPcRelativeFixupsMips, +  kInstructionSimplifierMips, +#endif +#ifdef ART_ENABLE_CODEGEN_x86 +  kPcRelativeFixupsX86, +#endif +#if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64) +  kX86MemoryOperandGeneration, +#endif +}; + +// Lookup name of optimization pass. +const char* OptimizationPassName(OptimizationPass pass); + +// Lookup optimization pass by name. +OptimizationPass OptimizationPassByName(const std::string& name); + +// Optimization definition consisting of an optimization pass +// and an optional alternative name (nullptr denotes default). +typedef std::pair<OptimizationPass, const char*> OptimizationDef; + +// Helper method for optimization definition array entries. +inline OptimizationDef OptDef(OptimizationPass pass, const char* name = nullptr) { +  return std::make_pair(pass, name); +} + +// Helper method to construct series of optimization passes. +// The array should consist of the requested optimizations +// and optional alternative names for repeated passes. +// Example: +//    { OptPass(kConstantFolding), +//      OptPass(Inliner), +//      OptPass(kConstantFolding, "constant_folding$after_inlining") +//    } +ArenaVector<HOptimization*> ConstructOptimizations( +    const OptimizationDef definitions[], +    size_t length, +    ArenaAllocator* allocator, +    HGraph* graph, +    OptimizingCompilerStats* stats, +    CodeGenerator* codegen, +    CompilerDriver* driver, +    const DexCompilationUnit& dex_compilation_unit, +    VariableSizedHandleScope* handles); +  }  // namespace art  #endif  // ART_COMPILER_OPTIMIZING_OPTIMIZATION_H_ diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 2bba985c34..53f9ec413b 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -22,23 +22,6 @@  #include <stdint.h> -#ifdef ART_ENABLE_CODEGEN_arm64 -#include "instruction_simplifier_arm64.h" -#endif - -#ifdef ART_ENABLE_CODEGEN_mips -#include "instruction_simplifier_mips.h" -#include "pc_relative_fixups_mips.h" -#endif - -#ifdef ART_ENABLE_CODEGEN_x86 -#include "pc_relative_fixups_x86.h" -#endif - -#if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64) -#include "x86_memory_gen.h" -#endif -  #include "art_method-inl.h"  #include "base/arena_allocator.h"  #include "base/arena_containers.h" @@ -47,16 +30,10 @@  #include "base/mutex.h"  #include "base/scoped_arena_allocator.h"  #include "base/timing_logger.h" -#include "bounds_check_elimination.h"  #include "builder.h" -#include "cha_guard_optimization.h"  #include "code_generator.h" -#include "code_sinking.h"  #include "compiled_method.h"  #include "compiler.h" -#include "constant_folding.h" -#include "constructor_fence_redundancy_elimination.h" -#include "dead_code_elimination.h"  #include "debug/elf_debug_writer.h"  #include "debug/method_debug_info.h"  #include "dex/verification_results.h" @@ -67,31 +44,19 @@  #include "driver/dex_compilation_unit.h"  #include "graph_checker.h"  #include "graph_visualizer.h" -#include "gvn.h" -#include "induction_var_analysis.h"  #include "inliner.h" -#include "instruction_simplifier.h" -#include "instruction_simplifier_arm.h" -#include "intrinsics.h"  #include "jit/debugger_interface.h"  #include "jit/jit.h"  #include "jit/jit_code_cache.h"  #include "jit/jit_logger.h"  #include "jni/quick/jni_compiler.h" -#include "licm.h"  #include "linker/linker_patch.h" -#include "load_store_analysis.h" -#include "load_store_elimination.h" -#include "loop_optimization.h"  #include "nodes.h"  #include "oat_quick_method_header.h"  #include "prepare_for_register_allocation.h"  #include "reference_type_propagation.h"  #include "register_allocator_linear_scan.h" -#include "scheduler.h"  #include "select_generator.h" -#include "sharpening.h" -#include "side_effects_analysis.h"  #include "ssa_builder.h"  #include "ssa_liveness_analysis.h"  #include "ssa_phi_elimination.h" @@ -311,12 +276,8 @@ class OptimizingCompiler FINAL : public Compiler {    CompiledMethod* JniCompile(uint32_t access_flags,                               uint32_t method_idx, -                             const DexFile& dex_file) const OVERRIDE { -    return ArtQuickJniCompileMethod(GetCompilerDriver(), -                                    access_flags, -                                    method_idx, -                                    dex_file); -  } +                             const DexFile& dex_file, +                             Handle<mirror::DexCache> dex_cache) const OVERRIDE;    uintptr_t GetEntryPointOf(ArtMethod* method) const OVERRIDE        REQUIRES_SHARED(Locks::mutator_lock_) { @@ -339,21 +300,52 @@ class OptimizingCompiler FINAL : public Compiler {   private:    void RunOptimizations(HGraph* graph,                          CodeGenerator* codegen, -                        CompilerDriver* driver,                          const DexCompilationUnit& dex_compilation_unit,                          PassObserver* pass_observer, -                        VariableSizedHandleScope* handles) const; +                        VariableSizedHandleScope* handles, +                        const OptimizationDef definitions[], +                        size_t length) const { +    // Convert definitions to optimization passes. +    ArenaVector<HOptimization*> optimizations = ConstructOptimizations( +        definitions, +        length, +        graph->GetAllocator(), +        graph, +        compilation_stats_.get(), +        codegen, +        GetCompilerDriver(), +        dex_compilation_unit, +        handles); +    DCHECK_EQ(length, optimizations.size()); +    // Run the optimization passes one by one. +    for (size_t i = 0; i < length; ++i) { +      PassScope scope(optimizations[i]->GetPassName(), pass_observer); +      optimizations[i]->Run(); +    } +  } + +  template <size_t length> void RunOptimizations( +      HGraph* graph, +      CodeGenerator* codegen, +      const DexCompilationUnit& dex_compilation_unit, +      PassObserver* pass_observer, +      VariableSizedHandleScope* handles, +      const OptimizationDef (&definitions)[length]) const { +    RunOptimizations( +        graph, codegen, dex_compilation_unit, pass_observer, handles, definitions, length); +  } -  void RunOptimizations(HOptimization* optimizations[], -                        size_t length, -                        PassObserver* pass_observer) const; +  void RunOptimizations(HGraph* graph, +                        CodeGenerator* codegen, +                        const DexCompilationUnit& dex_compilation_unit, +                        PassObserver* pass_observer, +                        VariableSizedHandleScope* handles) const;   private:    // Create a 'CompiledMethod' for an optimized graph.    CompiledMethod* Emit(ArenaAllocator* allocator,                         CodeVectorAllocator* code_allocator,                         CodeGenerator* codegen, -                       CompilerDriver* driver,                         const DexFile::CodeItem* item) const;    // Try compiling a method and return the code generator used for @@ -366,29 +358,29 @@ class OptimizingCompiler FINAL : public Compiler {    CodeGenerator* TryCompile(ArenaAllocator* allocator,                              ArenaStack* arena_stack,                              CodeVectorAllocator* code_allocator, -                            const DexFile::CodeItem* code_item, -                            uint32_t access_flags, -                            InvokeType invoke_type, -                            uint16_t class_def_idx, -                            uint32_t method_idx, -                            Handle<mirror::ClassLoader> class_loader, -                            const DexFile& dex_file, -                            Handle<mirror::DexCache> dex_cache, +                            const DexCompilationUnit& dex_compilation_unit,                              ArtMethod* method,                              bool osr,                              VariableSizedHandleScope* handles) const; +  CodeGenerator* TryCompileIntrinsic(ArenaAllocator* allocator, +                                     ArenaStack* arena_stack, +                                     CodeVectorAllocator* code_allocator, +                                     const DexCompilationUnit& dex_compilation_unit, +                                     ArtMethod* method, +                                     VariableSizedHandleScope* handles) const; +    void MaybeRunInliner(HGraph* graph,                         CodeGenerator* codegen, -                       CompilerDriver* driver,                         const DexCompilationUnit& dex_compilation_unit,                         PassObserver* pass_observer,                         VariableSizedHandleScope* handles) const; -  void RunArchOptimizations(InstructionSet instruction_set, -                            HGraph* graph, +  void RunArchOptimizations(HGraph* graph,                              CodeGenerator* codegen, -                            PassObserver* pass_observer) const; +                            const DexCompilationUnit& dex_compilation_unit, +                            PassObserver* pass_observer, +                            VariableSizedHandleScope* handles) const;    std::unique_ptr<OptimizingCompilerStats> compilation_stats_; @@ -444,299 +436,130 @@ static bool IsInstructionSetSupported(InstructionSet instruction_set) {        || instruction_set == InstructionSet::kX86_64;  } -// Strip pass name suffix to get optimization name. -static std::string ConvertPassNameToOptimizationName(const std::string& pass_name) { -  size_t pos = pass_name.find(kPassNameSeparator); -  return pos == std::string::npos ? pass_name : pass_name.substr(0, pos); -} - -static HOptimization* BuildOptimization( -    const std::string& pass_name, -    ArenaAllocator* allocator, -    HGraph* graph, -    OptimizingCompilerStats* stats, -    CodeGenerator* codegen, -    CompilerDriver* driver, -    const DexCompilationUnit& dex_compilation_unit, -    VariableSizedHandleScope* handles, -    SideEffectsAnalysis* most_recent_side_effects, -    HInductionVarAnalysis* most_recent_induction, -    LoadStoreAnalysis* most_recent_lsa) { -  std::string opt_name = ConvertPassNameToOptimizationName(pass_name); -  if (opt_name == BoundsCheckElimination::kBoundsCheckEliminationPassName) { -    CHECK(most_recent_side_effects != nullptr && most_recent_induction != nullptr); -    return new (allocator) BoundsCheckElimination(graph, -                                                  *most_recent_side_effects, -                                                  most_recent_induction); -  } else if (opt_name == GVNOptimization::kGlobalValueNumberingPassName) { -    CHECK(most_recent_side_effects != nullptr); -    return new (allocator) GVNOptimization(graph, *most_recent_side_effects, pass_name.c_str()); -  } else if (opt_name == HConstantFolding::kConstantFoldingPassName) { -    return new (allocator) HConstantFolding(graph, pass_name.c_str()); -  } else if (opt_name == HDeadCodeElimination::kDeadCodeEliminationPassName) { -    return new (allocator) HDeadCodeElimination(graph, stats, pass_name.c_str()); -  } else if (opt_name == HInliner::kInlinerPassName) { -    size_t number_of_dex_registers = dex_compilation_unit.GetCodeItem()->registers_size_; -    return new (allocator) HInliner(graph,                   // outer_graph -                                    graph,                   // outermost_graph -                                    codegen, -                                    dex_compilation_unit,    // outer_compilation_unit -                                    dex_compilation_unit,    // outermost_compilation_unit -                                    driver, -                                    handles, -                                    stats, -                                    number_of_dex_registers, -                                    /* total_number_of_instructions */ 0, -                                    /* parent */ nullptr); -  } else if (opt_name == HSharpening::kSharpeningPassName) { -    return new (allocator) HSharpening(graph, codegen, dex_compilation_unit, driver, handles); -  } else if (opt_name == HSelectGenerator::kSelectGeneratorPassName) { -    return new (allocator) HSelectGenerator(graph, handles, stats); -  } else if (opt_name == HInductionVarAnalysis::kInductionPassName) { -    return new (allocator) HInductionVarAnalysis(graph); -  } else if (opt_name == InstructionSimplifier::kInstructionSimplifierPassName) { -    return new (allocator) InstructionSimplifier(graph, codegen, driver, stats, pass_name.c_str()); -  } else if (opt_name == IntrinsicsRecognizer::kIntrinsicsRecognizerPassName) { -    return new (allocator) IntrinsicsRecognizer(graph, stats); -  } else if (opt_name == LICM::kLoopInvariantCodeMotionPassName) { -    CHECK(most_recent_side_effects != nullptr); -    return new (allocator) LICM(graph, *most_recent_side_effects, stats); -  } else if (opt_name == LoadStoreAnalysis::kLoadStoreAnalysisPassName) { -    return new (allocator) LoadStoreAnalysis(graph); -  } else if (opt_name == LoadStoreElimination::kLoadStoreEliminationPassName) { -    CHECK(most_recent_side_effects != nullptr); -    CHECK(most_recent_lsa != nullptr); -    return new (allocator) LoadStoreElimination(graph, -                                                *most_recent_side_effects, -                                                *most_recent_lsa, stats); -  } else if (opt_name == SideEffectsAnalysis::kSideEffectsAnalysisPassName) { -    return new (allocator) SideEffectsAnalysis(graph); -  } else if (opt_name == HLoopOptimization::kLoopOptimizationPassName) { -    return new (allocator) HLoopOptimization(graph, driver, most_recent_induction, stats); -  } else if (opt_name == CHAGuardOptimization::kCHAGuardOptimizationPassName) { -    return new (allocator) CHAGuardOptimization(graph); -  } else if (opt_name == CodeSinking::kCodeSinkingPassName) { -    return new (allocator) CodeSinking(graph, stats); -  } else if (opt_name == ConstructorFenceRedundancyElimination::kPassName) { -    return new (allocator) ConstructorFenceRedundancyElimination(graph, stats); -#ifdef ART_ENABLE_CODEGEN_arm -  } else if (opt_name == arm::InstructionSimplifierArm::kInstructionSimplifierArmPassName) { -    return new (allocator) arm::InstructionSimplifierArm(graph, stats); -#endif -#ifdef ART_ENABLE_CODEGEN_arm64 -  } else if (opt_name == arm64::InstructionSimplifierArm64::kInstructionSimplifierArm64PassName) { -    return new (allocator) arm64::InstructionSimplifierArm64(graph, stats); -#endif -#ifdef ART_ENABLE_CODEGEN_mips -  } else if (opt_name == mips::PcRelativeFixups::kPcRelativeFixupsMipsPassName) { -    return new (allocator) mips::PcRelativeFixups(graph, codegen, stats); -  } else if (opt_name == mips::InstructionSimplifierMips::kInstructionSimplifierMipsPassName) { -    return new (allocator) mips::InstructionSimplifierMips(graph, codegen, stats); -#endif -#ifdef ART_ENABLE_CODEGEN_x86 -  } else if (opt_name == x86::PcRelativeFixups::kPcRelativeFixupsX86PassName) { -    return new (allocator) x86::PcRelativeFixups(graph, codegen, stats); -  } else if (opt_name == x86::X86MemoryOperandGeneration::kX86MemoryOperandGenerationPassName) { -    return new (allocator) x86::X86MemoryOperandGeneration(graph, codegen, stats); -#endif -  } -  return nullptr; -} - -static ArenaVector<HOptimization*> BuildOptimizations( -    const std::vector<std::string>& pass_names, -    ArenaAllocator* allocator, -    HGraph* graph, -    OptimizingCompilerStats* stats, -    CodeGenerator* codegen, -    CompilerDriver* driver, -    const DexCompilationUnit& dex_compilation_unit, -    VariableSizedHandleScope* handles) { -  // Few HOptimizations constructors require SideEffectsAnalysis or HInductionVarAnalysis -  // instances. This method assumes that each of them expects the nearest instance preceeding it -  // in the pass name list. -  SideEffectsAnalysis* most_recent_side_effects = nullptr; -  HInductionVarAnalysis* most_recent_induction = nullptr; -  LoadStoreAnalysis* most_recent_lsa = nullptr; -  ArenaVector<HOptimization*> ret(allocator->Adapter()); -  for (const std::string& pass_name : pass_names) { -    HOptimization* opt = BuildOptimization( -        pass_name, -        allocator, -        graph, -        stats, -        codegen, -        driver, -        dex_compilation_unit, -        handles, -        most_recent_side_effects, -        most_recent_induction, -        most_recent_lsa); -    CHECK(opt != nullptr) << "Couldn't build optimization: \"" << pass_name << "\""; -    ret.push_back(opt); - -    std::string opt_name = ConvertPassNameToOptimizationName(pass_name); -    if (opt_name == SideEffectsAnalysis::kSideEffectsAnalysisPassName) { -      most_recent_side_effects = down_cast<SideEffectsAnalysis*>(opt); -    } else if (opt_name == HInductionVarAnalysis::kInductionPassName) { -      most_recent_induction = down_cast<HInductionVarAnalysis*>(opt); -    } else if (opt_name == LoadStoreAnalysis::kLoadStoreAnalysisPassName) { -      most_recent_lsa = down_cast<LoadStoreAnalysis*>(opt); -    } -  } -  return ret; -} - -void OptimizingCompiler::RunOptimizations(HOptimization* optimizations[], -                                          size_t length, -                                          PassObserver* pass_observer) const { -  for (size_t i = 0; i < length; ++i) { -    PassScope scope(optimizations[i]->GetPassName(), pass_observer); -    optimizations[i]->Run(); -  } -} -  void OptimizingCompiler::MaybeRunInliner(HGraph* graph,                                           CodeGenerator* codegen, -                                         CompilerDriver* driver,                                           const DexCompilationUnit& dex_compilation_unit,                                           PassObserver* pass_observer,                                           VariableSizedHandleScope* handles) const { -  OptimizingCompilerStats* stats = compilation_stats_.get(); -  const CompilerOptions& compiler_options = driver->GetCompilerOptions(); +  const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions();    bool should_inline = (compiler_options.GetInlineMaxCodeUnits() > 0);    if (!should_inline) {      return;    } -  size_t number_of_dex_registers = dex_compilation_unit.GetCodeItem()->registers_size_; -  HInliner* inliner = new (graph->GetAllocator()) HInliner( -      graph,                   // outer_graph -      graph,                   // outermost_graph -      codegen, -      dex_compilation_unit,    // outer_compilation_unit -      dex_compilation_unit,    // outermost_compilation_unit -      driver, -      handles, -      stats, -      number_of_dex_registers, -      /* total_number_of_instructions */ 0, -      /* parent */ nullptr); -  HOptimization* optimizations[] = { inliner }; - -  RunOptimizations(optimizations, arraysize(optimizations), pass_observer); +  OptimizationDef optimizations[] = { +    OptDef(OptimizationPass::kInliner) +  }; +  RunOptimizations(graph, +                   codegen, +                   dex_compilation_unit, +                   pass_observer, +                   handles, +                   optimizations);  } -void OptimizingCompiler::RunArchOptimizations(InstructionSet instruction_set, -                                              HGraph* graph, +void OptimizingCompiler::RunArchOptimizations(HGraph* graph,                                                CodeGenerator* codegen, -                                              PassObserver* pass_observer) const { -  UNUSED(codegen);  // To avoid compilation error when compiling for svelte -  OptimizingCompilerStats* stats = compilation_stats_.get(); -  ArenaAllocator* allocator = graph->GetAllocator(); -  switch (instruction_set) { +                                              const DexCompilationUnit& dex_compilation_unit, +                                              PassObserver* pass_observer, +                                              VariableSizedHandleScope* handles) const { +  switch (GetCompilerDriver()->GetInstructionSet()) {  #if defined(ART_ENABLE_CODEGEN_arm)      case InstructionSet::kThumb2:      case InstructionSet::kArm: { -      arm::InstructionSimplifierArm* simplifier = -          new (allocator) arm::InstructionSimplifierArm(graph, stats); -      SideEffectsAnalysis* side_effects = new (allocator) SideEffectsAnalysis(graph); -      GVNOptimization* gvn = -          new (allocator) GVNOptimization(graph, *side_effects, "GVN$after_arch"); -      HInstructionScheduling* scheduling = -          new (allocator) HInstructionScheduling(graph, instruction_set, codegen); -      HOptimization* arm_optimizations[] = { -        simplifier, -        side_effects, -        gvn, -        scheduling, +      OptimizationDef arm_optimizations[] = { +        OptDef(OptimizationPass::kInstructionSimplifierArm), +        OptDef(OptimizationPass::kSideEffectsAnalysis), +        OptDef(OptimizationPass::kGlobalValueNumbering, "GVN$after_arch"), +        OptDef(OptimizationPass::kScheduling)        }; -      RunOptimizations(arm_optimizations, arraysize(arm_optimizations), pass_observer); +      RunOptimizations(graph, +                       codegen, +                       dex_compilation_unit, +                       pass_observer, +                       handles, +                       arm_optimizations);        break;      }  #endif  #ifdef ART_ENABLE_CODEGEN_arm64      case InstructionSet::kArm64: { -      arm64::InstructionSimplifierArm64* simplifier = -          new (allocator) arm64::InstructionSimplifierArm64(graph, stats); -      SideEffectsAnalysis* side_effects = new (allocator) SideEffectsAnalysis(graph); -      GVNOptimization* gvn = -          new (allocator) GVNOptimization(graph, *side_effects, "GVN$after_arch"); -      HInstructionScheduling* scheduling = -          new (allocator) HInstructionScheduling(graph, instruction_set); -      HOptimization* arm64_optimizations[] = { -        simplifier, -        side_effects, -        gvn, -        scheduling, +      OptimizationDef arm64_optimizations[] = { +        OptDef(OptimizationPass::kInstructionSimplifierArm64), +        OptDef(OptimizationPass::kSideEffectsAnalysis), +        OptDef(OptimizationPass::kGlobalValueNumbering, "GVN$after_arch"), +        OptDef(OptimizationPass::kScheduling)        }; -      RunOptimizations(arm64_optimizations, arraysize(arm64_optimizations), pass_observer); +      RunOptimizations(graph, +                       codegen, +                       dex_compilation_unit, +                       pass_observer, +                       handles, +                       arm64_optimizations);        break;      }  #endif  #ifdef ART_ENABLE_CODEGEN_mips      case InstructionSet::kMips: { -      mips::InstructionSimplifierMips* simplifier = -          new (allocator) mips::InstructionSimplifierMips(graph, codegen, stats); -      SideEffectsAnalysis* side_effects = new (allocator) SideEffectsAnalysis(graph); -      GVNOptimization* gvn = -          new (allocator) GVNOptimization(graph, *side_effects, "GVN$after_arch"); -      mips::PcRelativeFixups* pc_relative_fixups = -          new (allocator) mips::PcRelativeFixups(graph, codegen, stats); -      HOptimization* mips_optimizations[] = { -          simplifier, -          side_effects, -          gvn, -          pc_relative_fixups, +      OptimizationDef mips_optimizations[] = { +        OptDef(OptimizationPass::kInstructionSimplifierMips), +        OptDef(OptimizationPass::kSideEffectsAnalysis), +        OptDef(OptimizationPass::kGlobalValueNumbering, "GVN$after_arch"), +        OptDef(OptimizationPass::kPcRelativeFixupsMips)        }; -      RunOptimizations(mips_optimizations, arraysize(mips_optimizations), pass_observer); +      RunOptimizations(graph, +                       codegen, +                       dex_compilation_unit, +                       pass_observer, +                       handles, +                       mips_optimizations);        break;      }  #endif  #ifdef ART_ENABLE_CODEGEN_mips64      case InstructionSet::kMips64: { -      SideEffectsAnalysis* side_effects = new (allocator) SideEffectsAnalysis(graph); -      GVNOptimization* gvn = -          new (allocator) GVNOptimization(graph, *side_effects, "GVN$after_arch"); -      HOptimization* mips64_optimizations[] = { -          side_effects, -          gvn, +      OptimizationDef mips64_optimizations[] = { +        OptDef(OptimizationPass::kSideEffectsAnalysis), +        OptDef(OptimizationPass::kGlobalValueNumbering, "GVN$after_arch")        }; -      RunOptimizations(mips64_optimizations, arraysize(mips64_optimizations), pass_observer); +      RunOptimizations(graph, +                       codegen, +                       dex_compilation_unit, +                       pass_observer, +                       handles, +                       mips64_optimizations);        break;      }  #endif  #ifdef ART_ENABLE_CODEGEN_x86      case InstructionSet::kX86: { -      SideEffectsAnalysis* side_effects = new (allocator) SideEffectsAnalysis(graph); -      GVNOptimization* gvn = -          new (allocator) GVNOptimization(graph, *side_effects, "GVN$after_arch"); -      x86::PcRelativeFixups* pc_relative_fixups = -          new (allocator) x86::PcRelativeFixups(graph, codegen, stats); -      x86::X86MemoryOperandGeneration* memory_gen = -          new (allocator) x86::X86MemoryOperandGeneration(graph, codegen, stats); -      HOptimization* x86_optimizations[] = { -          side_effects, -          gvn, -          pc_relative_fixups, -          memory_gen +      OptimizationDef x86_optimizations[] = { +        OptDef(OptimizationPass::kSideEffectsAnalysis), +        OptDef(OptimizationPass::kGlobalValueNumbering, "GVN$after_arch"), +        OptDef(OptimizationPass::kPcRelativeFixupsX86), +        OptDef(OptimizationPass::kX86MemoryOperandGeneration)        }; -      RunOptimizations(x86_optimizations, arraysize(x86_optimizations), pass_observer); +      RunOptimizations(graph, +                       codegen, +                       dex_compilation_unit, +                       pass_observer, +                       handles, +                       x86_optimizations);        break;      }  #endif  #ifdef ART_ENABLE_CODEGEN_x86_64      case InstructionSet::kX86_64: { -      SideEffectsAnalysis* side_effects = new (allocator) SideEffectsAnalysis(graph); -      GVNOptimization* gvn = -          new (allocator) GVNOptimization(graph, *side_effects, "GVN$after_arch"); -      x86::X86MemoryOperandGeneration* memory_gen = -          new (allocator) x86::X86MemoryOperandGeneration(graph, codegen, stats); -      HOptimization* x86_64_optimizations[] = { -          side_effects, -          gvn, -          memory_gen +      OptimizationDef x86_64_optimizations[] = { +        OptDef(OptimizationPass::kSideEffectsAnalysis), +        OptDef(OptimizationPass::kGlobalValueNumbering, "GVN$after_arch"), +        OptDef(OptimizationPass::kX86MemoryOperandGeneration)        }; -      RunOptimizations(x86_64_optimizations, arraysize(x86_64_optimizations), pass_observer); +      RunOptimizations(graph, +                       codegen, +                       dex_compilation_unit, +                       pass_observer, +                       handles, +                       x86_64_optimizations);        break;      }  #endif @@ -772,110 +595,93 @@ static void AllocateRegisters(HGraph* graph,    }  } +// Strip pass name suffix to get optimization name. +static std::string ConvertPassNameToOptimizationName(const std::string& pass_name) { +  size_t pos = pass_name.find(kPassNameSeparator); +  return pos == std::string::npos ? pass_name : pass_name.substr(0, pos); +} +  void OptimizingCompiler::RunOptimizations(HGraph* graph,                                            CodeGenerator* codegen, -                                          CompilerDriver* driver,                                            const DexCompilationUnit& dex_compilation_unit,                                            PassObserver* pass_observer,                                            VariableSizedHandleScope* handles) const { -  OptimizingCompilerStats* stats = compilation_stats_.get(); -  ArenaAllocator* allocator = graph->GetAllocator(); -  if (driver->GetCompilerOptions().GetPassesToRun() != nullptr) { -    ArenaVector<HOptimization*> optimizations = BuildOptimizations( -        *driver->GetCompilerOptions().GetPassesToRun(), -        allocator, -        graph, -        stats, -        codegen, -        driver, -        dex_compilation_unit, -        handles); -    RunOptimizations(&optimizations[0], optimizations.size(), pass_observer); +  const std::vector<std::string>* pass_names = +      GetCompilerDriver()->GetCompilerOptions().GetPassesToRun(); +  if (pass_names != nullptr) { +    // If passes were defined on command-line, build the optimization +    // passes and run these instead of the built-in optimizations. +    const size_t length = pass_names->size(); +    std::vector<OptimizationDef> optimizations; +    for (const std::string& pass_name : *pass_names) { +      std::string opt_name = ConvertPassNameToOptimizationName(pass_name); +      optimizations.push_back(OptDef(OptimizationPassByName(opt_name.c_str()), pass_name.c_str())); +    } +    RunOptimizations(graph, +                     codegen, +                     dex_compilation_unit, +                     pass_observer, +                     handles, +                     optimizations.data(), +                     length);      return;    } -  HDeadCodeElimination* dce1 = new (allocator) HDeadCodeElimination( -      graph, stats, "dead_code_elimination$initial"); -  HDeadCodeElimination* dce2 = new (allocator) HDeadCodeElimination( -      graph, stats, "dead_code_elimination$after_inlining"); -  HDeadCodeElimination* dce3 = new (allocator) HDeadCodeElimination( -      graph, stats, "dead_code_elimination$final"); -  HConstantFolding* fold1 = new (allocator) HConstantFolding(graph, "constant_folding"); -  InstructionSimplifier* simplify1 = new (allocator) InstructionSimplifier( -      graph, codegen, driver, stats); -  HSelectGenerator* select_generator = new (allocator) HSelectGenerator(graph, handles, stats); -  HConstantFolding* fold2 = new (allocator) HConstantFolding( -      graph, "constant_folding$after_inlining"); -  HConstantFolding* fold3 = new (allocator) HConstantFolding(graph, "constant_folding$after_bce"); -  SideEffectsAnalysis* side_effects1 = new (allocator) SideEffectsAnalysis( -      graph, "side_effects$before_gvn"); -  SideEffectsAnalysis* side_effects2 = new (allocator) SideEffectsAnalysis( -      graph, "side_effects$before_lse"); -  GVNOptimization* gvn = new (allocator) GVNOptimization(graph, *side_effects1); -  LICM* licm = new (allocator) LICM(graph, *side_effects1, stats); -  HInductionVarAnalysis* induction = new (allocator) HInductionVarAnalysis(graph); -  BoundsCheckElimination* bce = -      new (allocator) BoundsCheckElimination(graph, *side_effects1, induction); -  HLoopOptimization* loop = new (allocator) HLoopOptimization(graph, driver, induction, stats); -  LoadStoreAnalysis* lsa = new (allocator) LoadStoreAnalysis(graph); -  LoadStoreElimination* lse = -      new (allocator) LoadStoreElimination(graph, *side_effects2, *lsa, stats); -  HSharpening* sharpening = new (allocator) HSharpening( -      graph, codegen, dex_compilation_unit, driver, handles); -  InstructionSimplifier* simplify2 = new (allocator) InstructionSimplifier( -      graph, codegen, driver, stats, "instruction_simplifier$after_inlining"); -  InstructionSimplifier* simplify3 = new (allocator) InstructionSimplifier( -      graph, codegen, driver, stats, "instruction_simplifier$after_bce"); -  InstructionSimplifier* simplify4 = new (allocator) InstructionSimplifier( -      graph, codegen, driver, stats, "instruction_simplifier$before_codegen"); -  IntrinsicsRecognizer* intrinsics = new (allocator) IntrinsicsRecognizer(graph, stats); -  CHAGuardOptimization* cha_guard = new (allocator) CHAGuardOptimization(graph); -  CodeSinking* code_sinking = new (allocator) CodeSinking(graph, stats); -  ConstructorFenceRedundancyElimination* cfre = -      new (allocator) ConstructorFenceRedundancyElimination(graph, stats); - -  HOptimization* optimizations1[] = { -    intrinsics, -    sharpening, -    fold1, -    simplify1, -    dce1, +  OptimizationDef optimizations1[] = { +    OptDef(OptimizationPass::kIntrinsicsRecognizer), +    OptDef(OptimizationPass::kSharpening), +    OptDef(OptimizationPass::kConstantFolding), +    OptDef(OptimizationPass::kInstructionSimplifier), +    OptDef(OptimizationPass::kDeadCodeElimination, "dead_code_elimination$initial")    }; -  RunOptimizations(optimizations1, arraysize(optimizations1), pass_observer); +  RunOptimizations(graph, +                   codegen, +                   dex_compilation_unit, +                   pass_observer, +                   handles, +                   optimizations1); -  MaybeRunInliner(graph, codegen, driver, dex_compilation_unit, pass_observer, handles); +  MaybeRunInliner(graph, codegen, dex_compilation_unit, pass_observer, handles); -  HOptimization* optimizations2[] = { +  OptimizationDef optimizations2[] = {      // SelectGenerator depends on the InstructionSimplifier removing      // redundant suspend checks to recognize empty blocks. -    select_generator, -    fold2,  // TODO: if we don't inline we can also skip fold2. -    simplify2, -    dce2, -    side_effects1, -    gvn, -    licm, -    induction, -    bce, -    loop, -    fold3,  // evaluates code generated by dynamic bce -    simplify3, -    side_effects2, -    lsa, -    lse, -    cha_guard, -    dce3, -    code_sinking, +    OptDef(OptimizationPass::kSelectGenerator), +    // TODO: if we don't inline we can also skip fold2. +    OptDef(OptimizationPass::kConstantFolding,       "constant_folding$after_inlining"), +    OptDef(OptimizationPass::kInstructionSimplifier, "instruction_simplifier$after_inlining"), +    OptDef(OptimizationPass::kDeadCodeElimination,   "dead_code_elimination$after_inlining"), +    OptDef(OptimizationPass::kSideEffectsAnalysis,   "side_effects$before_gvn"), +    OptDef(OptimizationPass::kGlobalValueNumbering), +    OptDef(OptimizationPass::kInvariantCodeMotion), +    OptDef(OptimizationPass::kInductionVarAnalysis), +    OptDef(OptimizationPass::kBoundsCheckElimination), +    OptDef(OptimizationPass::kLoopOptimization), +    // Evaluates code generated by dynamic bce. +    OptDef(OptimizationPass::kConstantFolding,       "constant_folding$after_bce"), +    OptDef(OptimizationPass::kInstructionSimplifier, "instruction_simplifier$after_bce"), +    OptDef(OptimizationPass::kSideEffectsAnalysis,   "side_effects$before_lse"), +    OptDef(OptimizationPass::kLoadStoreAnalysis), +    OptDef(OptimizationPass::kLoadStoreElimination), +    OptDef(OptimizationPass::kCHAGuardOptimization), +    OptDef(OptimizationPass::kDeadCodeElimination,   "dead_code_elimination$final"), +    OptDef(OptimizationPass::kCodeSinking),      // The codegen has a few assumptions that only the instruction simplifier      // can satisfy. For example, the code generator does not expect to see a      // HTypeConversion from a type to the same type. -    simplify4, -    cfre,  // Eliminate constructor fences after code sinking to avoid -           // complicated sinking logic to split a fence with many inputs. +    OptDef(OptimizationPass::kInstructionSimplifier, "instruction_simplifier$before_codegen"), +    // Eliminate constructor fences after code sinking to avoid +    // complicated sinking logic to split a fence with many inputs. +    OptDef(OptimizationPass::kConstructorFenceRedundancyElimination)    }; -  RunOptimizations(optimizations2, arraysize(optimizations2), pass_observer); +  RunOptimizations(graph, +                   codegen, +                   dex_compilation_unit, +                   pass_observer, +                   handles, +                   optimizations2); -  RunArchOptimizations(driver->GetInstructionSet(), graph, codegen, pass_observer); +  RunArchOptimizations(graph, codegen, dex_compilation_unit, pass_observer, handles);  }  static ArenaVector<linker::LinkerPatch> EmitAndSortLinkerPatches(CodeGenerator* codegen) { @@ -894,8 +700,7 @@ static ArenaVector<linker::LinkerPatch> EmitAndSortLinkerPatches(CodeGenerator*  CompiledMethod* OptimizingCompiler::Emit(ArenaAllocator* allocator,                                           CodeVectorAllocator* code_allocator,                                           CodeGenerator* codegen, -                                         CompilerDriver* compiler_driver, -                                         const DexFile::CodeItem* code_item) const { +                                         const DexFile::CodeItem* code_item_for_osr_check) const {    ArenaVector<linker::LinkerPatch> linker_patches = EmitAndSortLinkerPatches(codegen);    ArenaVector<uint8_t> stack_map(allocator->Adapter(kArenaAllocStackMaps));    ArenaVector<uint8_t> method_info(allocator->Adapter(kArenaAllocStackMaps)); @@ -906,10 +711,10 @@ CompiledMethod* OptimizingCompiler::Emit(ArenaAllocator* allocator,    method_info.resize(method_info_size);    codegen->BuildStackMaps(MemoryRegion(stack_map.data(), stack_map.size()),                            MemoryRegion(method_info.data(), method_info.size()), -                          *code_item); +                          code_item_for_osr_check);    CompiledMethod* compiled_method = CompiledMethod::SwapAllocCompiledMethod( -      compiler_driver, +      GetCompilerDriver(),        codegen->GetInstructionSet(),        ArrayRef<const uint8_t>(code_allocator->GetMemory()),        // Follow Quick's behavior and set the frame size to zero if it is @@ -929,21 +734,16 @@ CompiledMethod* OptimizingCompiler::Emit(ArenaAllocator* allocator,  CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator,                                                ArenaStack* arena_stack,                                                CodeVectorAllocator* code_allocator, -                                              const DexFile::CodeItem* code_item, -                                              uint32_t access_flags, -                                              InvokeType invoke_type, -                                              uint16_t class_def_idx, -                                              uint32_t method_idx, -                                              Handle<mirror::ClassLoader> class_loader, -                                              const DexFile& dex_file, -                                              Handle<mirror::DexCache> dex_cache, +                                              const DexCompilationUnit& dex_compilation_unit,                                                ArtMethod* method,                                                bool osr,                                                VariableSizedHandleScope* handles) const { -  MaybeRecordStat(compilation_stats_.get(), -                  MethodCompilationStat::kAttemptCompilation); +  MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kAttemptCompilation);    CompilerDriver* compiler_driver = GetCompilerDriver();    InstructionSet instruction_set = compiler_driver->GetInstructionSet(); +  const DexFile& dex_file = *dex_compilation_unit.GetDexFile(); +  uint32_t method_idx = dex_compilation_unit.GetDexMethodIndex(); +  const DexFile::CodeItem* code_item = dex_compilation_unit.GetCodeItem();    // Always use the Thumb-2 assembler: some runtime functionality    // (like implicit stack overflow checks) assume Thumb-2. @@ -973,18 +773,6 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator,      return nullptr;    } -  ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); -  DexCompilationUnit dex_compilation_unit( -      class_loader, -      class_linker, -      dex_file, -      code_item, -      class_def_idx, -      method_idx, -      access_flags, -      /* verified_method */ nullptr, -      dex_cache); -    HGraph* graph = new (allocator) HGraph(        allocator,        arena_stack, @@ -996,11 +784,6 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator,        osr);    const uint8_t* interpreter_metadata = nullptr; -  if (method == nullptr) { -    ScopedObjectAccess soa(Thread::Current()); -    method = compiler_driver->ResolveMethod( -        soa, dex_cache, class_loader, &dex_compilation_unit, method_idx, invoke_type); -  }    // For AOT compilation, we may not get a method, for example if its class is erroneous.    // JIT should always have a method.    DCHECK(Runtime::Current()->IsAotCompiler() || method != nullptr); @@ -1034,6 +817,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator,      VLOG(compiler) << "Building " << pass_observer.GetMethodName();      PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer);      HGraphBuilder builder(graph, +                          code_item,                            &dex_compilation_unit,                            &dex_compilation_unit,                            compiler_driver, @@ -1074,7 +858,6 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator,    RunOptimizations(graph,                     codegen.get(), -                   compiler_driver,                     dex_compilation_unit,                     &pass_observer,                     handles); @@ -1093,6 +876,112 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator,    return codegen.release();  } +CodeGenerator* OptimizingCompiler::TryCompileIntrinsic( +    ArenaAllocator* allocator, +    ArenaStack* arena_stack, +    CodeVectorAllocator* code_allocator, +    const DexCompilationUnit& dex_compilation_unit, +    ArtMethod* method, +    VariableSizedHandleScope* handles) const { +  CompilerDriver* compiler_driver = GetCompilerDriver(); +  InstructionSet instruction_set = compiler_driver->GetInstructionSet(); +  const DexFile& dex_file = *dex_compilation_unit.GetDexFile(); +  uint32_t method_idx = dex_compilation_unit.GetDexMethodIndex(); + +  // Always use the Thumb-2 assembler: some runtime functionality +  // (like implicit stack overflow checks) assume Thumb-2. +  DCHECK_NE(instruction_set, InstructionSet::kArm); + +  // Do not attempt to compile on architectures we do not support. +  if (!IsInstructionSetSupported(instruction_set)) { +    MaybeRecordStat(compilation_stats_.get(), +                    MethodCompilationStat::kNotCompiledUnsupportedIsa); +    return nullptr; +  } + +  HGraph* graph = new (allocator) HGraph( +      allocator, +      arena_stack, +      dex_file, +      method_idx, +      compiler_driver->GetInstructionSet(), +      kInvalidInvokeType, +      compiler_driver->GetCompilerOptions().GetDebuggable(), +      /* osr */ false); + +  DCHECK(Runtime::Current()->IsAotCompiler()); +  DCHECK(method != nullptr); +  graph->SetArtMethod(method); + +  std::unique_ptr<CodeGenerator> codegen( +      CodeGenerator::Create(graph, +                            instruction_set, +                            *compiler_driver->GetInstructionSetFeatures(), +                            compiler_driver->GetCompilerOptions(), +                            compilation_stats_.get())); +  if (codegen.get() == nullptr) { +    MaybeRecordStat(compilation_stats_.get(), +                    MethodCompilationStat::kNotCompiledNoCodegen); +    return nullptr; +  } +  codegen->GetAssembler()->cfi().SetEnabled( +      compiler_driver->GetCompilerOptions().GenerateAnyDebugInfo()); + +  PassObserver pass_observer(graph, +                             codegen.get(), +                             visualizer_output_.get(), +                             compiler_driver, +                             dump_mutex_); + +  { +    VLOG(compiler) << "Building intrinsic graph " << pass_observer.GetMethodName(); +    PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer); +    HGraphBuilder builder(graph, +                          /* code_item */ nullptr, +                          &dex_compilation_unit, +                          &dex_compilation_unit, +                          compiler_driver, +                          codegen.get(), +                          compilation_stats_.get(), +                          /* interpreter_metadata */ nullptr, +                          handles); +    builder.BuildIntrinsicGraph(method); +  } + +  OptimizationDef optimizations[] = { +    OptDef(OptimizationPass::kIntrinsicsRecognizer), +    // Some intrinsics are converted to HIR by the simplifier and the codegen also +    // has a few assumptions that only the instruction simplifier can satisfy. +    OptDef(OptimizationPass::kInstructionSimplifier), +  }; +  RunOptimizations(graph, +                   codegen.get(), +                   dex_compilation_unit, +                   &pass_observer, +                   handles, +                   optimizations); + +  RunArchOptimizations(graph, codegen.get(), dex_compilation_unit, &pass_observer, handles); + +  AllocateRegisters(graph, +                    codegen.get(), +                    &pass_observer, +                    compiler_driver->GetCompilerOptions().GetRegisterAllocationStrategy(), +                    compilation_stats_.get()); +  if (!codegen->IsLeafMethod()) { +    VLOG(compiler) << "Intrinsic method is not leaf: " << method->GetIntrinsic() +        << " " << graph->PrettyMethod(); +    return nullptr; +  } + +  codegen->Compile(code_allocator); +  pass_observer.DumpDisassembly(); + +  VLOG(compiler) << "Compiled intrinsic: " << method->GetIntrinsic() +      << " " << graph->PrettyMethod(); +  return codegen.release(); +} +  CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,                                              uint32_t access_flags,                                              InvokeType invoke_type, @@ -1102,42 +991,70 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,                                              const DexFile& dex_file,                                              Handle<mirror::DexCache> dex_cache) const {    CompilerDriver* compiler_driver = GetCompilerDriver(); -  CompiledMethod* method = nullptr; -  DCHECK(Runtime::Current()->IsAotCompiler()); +  CompiledMethod* compiled_method = nullptr; +  Runtime* runtime = Runtime::Current(); +  DCHECK(runtime->IsAotCompiler());    const VerifiedMethod* verified_method = compiler_driver->GetVerifiedMethod(&dex_file, method_idx);    DCHECK(!verified_method->HasRuntimeThrow());    if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file) ||        verifier::CanCompilerHandleVerificationFailure(            verified_method->GetEncounteredVerificationFailures())) { -    ArenaAllocator allocator(Runtime::Current()->GetArenaPool()); -    ArenaStack arena_stack(Runtime::Current()->GetArenaPool()); +    ArenaAllocator allocator(runtime->GetArenaPool()); +    ArenaStack arena_stack(runtime->GetArenaPool());      CodeVectorAllocator code_allocator(&allocator);      std::unique_ptr<CodeGenerator> codegen; +    bool compiled_intrinsic = false;      { +      DexCompilationUnit dex_compilation_unit( +          jclass_loader, +          runtime->GetClassLinker(), +          dex_file, +          code_item, +          class_def_idx, +          method_idx, +          access_flags, +          /* verified_method */ nullptr,  // Not needed by the Optimizing compiler. +          dex_cache);        ScopedObjectAccess soa(Thread::Current()); +      ArtMethod* method = compiler_driver->ResolveMethod( +            soa, dex_cache, jclass_loader, &dex_compilation_unit, method_idx, invoke_type);        VariableSizedHandleScope handles(soa.Self());        // Go to native so that we don't block GC during compilation.        ScopedThreadSuspension sts(soa.Self(), kNative); -      codegen.reset( -          TryCompile(&allocator, -                     &arena_stack, -                     &code_allocator, -                     code_item, -                     access_flags, -                     invoke_type, -                     class_def_idx, -                     method_idx, -                     jclass_loader, -                     dex_file, -                     dex_cache, -                     nullptr, -                     /* osr */ false, -                     &handles)); +      if (method != nullptr && UNLIKELY(method->IsIntrinsic())) { +        DCHECK(compiler_driver->GetCompilerOptions().IsBootImage()); +        codegen.reset( +            TryCompileIntrinsic(&allocator, +                                &arena_stack, +                                &code_allocator, +                                dex_compilation_unit, +                                method, +                                &handles)); +        if (codegen != nullptr) { +          compiled_intrinsic = true; +        } +      } +      if (codegen == nullptr) { +        codegen.reset( +            TryCompile(&allocator, +                       &arena_stack, +                       &code_allocator, +                       dex_compilation_unit, +                       method, +                       /* osr */ false, +                       &handles)); +      }      }      if (codegen.get() != nullptr) {        MaybeRecordStat(compilation_stats_.get(),                        MethodCompilationStat::kCompiled); -      method = Emit(&allocator, &code_allocator, codegen.get(), compiler_driver, code_item); +      compiled_method = Emit(&allocator, +                             &code_allocator, +                             codegen.get(), +                             compiled_intrinsic ? nullptr : code_item); +      if (compiled_intrinsic) { +        compiled_method->MarkAsIntrinsic(); +      }        if (kArenaAllocatorCountAllocations) {          codegen.reset();  // Release codegen's ScopedArenaAllocator for memory accounting. @@ -1171,10 +1088,61 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,      // regressing.      std::string method_name = dex_file.PrettyMethod(method_idx);      bool shouldCompile = method_name.find("$opt$") != std::string::npos; -    DCHECK((method != nullptr) || !shouldCompile) << "Didn't compile " << method_name; +    DCHECK((compiled_method != nullptr) || !shouldCompile) << "Didn't compile " << method_name; +  } + +  return compiled_method; +} + +CompiledMethod* OptimizingCompiler::JniCompile(uint32_t access_flags, +                                               uint32_t method_idx, +                                               const DexFile& dex_file, +                                               Handle<mirror::DexCache> dex_cache) const { +  if (GetCompilerDriver()->GetCompilerOptions().IsBootImage()) { +    ScopedObjectAccess soa(Thread::Current()); +    Runtime* runtime = Runtime::Current(); +    ArtMethod* method = runtime->GetClassLinker()->LookupResolvedMethod( +        method_idx, dex_cache.Get(), /* class_loader */ nullptr); +    if (method != nullptr && UNLIKELY(method->IsIntrinsic())) { +      ScopedNullHandle<mirror::ClassLoader> class_loader;  // null means boot class path loader. +      DexCompilationUnit dex_compilation_unit( +          class_loader, +          runtime->GetClassLinker(), +          dex_file, +          /* code_item */ nullptr, +          /* class_def_idx */ DexFile::kDexNoIndex16, +          method_idx, +          access_flags, +          /* verified_method */ nullptr, +          dex_cache); +      ArenaAllocator allocator(runtime->GetArenaPool()); +      ArenaStack arena_stack(runtime->GetArenaPool()); +      CodeVectorAllocator code_allocator(&allocator); +      VariableSizedHandleScope handles(soa.Self()); +      // Go to native so that we don't block GC during compilation. +      ScopedThreadSuspension sts(soa.Self(), kNative); +      std::unique_ptr<CodeGenerator> codegen( +          TryCompileIntrinsic(&allocator, +                              &arena_stack, +                              &code_allocator, +                              dex_compilation_unit, +                              method, +                              &handles)); +      if (codegen != nullptr) { +        CompiledMethod* compiled_method = Emit(&allocator, +                                               &code_allocator, +                                               codegen.get(), +                                               /* code_item_for_osr_check */ nullptr); +        compiled_method->MarkAsIntrinsic(); +        return compiled_method; +      } +    }    } -  return method; +  return ArtQuickJniCompileMethod(GetCompilerDriver(), +                                  access_flags, +                                  method_idx, +                                  dex_file);  }  Compiler* CreateOptimizingCompiler(CompilerDriver* driver) { @@ -1221,29 +1189,33 @@ bool OptimizingCompiler::JitCompile(Thread* self,    const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());    const uint32_t method_idx = method->GetDexMethodIndex();    const uint32_t access_flags = method->GetAccessFlags(); -  const InvokeType invoke_type = method->GetInvokeType(); -  ArenaAllocator allocator(Runtime::Current()->GetJitArenaPool()); +  Runtime* runtime = Runtime::Current(); +  ArenaAllocator allocator(runtime->GetJitArenaPool());    ArenaStack arena_stack(Runtime::Current()->GetJitArenaPool());    CodeVectorAllocator code_allocator(&allocator);    VariableSizedHandleScope handles(self);    std::unique_ptr<CodeGenerator> codegen;    { +    DexCompilationUnit dex_compilation_unit( +        class_loader, +        runtime->GetClassLinker(), +        *dex_file, +        code_item, +        class_def_idx, +        method_idx, +        access_flags, +        /* verified_method */ nullptr, +        dex_cache); +      // Go to native so that we don't block GC during compilation.      ScopedThreadSuspension sts(self, kNative);      codegen.reset(          TryCompile(&allocator,                     &arena_stack,                     &code_allocator, -                   code_item, -                   access_flags, -                   invoke_type, -                   class_def_idx, -                   method_idx, -                   class_loader, -                   *dex_file, -                   dex_cache, +                   dex_compilation_unit,                     method,                     osr,                     &handles)); @@ -1286,7 +1258,7 @@ bool OptimizingCompiler::JitCompile(Thread* self,    MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kCompiled);    codegen->BuildStackMaps(MemoryRegion(stack_map_data, stack_map_size),                            MemoryRegion(method_info_data, method_info_size), -                          *code_item); +                          code_item);    codegen->EmitJitRoots(code_allocator.GetData(), roots, roots_data);    const void* code = code_cache->CommitCode( diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h index e90c30d5ca..158c252f45 100644 --- a/compiler/optimizing/optimizing_unit_test.h +++ b/compiler/optimizing/optimizing_unit_test.h @@ -22,6 +22,7 @@  #include "common_compiler_test.h"  #include "dex_file.h"  #include "dex_instruction.h" +#include "driver/dex_compilation_unit.h"  #include "handle_scope-inl.h"  #include "mirror/class_loader.h"  #include "mirror/dex_cache.h" @@ -133,12 +134,11 @@ class OptimizingUnitTest : public CommonCompilerTest {        if (handles_ == nullptr) {          handles_.reset(new VariableSizedHandleScope(soa.Self()));        } -      const DexFile* dex_file = graph->GetAllocator()->Alloc<DexFile>();        const DexCompilationUnit* dex_compilation_unit =            new (graph->GetAllocator()) DexCompilationUnit(                handles_->NewHandle<mirror::ClassLoader>(nullptr),                /* class_linker */ nullptr, -              *dex_file, +              graph->GetDexFile(),                code_item,                /* class_def_index */ DexFile::kDexNoIndex16,                /* method_idx */ dex::kDexNoIndex, diff --git a/compiler/optimizing/pc_relative_fixups_mips.h b/compiler/optimizing/pc_relative_fixups_mips.h index 5a7397bf9d..ec2c711f8d 100644 --- a/compiler/optimizing/pc_relative_fixups_mips.h +++ b/compiler/optimizing/pc_relative_fixups_mips.h @@ -29,7 +29,7 @@ namespace mips {  class PcRelativeFixups : public HOptimization {   public:    PcRelativeFixups(HGraph* graph, CodeGenerator* codegen, OptimizingCompilerStats* stats) -      : HOptimization(graph, "pc_relative_fixups_mips", stats), +      : HOptimization(graph, kPcRelativeFixupsMipsPassName, stats),          codegen_(codegen) {}    static constexpr const char* kPcRelativeFixupsMipsPassName = "pc_relative_fixups_mips"; diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc index fe98aa9561..1ed190d328 100644 --- a/compiler/optimizing/prepare_for_register_allocation.cc +++ b/compiler/optimizing/prepare_for_register_allocation.cc @@ -53,16 +53,18 @@ void PrepareForRegisterAllocation::VisitDeoptimize(HDeoptimize* deoptimize) {  void PrepareForRegisterAllocation::VisitBoundsCheck(HBoundsCheck* check) {    check->ReplaceWith(check->InputAt(0));    if (check->IsStringCharAt()) { -    // Add a fake environment for String.charAt() inline info as we want -    // the exception to appear as being thrown from there. +    // Add a fake environment for String.charAt() inline info as we want the exception +    // to appear as being thrown from there. Skip if we're compiling String.charAt() itself.      ArtMethod* char_at_method = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt); -    ArenaAllocator* allocator = GetGraph()->GetAllocator(); -    HEnvironment* environment = new (allocator) HEnvironment(allocator, -                                                             /* number_of_vregs */ 0u, -                                                             char_at_method, -                                                             /* dex_pc */ dex::kDexNoIndex, -                                                             check); -    check->InsertRawEnvironment(environment); +    if (GetGraph()->GetArtMethod() != char_at_method) { +      ArenaAllocator* allocator = GetGraph()->GetAllocator(); +      HEnvironment* environment = new (allocator) HEnvironment(allocator, +                                                               /* number_of_vregs */ 0u, +                                                               char_at_method, +                                                               /* dex_pc */ dex::kDexNoIndex, +                                                               check); +      check->InsertRawEnvironment(environment); +    }    }  } diff --git a/compiler/optimizing/scheduler.h b/compiler/optimizing/scheduler.h index a6e160379b..bb7c353bc2 100644 --- a/compiler/optimizing/scheduler.h +++ b/compiler/optimizing/scheduler.h @@ -495,8 +495,11 @@ inline bool SchedulingGraph::IsSchedulingBarrier(const HInstruction* instruction  class HInstructionScheduling : public HOptimization {   public: -  HInstructionScheduling(HGraph* graph, InstructionSet instruction_set, CodeGenerator* cg = nullptr) -      : HOptimization(graph, kInstructionScheduling), +  HInstructionScheduling(HGraph* graph, +                         InstructionSet instruction_set, +                         CodeGenerator* cg = nullptr, +                         const char* name = kInstructionSchedulingPassName) +      : HOptimization(graph, name),          codegen_(cg),          instruction_set_(instruction_set) {} @@ -505,7 +508,7 @@ class HInstructionScheduling : public HOptimization {    }    void Run(bool only_optimize_loop_blocks, bool schedule_randomly); -  static constexpr const char* kInstructionScheduling = "scheduler"; +  static constexpr const char* kInstructionSchedulingPassName = "scheduler";   private:    CodeGenerator* const codegen_; diff --git a/compiler/optimizing/select_generator.cc b/compiler/optimizing/select_generator.cc index 77ec9a6285..66e51421ca 100644 --- a/compiler/optimizing/select_generator.cc +++ b/compiler/optimizing/select_generator.cc @@ -24,8 +24,9 @@ static constexpr size_t kMaxInstructionsInBranch = 1u;  HSelectGenerator::HSelectGenerator(HGraph* graph,                                     VariableSizedHandleScope* handles, -                                   OptimizingCompilerStats* stats) -    : HOptimization(graph, kSelectGeneratorPassName, stats), +                                   OptimizingCompilerStats* stats, +                                   const char* name) +    : HOptimization(graph, name, stats),        handle_scope_(handles) {  } diff --git a/compiler/optimizing/select_generator.h b/compiler/optimizing/select_generator.h index f8cf00e35a..bda57fd5c8 100644 --- a/compiler/optimizing/select_generator.h +++ b/compiler/optimizing/select_generator.h @@ -65,7 +65,8 @@ class HSelectGenerator : public HOptimization {   public:    HSelectGenerator(HGraph* graph,                     VariableSizedHandleScope* handles, -                   OptimizingCompilerStats* stats); +                   OptimizingCompilerStats* stats, +                   const char* name = kSelectGeneratorPassName);    void Run() OVERRIDE; diff --git a/compiler/optimizing/sharpening.h b/compiler/optimizing/sharpening.h index f74b0afdbf..bb1954eeeb 100644 --- a/compiler/optimizing/sharpening.h +++ b/compiler/optimizing/sharpening.h @@ -36,8 +36,9 @@ class HSharpening : public HOptimization {                CodeGenerator* codegen,                const DexCompilationUnit& compilation_unit,                CompilerDriver* compiler_driver, -              VariableSizedHandleScope* handles) -      : HOptimization(graph, kSharpeningPassName), +              VariableSizedHandleScope* handles, +              const char* name = kSharpeningPassName) +      : HOptimization(graph, name),          codegen_(codegen),          compilation_unit_(compilation_unit),          compiler_driver_(compiler_driver), diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc index 9bc80457a3..4f43eb374c 100644 --- a/compiler/optimizing/stack_map_stream.cc +++ b/compiler/optimizing/stack_map_stream.cc @@ -32,7 +32,6 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc,                                          uint32_t num_dex_registers,                                          uint8_t inlining_depth) {    DCHECK_EQ(0u, current_entry_.dex_pc) << "EndStackMapEntry not called after BeginStackMapEntry"; -  DCHECK_NE(dex_pc, static_cast<uint32_t>(-1)) << "invalid dex_pc";    current_entry_.dex_pc = dex_pc;    current_entry_.native_pc_code_offset = CodeOffset::FromOffset(native_pc_offset, instruction_set_);    current_entry_.register_mask = register_mask; @@ -56,7 +55,10 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc,      number_of_stack_maps_with_inline_info_++;    } -  dex_pc_max_ = std::max(dex_pc_max_, dex_pc); +  // Note: dex_pc can be kNoDexPc for native method intrinsics. +  if (dex_pc != dex::kDexNoIndex && (dex_pc_max_ == dex::kDexNoIndex || dex_pc_max_ < dex_pc)) { +    dex_pc_max_ = dex_pc; +  }    register_mask_max_ = std::max(register_mask_max_, register_mask);    current_dex_register_ = 0;  } diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h index e126609dba..579aabdb5f 100644 --- a/compiler/optimizing/stack_map_stream.h +++ b/compiler/optimizing/stack_map_stream.h @@ -73,7 +73,7 @@ class StackMapStream : public ValueObject {          method_indices_(allocator->Adapter(kArenaAllocStackMapStream)),          dex_register_entries_(allocator->Adapter(kArenaAllocStackMapStream)),          stack_mask_max_(-1), -        dex_pc_max_(0), +        dex_pc_max_(kNoDexPc),          register_mask_max_(0),          number_of_stack_maps_with_inline_info_(0),          dex_map_hash_to_stack_map_indices_(std::less<uint32_t>(), diff --git a/compiler/utils/intrusive_forward_list_test.cc b/compiler/utils/intrusive_forward_list_test.cc index 939676cdc8..e97c3044d0 100644 --- a/compiler/utils/intrusive_forward_list_test.cc +++ b/compiler/utils/intrusive_forward_list_test.cc @@ -574,11 +574,11 @@ void IntrusiveForwardListTest::Remove() {    ref.remove(4);    ifl.remove(4);    ASSERT_LISTS_EQUAL(ref, ifl); -  auto odd = [](ValueType value) { return (value.value & 1) != 0; };  // NOLINT(readability/braces) +  auto odd = [](ValueType value) { return (value.value & 1) != 0; };    ref.remove_if(odd);    ifl.remove_if(odd);    ASSERT_LISTS_EQUAL(ref, ifl); -  auto all = [](ValueType value ATTRIBUTE_UNUSED) { return true; };  // NOLINT(readability/braces) +  auto all = [](ValueType value ATTRIBUTE_UNUSED) { return true; };    ref.remove_if(all);    ifl.remove_if(all);    ASSERT_LISTS_EQUAL(ref, ifl); @@ -721,7 +721,7 @@ void IntrusiveForwardListTest::ModifyValue() {    ListType ifl(storage.begin(), storage.end());    ASSERT_LISTS_EQUAL(ref, ifl); -  auto add1 = [](const ValueType& value) { return value.value + 1; };  // NOLINT [readability/braces] +  auto add1 = [](const ValueType& value) { return value.value + 1; };    std::transform(ref.begin(), ref.end(), ref.begin(), add1);    std::transform(ifl.begin(), ifl.end(), ifl.begin(), add1);    ASSERT_LISTS_EQUAL(ref, ifl); diff --git a/compiler/utils/swap_space.h b/compiler/utils/swap_space.h index 08e243b644..2280f8b993 100644 --- a/compiler/utils/swap_space.h +++ b/compiler/utils/swap_space.h @@ -124,7 +124,7 @@ class SwapAllocator<void> {    explicit SwapAllocator(SwapSpace* swap_space) : swap_space_(swap_space) {}    template <typename U> -  SwapAllocator(const SwapAllocator<U>& other)  // NOLINT, implicit +  SwapAllocator(const SwapAllocator<U>& other)        : swap_space_(other.swap_space_) {}    SwapAllocator(const SwapAllocator& other) = default; @@ -160,7 +160,7 @@ class SwapAllocator {    explicit SwapAllocator(SwapSpace* swap_space) : swap_space_(swap_space) {}    template <typename U> -  SwapAllocator(const SwapAllocator<U>& other)  // NOLINT, implicit +  SwapAllocator(const SwapAllocator<U>& other)        : swap_space_(other.swap_space_) {}    SwapAllocator(const SwapAllocator& other) = default; diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc index e232addd26..36c5c3c0c4 100644 --- a/compiler/utils/x86/assembler_x86_test.cc +++ b/compiler/utils/x86/assembler_x86_test.cc @@ -90,7 +90,7 @@ class AssemblerX86Test : public AssemblerTest<x86::X86Assembler,      }      if (registers_.size() == 0) {        registers_.insert(end(registers_), -                        {  // NOLINT(whitespace/braces) +                        {                            new x86::Register(x86::EAX),                            new x86::Register(x86::EBX),                            new x86::Register(x86::ECX), @@ -104,7 +104,7 @@ class AssemblerX86Test : public AssemblerTest<x86::X86Assembler,      if (fp_registers_.size() == 0) {        fp_registers_.insert(end(fp_registers_), -                           {  // NOLINT(whitespace/braces) +                           {                               new x86::XmmRegister(x86::XMM0),                               new x86::XmmRegister(x86::XMM1),                               new x86::XmmRegister(x86::XMM2),  |