From 9b297bfc588c7d38efd12a6f38cd2710fc513ee3 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 6 Sep 2013 11:11:25 -0700 Subject: Refactor CompilerDriver::Compute..FieldInfo Don't use non-const reference arguments. Move ins before outs. Change-Id: I7b251156388d8f07513b3da62ebfd29e5fd9ff76 --- compiler/dex/quick/codegen_util.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index e081c16bb5..dcb0a99d08 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -50,9 +50,9 @@ void Mir2Lir::MarkSafepointPC(LIR* inst) { DCHECK_EQ(safepoint_pc->def_mask, ENCODE_ALL); } -bool Mir2Lir::FastInstance(uint32_t field_idx, int& field_offset, bool& is_volatile, bool is_put) { +bool Mir2Lir::FastInstance(uint32_t field_idx, bool is_put, int* field_offset, bool* is_volatile) { return cu_->compiler_driver->ComputeInstanceFieldInfo( - field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, is_volatile, is_put); + field_idx, mir_graph_->GetCurrentDexCompilationUnit(), is_put, field_offset, is_volatile); } /* Convert an instruction to a NOP */ -- cgit v1.2.3-59-g8ed1b From 56c717860df2d71d66fb77aa77f29dd346e559d3 Mon Sep 17 00:00:00 2001 From: buzbee Date: Thu, 5 Sep 2013 17:13:19 -0700 Subject: Compile-time tuning Specialized the dataflow iterators and did a few other minor tweaks. Showing ~5% compile-time improvement in a single-threaded environment; less in multi-threaded (presumably because we're blocked by something else). Change-Id: I2e2ed58d881414b9fc97e04cd0623e188259afd2 --- compiler/dex/dataflow_iterator-inl.h | 71 +++++++++++------- compiler/dex/dataflow_iterator.h | 118 ++++++++++++++++-------------- compiler/dex/growable_array.h | 5 ++ compiler/dex/mir_analysis.cc | 2 +- compiler/dex/mir_dataflow.cc | 4 +- compiler/dex/mir_optimization.cc | 14 ++-- compiler/dex/portable/mir_to_gbc.cc | 4 +- compiler/dex/quick/codegen_util.cc | 12 +-- compiler/dex/quick/local_optimizations.cc | 5 +- compiler/dex/quick/mir_to_lir-inl.h | 7 +- compiler/dex/quick/mir_to_lir.cc | 7 +- compiler/dex/quick/mir_to_lir.h | 2 +- compiler/dex/quick/ralloc_util.cc | 91 +++++++---------------- compiler/dex/ssa_transformation.cc | 20 ++--- compiler/dex/vreg_analysis.cc | 2 +- 15 files changed, 183 insertions(+), 181 deletions(-) (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/dataflow_iterator-inl.h b/compiler/dex/dataflow_iterator-inl.h index 06cc505a9a..236c6f4940 100644 --- a/compiler/dex/dataflow_iterator-inl.h +++ b/compiler/dex/dataflow_iterator-inl.h @@ -21,42 +21,63 @@ namespace art { -inline BasicBlock* DataflowIterator::NextBody(bool had_change) { +// Single forward pass over the nodes. +inline BasicBlock* DataflowIterator::ForwardSingleNext() { + BasicBlock* res = NULL; + if (idx_ < end_idx_) { + int bb_id = block_id_list_->Get(idx_++); + res = mir_graph_->GetBasicBlock(bb_id); + } + return res; +} + +// Repeat full forward passes over all nodes until no change occurs during a complete pass. +inline BasicBlock* DataflowIterator::ForwardRepeatNext(bool had_change) { changed_ |= had_change; BasicBlock* res = NULL; - if (reverse_) { - if (is_iterative_ && changed_ && (idx_ < 0)) { - idx_ = start_idx_; - changed_ = false; - } - if (idx_ >= 0) { - int bb_id = block_id_list_->Get(idx_--); - res = mir_graph_->GetBasicBlock(bb_id); - } - } else { - if (is_iterative_ && changed_ && (idx_ >= end_idx_)) { - idx_ = start_idx_; - changed_ = false; - } - if (idx_ < end_idx_) { - int bb_id = block_id_list_->Get(idx_++); - res = mir_graph_->GetBasicBlock(bb_id); - } + if ((idx_ >= end_idx_) && changed_) { + idx_ = start_idx_; + changed_ = false; + } + if (idx_ < end_idx_) { + int bb_id = block_id_list_->Get(idx_++); + res = mir_graph_->GetBasicBlock(bb_id); } return res; } -// AllNodes uses the existing GrowableArray iterator, so use different NextBody(). -inline BasicBlock* AllNodesIterator::NextBody(bool had_change) { +// Single reverse pass over the nodes. +inline BasicBlock* DataflowIterator::ReverseSingleNext() { + BasicBlock* res = NULL; + if (idx_ >= 0) { + int bb_id = block_id_list_->Get(idx_--); + res = mir_graph_->GetBasicBlock(bb_id); + } + return res; +} + +// Repeat full backwards passes over all nodes until no change occurs during a complete pass. +inline BasicBlock* DataflowIterator::ReverseRepeatNext(bool had_change) { changed_ |= had_change; + BasicBlock* res = NULL; + if ((idx_ < 0) && changed_) { + idx_ = start_idx_; + changed_ = false; + } + if (idx_ >= 0) { + int bb_id = block_id_list_->Get(idx_--); + res = mir_graph_->GetBasicBlock(bb_id); + } + return res; +} + +// AllNodes uses the existing GrowableArray iterator, and should be considered unordered. +inline BasicBlock* AllNodesIterator::Next() { BasicBlock* res = NULL; bool keep_looking = true; while (keep_looking) { res = all_nodes_iterator_->Next(); - if (is_iterative_ && changed_ && (res == NULL)) { - all_nodes_iterator_->Reset(); - changed_ = false; - } else if ((res == NULL) || (!res->hidden)) { + if ((res == NULL) || (!res->hidden)) { keep_looking = false; } } diff --git a/compiler/dex/dataflow_iterator.h b/compiler/dex/dataflow_iterator.h index da44ffd99c..1dab54ea72 100644 --- a/compiler/dex/dataflow_iterator.h +++ b/compiler/dex/dataflow_iterator.h @@ -27,124 +27,130 @@ namespace art { * interesting orders. Note that for efficiency, the visit orders have been pre-computed. * The order itself will not change during the iteration. However, for some uses, * auxiliary data associated with the basic blocks may be changed during the iteration, - * necessitating another pass over the list. - * - * To support this usage, we have is_iterative_. If false, the iteration is a one-shot - * pass through the pre-computed list using Next(). If true, the caller must tell the - * iterator whether a change has been made that necessitates another pass. Use - * Next(had_change) for this. The general idea is that the iterative_ use case means - * that the iterator will keep repeating the full basic block list until a complete pass - * is made through it with no changes. Note that calling Next(true) does not affect - * the iteration order or short-curcuit the current pass - it simply tells the iterator - * that once it has finished walking through the block list it should reset and do another - * full pass through the list. + * necessitating another pass over the list. If this behavior is required, use the + * "Repeating" variant. For the repeating variant, the caller must tell the iterator + * whether a change has been made that necessitates another pass. Note that calling Next(true) + * does not affect the iteration order or short-circuit the current pass - it simply tells + * the iterator that once it has finished walking through the block list it should reset and + * do another full pass through the list. */ class DataflowIterator { public: virtual ~DataflowIterator() {} - // Return the next BasicBlock* to visit. - BasicBlock* Next() { - DCHECK(!is_iterative_); - return NextBody(false); - } - - /* - * Return the next BasicBlock* to visit, and tell the iterator whether any change - * has occurred that requires another full pass over the block list. - */ - BasicBlock* Next(bool had_change) { - DCHECK(is_iterative_); - return NextBody(had_change); - } - protected: - DataflowIterator(MIRGraph* mir_graph, bool is_iterative, int start_idx, int end_idx, - bool reverse) + DataflowIterator(MIRGraph* mir_graph, int start_idx, int end_idx) : mir_graph_(mir_graph), - is_iterative_(is_iterative), start_idx_(start_idx), end_idx_(end_idx), - reverse_(reverse), block_id_list_(NULL), idx_(0), changed_(false) {} - virtual BasicBlock* NextBody(bool had_change) ALWAYS_INLINE; + virtual BasicBlock* ForwardSingleNext() ALWAYS_INLINE; + virtual BasicBlock* ReverseSingleNext() ALWAYS_INLINE; + virtual BasicBlock* ForwardRepeatNext(bool had_change) ALWAYS_INLINE; + virtual BasicBlock* ReverseRepeatNext(bool had_change) ALWAYS_INLINE; MIRGraph* const mir_graph_; - const bool is_iterative_; const int start_idx_; const int end_idx_; - const bool reverse_; GrowableArray* block_id_list_; int idx_; bool changed_; }; // DataflowIterator - class ReachableNodesIterator : public DataflowIterator { + class PreOrderDfsIterator : public DataflowIterator { public: - ReachableNodesIterator(MIRGraph* mir_graph, bool is_iterative) - : DataflowIterator(mir_graph, is_iterative, 0, - mir_graph->GetNumReachableBlocks(), false) { + explicit PreOrderDfsIterator(MIRGraph* mir_graph) + : DataflowIterator(mir_graph, 0, mir_graph->GetNumReachableBlocks()) { idx_ = start_idx_; block_id_list_ = mir_graph->GetDfsOrder(); } + + BasicBlock* Next() { + return ForwardSingleNext(); + } }; - class PreOrderDfsIterator : public DataflowIterator { + class RepeatingPreOrderDfsIterator : public DataflowIterator { public: - PreOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative) - : DataflowIterator(mir_graph, is_iterative, 0, - mir_graph->GetNumReachableBlocks(), false) { + explicit RepeatingPreOrderDfsIterator(MIRGraph* mir_graph) + : DataflowIterator(mir_graph, 0, mir_graph->GetNumReachableBlocks()) { idx_ = start_idx_; block_id_list_ = mir_graph->GetDfsOrder(); } + + BasicBlock* Next(bool had_change) { + return ForwardRepeatNext(had_change); + } }; - class PostOrderDfsIterator : public DataflowIterator { + class RepeatingPostOrderDfsIterator : public DataflowIterator { public: - PostOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative) - : DataflowIterator(mir_graph, is_iterative, 0, - mir_graph->GetNumReachableBlocks(), false) { + explicit RepeatingPostOrderDfsIterator(MIRGraph* mir_graph) + : DataflowIterator(mir_graph, 0, mir_graph->GetNumReachableBlocks()) { idx_ = start_idx_; block_id_list_ = mir_graph->GetDfsPostOrder(); } + + BasicBlock* Next(bool had_change) { + return ForwardRepeatNext(had_change); + } }; class ReversePostOrderDfsIterator : public DataflowIterator { public: - ReversePostOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative) - : DataflowIterator(mir_graph, is_iterative, - mir_graph->GetNumReachableBlocks() -1, 0, true) { + explicit ReversePostOrderDfsIterator(MIRGraph* mir_graph) + : DataflowIterator(mir_graph, mir_graph->GetNumReachableBlocks() -1, 0) { + idx_ = start_idx_; + block_id_list_ = mir_graph->GetDfsPostOrder(); + } + + BasicBlock* Next() { + return ReverseSingleNext(); + } + }; + + class RepeatingReversePostOrderDfsIterator : public DataflowIterator { + public: + explicit RepeatingReversePostOrderDfsIterator(MIRGraph* mir_graph) + : DataflowIterator(mir_graph, mir_graph->GetNumReachableBlocks() -1, 0) { idx_ = start_idx_; block_id_list_ = mir_graph->GetDfsPostOrder(); } + + BasicBlock* Next(bool had_change) { + return ReverseRepeatNext(had_change); + } }; class PostOrderDOMIterator : public DataflowIterator { public: - PostOrderDOMIterator(MIRGraph* mir_graph, bool is_iterative) - : DataflowIterator(mir_graph, is_iterative, 0, - mir_graph->GetNumReachableBlocks(), false) { + explicit PostOrderDOMIterator(MIRGraph* mir_graph) + : DataflowIterator(mir_graph, 0, mir_graph->GetNumReachableBlocks()) { idx_ = start_idx_; block_id_list_ = mir_graph->GetDomPostOrder(); } + + BasicBlock* Next() { + return ForwardSingleNext(); + } }; class AllNodesIterator : public DataflowIterator { public: - AllNodesIterator(MIRGraph* mir_graph, bool is_iterative) - : DataflowIterator(mir_graph, is_iterative, 0, 0, false) { - all_nodes_iterator_ = - new (mir_graph->GetArena()) GrowableArray::Iterator(mir_graph->GetBlockList()); + explicit AllNodesIterator(MIRGraph* mir_graph) + : DataflowIterator(mir_graph, 0, 0) { + all_nodes_iterator_ = new + (mir_graph->GetArena()) GrowableArray::Iterator(mir_graph->GetBlockList()); } void Reset() { all_nodes_iterator_->Reset(); } - BasicBlock* NextBody(bool had_change) ALWAYS_INLINE; + BasicBlock* Next() ALWAYS_INLINE; private: GrowableArray::Iterator* all_nodes_iterator_; diff --git a/compiler/dex/growable_array.h b/compiler/dex/growable_array.h index 8e2abfbaf1..9053285af0 100644 --- a/compiler/dex/growable_array.h +++ b/compiler/dex/growable_array.h @@ -150,6 +150,11 @@ class GrowableArray { size_t Size() const { return num_used_; } + void SetSize(size_t new_size) { + Resize(new_size); + num_used_ = new_size; + } + T* GetRawStorage() const { return elem_list_; } static void* operator new(size_t size, ArenaAllocator* arena) { diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc index d7a4136a01..8472a3c011 100644 --- a/compiler/dex/mir_analysis.cc +++ b/compiler/dex/mir_analysis.cc @@ -1061,7 +1061,7 @@ bool MIRGraph::SkipCompilation(Runtime::CompilerFilter compiler_filter) { memset(&stats, 0, sizeof(stats)); ClearAllVisitedFlags(); - AllNodesIterator iter(this, false /* not iterative */); + AllNodesIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { AnalyzeBlock(bb, &stats); } diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc index 3a73717a7b..addfd6b6b7 100644 --- a/compiler/dex/mir_dataflow.cc +++ b/compiler/dex/mir_dataflow.cc @@ -1287,7 +1287,7 @@ void MIRGraph::MethodUseCount() { if (cu_->disable_opt & (1 << kPromoteRegs)) { return; } - AllNodesIterator iter(this, false /* not iterative */); + AllNodesIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { CountUses(bb); } @@ -1331,7 +1331,7 @@ bool MIRGraph::VerifyPredInfo(BasicBlock* bb) { void MIRGraph::VerifyDataflow() { /* Verify if all blocks are connected as claimed */ - AllNodesIterator iter(this, false /* not iterative */); + AllNodesIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { VerifyPredInfo(bb); } diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index b7611f8f5b..05e428e178 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -96,7 +96,7 @@ void MIRGraph::PropagateConstants() { is_constant_v_ = new (arena_) ArenaBitVector(arena_, GetNumSSARegs(), false); constant_values_ = static_cast(arena_->Alloc(sizeof(int) * GetNumSSARegs(), ArenaAllocator::kAllocDFInfo)); - AllNodesIterator iter(this, false /* not iterative */); + AllNodesIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { DoConstantPropogation(bb); } @@ -762,11 +762,11 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { void MIRGraph::NullCheckElimination() { if (!(cu_->disable_opt & (1 << kNullCheckElimination))) { DCHECK(temp_ssa_register_v_ != NULL); - AllNodesIterator iter(this, false /* not iterative */); + AllNodesIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { NullCheckEliminationInit(bb); } - PreOrderDfsIterator iter2(this, true /* iterative */); + RepeatingPreOrderDfsIterator iter2(this); bool change = false; for (BasicBlock* bb = iter2.Next(change); bb != NULL; bb = iter2.Next(change)) { change = EliminateNullChecks(bb); @@ -778,7 +778,7 @@ void MIRGraph::NullCheckElimination() { } void MIRGraph::BasicBlockCombine() { - PreOrderDfsIterator iter(this, false /* not iterative */); + PreOrderDfsIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { CombineBlocks(bb); } @@ -791,7 +791,7 @@ void MIRGraph::CodeLayout() { if (cu_->enable_debug & (1 << kDebugVerifyDataflow)) { VerifyDataflow(); } - AllNodesIterator iter(this, false /* not iterative */); + AllNodesIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { LayoutBlocks(bb); } @@ -804,7 +804,7 @@ void MIRGraph::DumpCheckStats() { Checkstats* stats = static_cast(arena_->Alloc(sizeof(Checkstats), ArenaAllocator::kAllocDFInfo)); checkstats_ = stats; - AllNodesIterator iter(this, false /* not iterative */); + AllNodesIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { CountChecks(bb); } @@ -858,7 +858,7 @@ void MIRGraph::BasicBlockOptimization() { if (!(cu_->disable_opt & (1 << kBBOpt))) { DCHECK_EQ(cu_->num_compiler_temps, 0); ClearAllVisitedFlags(); - PreOrderDfsIterator iter2(this, false /* not iterative */); + PreOrderDfsIterator iter2(this); for (BasicBlock* bb = iter2.Next(); bb != NULL; bb = iter2.Next()) { BuildExtendedBBList(bb); } diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc index 7831cf6f7a..2cf55e7ea5 100644 --- a/compiler/dex/portable/mir_to_gbc.cc +++ b/compiler/dex/portable/mir_to_gbc.cc @@ -1877,7 +1877,7 @@ void MirConverter::MethodMIR2Bitcode() { CreateFunction(); // Create an LLVM basic block for each MIR block in dfs preorder - PreOrderDfsIterator iter(mir_graph_, false /* not iterative */); + PreOrderDfsIterator iter(mir_graph_); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { CreateLLVMBasicBlock(bb); } @@ -1909,7 +1909,7 @@ void MirConverter::MethodMIR2Bitcode() { } } - PreOrderDfsIterator iter2(mir_graph_, false /* not iterative */); + PreOrderDfsIterator iter2(mir_graph_); for (BasicBlock* bb = iter2.Next(); bb != NULL; bb = iter2.Next()) { BlockBitcodeConversion(bb); } diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index e081c16bb5..8c5949b4df 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -710,7 +710,6 @@ int Mir2Lir::AssignInsnOffsets() { } /* Pseudo opcodes don't consume space */ } - return offset; } @@ -789,15 +788,15 @@ void Mir2Lir::AssembleLIR() { */ LIR* Mir2Lir::InsertCaseLabel(int vaddr, int keyVal) { SafeMap::iterator it; - it = boundary_map_.find(vaddr); - if (it == boundary_map_.end()) { + LIR* boundary_lir = boundary_map_.Get(vaddr); + if (boundary_lir == NULL) { LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr; } LIR* new_label = static_cast(arena_->Alloc(sizeof(LIR), ArenaAllocator::kAllocLIR)); new_label->dalvik_offset = vaddr; new_label->opcode = kPseudoCaseLabel; new_label->operands[0] = keyVal; - InsertLIRAfter(it->second, new_label); + InsertLIRAfter(boundary_lir, new_label); return new_label; } @@ -889,7 +888,7 @@ void Mir2Lir::DumpPackedSwitchTable(const uint16_t* table) { */ LIR* Mir2Lir::MarkBoundary(int offset, const char* inst_str) { LIR* res = NewLIR1(kPseudoDalvikByteCodeBoundary, reinterpret_cast(inst_str)); - if (boundary_map_.find(offset) == boundary_map_.end()) { + if (boundary_map_.Get(offset) == NULL) { boundary_map_.Put(offset, res); } return res; @@ -947,6 +946,7 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena throw_launchpads_(arena, 2048, kGrowableArrayThrowLaunchPads), suspend_launchpads_(arena, 4, kGrowableArraySuspendLaunchPads), intrinsic_launchpads_(arena, 2048, kGrowableArrayMisc), + boundary_map_(arena, 0, kGrowableArrayMisc), data_offset_(0), total_size_(0), block_label_list_(NULL), @@ -963,6 +963,8 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena promotion_map_ = static_cast (arena_->Alloc((cu_->num_dalvik_registers + cu_->num_compiler_temps + 1) * sizeof(promotion_map_[0]), ArenaAllocator::kAllocRegAlloc)); + // Pre-fill with nulls. + boundary_map_.SetSize(cu->code_item->insns_size_in_code_units_); } void Mir2Lir::Materialize() { diff --git a/compiler/dex/quick/local_optimizations.cc b/compiler/dex/quick/local_optimizations.cc index 630e990733..41adb946a2 100644 --- a/compiler/dex/quick/local_optimizations.cc +++ b/compiler/dex/quick/local_optimizations.cc @@ -99,12 +99,11 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { int native_reg_id; if (cu_->instruction_set == kX86) { // If x86, location differs depending on whether memory/reg operation. - native_reg_id = (GetTargetInstFlags(this_lir->opcode) & IS_STORE) ? this_lir->operands[2] - : this_lir->operands[0]; + native_reg_id = (target_flags & IS_STORE) ? this_lir->operands[2] : this_lir->operands[0]; } else { native_reg_id = this_lir->operands[0]; } - bool is_this_lir_load = GetTargetInstFlags(this_lir->opcode) & IS_LOAD; + bool is_this_lir_load = target_flags & IS_LOAD; LIR* check_lir; /* Use the mem mask to determine the rough memory location */ uint64_t this_mem_mask = (this_lir->use_mask | this_lir->def_mask) & ENCODE_MEM; diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h index 440df2afa6..f9ec19951e 100644 --- a/compiler/dex/quick/mir_to_lir-inl.h +++ b/compiler/dex/quick/mir_to_lir-inl.h @@ -33,7 +33,12 @@ inline void Mir2Lir::ClobberBody(RegisterInfo* p) { p->def_end = NULL; if (p->pair) { p->pair = false; - Clobber(p->partner); + p = GetRegInfo(p->partner); + p->pair = false; + p->live = false; + p->s_reg = INVALID_SREG; + p->def_start = NULL; + p->def_end = NULL; } } } diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc index c41feb1348..7c79f59853 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -706,16 +706,15 @@ bool Mir2Lir::MethodBlockCodeGen(BasicBlock* bb) { } // Free temp registers and reset redundant store tracking. - ResetRegPool(); - ResetDefTracking(); - ClobberAllRegs(); if (bb->block_type == kEntryBlock) { + ResetRegPool(); int start_vreg = cu_->num_dalvik_registers - cu_->num_ins; GenEntrySequence(&mir_graph_->reg_location_[start_vreg], mir_graph_->reg_location_[mir_graph_->GetMethodSReg()]); } else if (bb->block_type == kExitBlock) { + ResetRegPool(); GenExitSequence(); } @@ -815,7 +814,7 @@ void Mir2Lir::MethodMIR2LIR() { static_cast(arena_->Alloc(sizeof(LIR) * mir_graph_->GetNumBlocks(), ArenaAllocator::kAllocLIR)); - PreOrderDfsIterator iter(mir_graph_, false /* not iterative */); + PreOrderDfsIterator iter(mir_graph_); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { MethodBlockCodeGen(bb); } diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index a37ebd173f..7e6d21a440 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -727,7 +727,7 @@ class Mir2Lir : public Backend { GrowableArray throw_launchpads_; GrowableArray suspend_launchpads_; GrowableArray intrinsic_launchpads_; - SafeMap boundary_map_; // boundary lookup cache. + GrowableArray boundary_map_; /* * Holds mapping from native PC to dex PC for safepoints where we may deoptimize. * Native PC is on the return address of the safepointed operation. Dex PC is for diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc index 71b74a4a68..db110aabd5 100644 --- a/compiler/dex/quick/ralloc_util.cc +++ b/compiler/dex/quick/ralloc_util.cc @@ -379,7 +379,7 @@ Mir2Lir::RegisterInfo* Mir2Lir::AllocLiveBody(RegisterInfo* p, int num_regs, int if (s_reg == -1) return NULL; for (int i = 0; i < num_regs; i++) { - if (p[i].live && (p[i].s_reg == s_reg)) { + if ((p[i].s_reg == s_reg) && p[i].live) { if (p[i].is_temp) p[i].in_use = true; return &p[i]; @@ -412,47 +412,16 @@ Mir2Lir::RegisterInfo* Mir2Lir::AllocLive(int s_reg, int reg_class) { } void Mir2Lir::FreeTemp(int reg) { - RegisterInfo* p = reg_pool_->core_regs; - int num_regs = reg_pool_->num_core_regs; - for (int i = 0; i< num_regs; i++) { - if (p[i].reg == reg) { - if (p[i].is_temp) { - p[i].in_use = false; - } - p[i].pair = false; - return; - } - } - p = reg_pool_->FPRegs; - num_regs = reg_pool_->num_fp_regs; - for (int i = 0; i< num_regs; i++) { - if (p[i].reg == reg) { - if (p[i].is_temp) { - p[i].in_use = false; - } - p[i].pair = false; - return; - } + RegisterInfo* p = GetRegInfo(reg); + if (p->is_temp) { + p->in_use = false; } - LOG(FATAL) << "Tried to free a non-existant temp: r" << reg; + p->pair = false; } Mir2Lir::RegisterInfo* Mir2Lir::IsLive(int reg) { - RegisterInfo* p = reg_pool_->core_regs; - int num_regs = reg_pool_->num_core_regs; - for (int i = 0; i< num_regs; i++) { - if (p[i].reg == reg) { - return p[i].live ? &p[i] : NULL; - } - } - p = reg_pool_->FPRegs; - num_regs = reg_pool_->num_fp_regs; - for (int i = 0; i< num_regs; i++) { - if (p[i].reg == reg) { - return p[i].live ? &p[i] : NULL; - } - } - return NULL; + RegisterInfo* p = GetRegInfo(reg); + return p->live ? p : NULL; } Mir2Lir::RegisterInfo* Mir2Lir::IsTemp(int reg) { @@ -476,27 +445,10 @@ bool Mir2Lir::IsDirty(int reg) { * allocated. Use with caution. */ void Mir2Lir::LockTemp(int reg) { - RegisterInfo* p = reg_pool_->core_regs; - int num_regs = reg_pool_->num_core_regs; - for (int i = 0; i< num_regs; i++) { - if (p[i].reg == reg) { - DCHECK(p[i].is_temp); - p[i].in_use = true; - p[i].live = false; - return; - } - } - p = reg_pool_->FPRegs; - num_regs = reg_pool_->num_fp_regs; - for (int i = 0; i< num_regs; i++) { - if (p[i].reg == reg) { - DCHECK(p[i].is_temp); - p[i].in_use = true; - p[i].live = false; - return; - } - } - LOG(FATAL) << "Tried to lock a non-existant temp: r" << reg; + RegisterInfo* p = GetRegInfo(reg); + DCHECK(p->is_temp); + p->in_use = true; + p->live = false; } void Mir2Lir::ResetDef(int reg) { @@ -599,11 +551,24 @@ void Mir2Lir::ResetDefTracking() { } void Mir2Lir::ClobberAllRegs() { - for (int i = 0; i< reg_pool_->num_core_regs; i++) { - ClobberBody(®_pool_->core_regs[i]); + RegisterInfo* p; + for (p = reg_pool_->core_regs; p < reg_pool_->core_regs + reg_pool_->num_core_regs; p++) { + if (p->is_temp) { + p->live = false; + p->s_reg = INVALID_SREG; + p->def_start = NULL; + p->def_end = NULL; + p->pair = false; + } } - for (int i = 0; i< reg_pool_->num_fp_regs; i++) { - ClobberBody(®_pool_->FPRegs[i]); + for (p = reg_pool_->FPRegs; p < reg_pool_->FPRegs + reg_pool_->num_fp_regs; p++) { + if (p->is_temp) { + p->live = false; + p->s_reg = INVALID_SREG; + p->def_start = NULL; + p->def_end = NULL; + p->pair = false; + } } } diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc index cd1602f674..366d7f26be 100644 --- a/compiler/dex/ssa_transformation.cc +++ b/compiler/dex/ssa_transformation.cc @@ -22,7 +22,7 @@ namespace art { void MIRGraph::ClearAllVisitedFlags() { - AllNodesIterator iter(this, false /* not iterative */); + AllNodesIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { bb->visited = false; } @@ -145,11 +145,11 @@ void MIRGraph::ComputeDefBlockMatrix() { def_block_matrix_[i] = new (arena_) ArenaBitVector(arena_, GetNumBlocks(), false, kBitMapBMatrix); } - AllNodesIterator iter(this, false /* not iterative */); + AllNodesIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { FindLocalLiveIn(bb); } - AllNodesIterator iter2(this, false /* not iterative */); + AllNodesIterator iter2(this); for (BasicBlock* bb = iter2.Next(); bb != NULL; bb = iter2.Next()) { FillDefBlockMatrix(bb); } @@ -377,7 +377,7 @@ void MIRGraph::ComputeDominators() { int num_total_blocks = GetBasicBlockListCount(); /* Initialize domination-related data structures */ - ReachableNodesIterator iter(this, false /* not iterative */); + PreOrderDfsIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { InitializeDominationInfo(bb); } @@ -396,7 +396,7 @@ void MIRGraph::ComputeDominators() { i_dom_list_[GetEntryBlock()->dfs_id] = GetEntryBlock()->dfs_id; /* Compute the immediate dominators */ - ReversePostOrderDfsIterator iter2(this, true /* iterative */); + RepeatingReversePostOrderDfsIterator iter2(this); bool change = false; for (BasicBlock* bb = iter2.Next(false); bb != NULL; bb = iter2.Next(change)) { change = ComputeblockIDom(bb); @@ -414,19 +414,19 @@ void MIRGraph::ComputeDominators() { } GetEntryBlock()->i_dom = NULL; - ReachableNodesIterator iter3(this, false /* not iterative */); + PreOrderDfsIterator iter3(this); for (BasicBlock* bb = iter3.Next(); bb != NULL; bb = iter3.Next()) { SetDominators(bb); } - ReversePostOrderDfsIterator iter4(this, false /* not iterative */); + ReversePostOrderDfsIterator iter4(this); for (BasicBlock* bb = iter4.Next(); bb != NULL; bb = iter4.Next()) { ComputeBlockDominators(bb); } // Compute the dominance frontier for each block. ComputeDomPostOrderTraversal(GetEntryBlock()); - PostOrderDOMIterator iter5(this, false /* not iterative */); + PostOrderDOMIterator iter5(this); for (BasicBlock* bb = iter5.Next(); bb != NULL; bb = iter5.Next()) { ComputeDominanceFrontier(bb); } @@ -503,7 +503,7 @@ void MIRGraph::InsertPhiNodes() { temp_dalvik_register_v_ = new (arena_) ArenaBitVector(arena_, cu_->num_dalvik_registers, false, kBitMapRegisterV); - PostOrderDfsIterator iter(this, true /* iterative */); + RepeatingPostOrderDfsIterator iter(this); bool change = false; for (BasicBlock* bb = iter.Next(false); bb != NULL; bb = iter.Next(change)) { change = ComputeBlockLiveIns(bb); @@ -700,7 +700,7 @@ void MIRGraph::SSATransformation() { new (arena_) ArenaBitVector(arena_, GetNumSSARegs(), false, kBitMapTempSSARegisterV); /* Insert phi-operands with latest SSA names from predecessor blocks */ - ReachableNodesIterator iter2(this, false /* not iterative */); + PreOrderDfsIterator iter2(this); for (BasicBlock* bb = iter2.Next(); bb != NULL; bb = iter2.Next()) { InsertPhiNodeOperands(bb); } diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc index 07f37bbbbb..25510684d1 100644 --- a/compiler/dex/vreg_analysis.cc +++ b/compiler/dex/vreg_analysis.cc @@ -444,7 +444,7 @@ void MIRGraph::BuildRegLocations() { } /* Do type & size inference pass */ - PreOrderDfsIterator iter(this, true /* iterative */); + RepeatingPreOrderDfsIterator iter(this); bool change = false; for (BasicBlock* bb = iter.Next(false); bb != NULL; bb = iter.Next(change)) { change = InferTypeAndSize(bb); -- cgit v1.2.3-59-g8ed1b From 28c2300d9a85f4e7288fb5d94280332f923b4df3 Mon Sep 17 00:00:00 2001 From: buzbee Date: Sat, 7 Sep 2013 09:12:27 -0700 Subject: More compile-time tuning Small, but measurable, improvement. Change-Id: Ie3c7180f9f9cbfb1729588e7a4b2cf6c6d291c95 --- compiler/dex/arena_bit_vector.cc | 6 -- compiler/dex/arena_bit_vector.h | 8 +- compiler/dex/mir_graph.h | 23 +++++ compiler/dex/quick/codegen_util.cc | 4 +- compiler/dex/vreg_analysis.cc | 199 +++++++++++++++++++++++-------------- 5 files changed, 155 insertions(+), 85 deletions(-) (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/arena_bit_vector.cc b/compiler/dex/arena_bit_vector.cc index 3fa9295276..b921f615b6 100644 --- a/compiler/dex/arena_bit_vector.cc +++ b/compiler/dex/arena_bit_vector.cc @@ -87,12 +87,6 @@ void ArenaBitVector::ClearBit(unsigned int num) { storage_[num >> 5] &= ~check_masks[num & 0x1f]; } -// Copy a whole vector to the other. Sizes must match. -void ArenaBitVector::Copy(ArenaBitVector* src) { - DCHECK_EQ(storage_size_, src->GetStorageSize()); - memcpy(storage_, src->GetRawStorage(), sizeof(uint32_t) * storage_size_); -} - // Intersect with another bit vector. Sizes and expandability must be the same. void ArenaBitVector::Intersect(const ArenaBitVector* src) { DCHECK_EQ(storage_size_, src->GetStorageSize()); diff --git a/compiler/dex/arena_bit_vector.h b/compiler/dex/arena_bit_vector.h index 8bcd628dc0..24a7ce9601 100644 --- a/compiler/dex/arena_bit_vector.h +++ b/compiler/dex/arena_bit_vector.h @@ -44,7 +44,7 @@ class ArenaBitVector { DCHECK_EQ(bit_size_, p_bits_->GetStorageSize() * sizeof(uint32_t) * 8); DCHECK_EQ(bit_storage_, p_bits_->GetRawStorage()); - if (bit_index_ >= bit_size_) return -1; + if (UNLIKELY(bit_index_ >= bit_size_)) return -1; uint32_t word_index = bit_index_ / 32; uint32_t word = bit_storage_[word_index]; @@ -54,7 +54,7 @@ class ArenaBitVector { bit_index_ &= ~0x1f; do { word_index++; - if ((word_index * 32) >= bit_size_) { + if (UNLIKELY((word_index * 32) >= bit_size_)) { bit_index_ = bit_size_; return -1; } @@ -95,7 +95,9 @@ class ArenaBitVector { bool IsBitSet(unsigned int num); void ClearAllBits(); void SetInitialBits(unsigned int num_bits); - void Copy(ArenaBitVector* src); + void Copy(ArenaBitVector* src) { + memcpy(storage_, src->GetRawStorage(), sizeof(uint32_t) * storage_size_); + } void Intersect(const ArenaBitVector* src2); void Union(const ArenaBitVector* src); // Are we equal to another bit vector? Note: expandability attributes must also match. diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 28ab2834e1..15e15c380f 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -580,11 +580,34 @@ class MIRGraph { void SSATransformation(); void CheckForDominanceFrontier(BasicBlock* dom_bb, const BasicBlock* succ_bb); void NullCheckElimination(); + /* + * Type inference handling helpers. Because Dalvik's bytecode is not fully typed, + * we have to do some work to figure out the sreg type. For some operations it is + * clear based on the opcode (i.e. ADD_FLOAT v0, v1, v2), but for others (MOVE), we + * may never know the "real" type. + * + * We perform the type inference operation by using an iterative walk over + * the graph, propagating types "defined" by typed opcodes to uses and defs in + * non-typed opcodes (such as MOVE). The Setxx(index) helpers are used to set defined + * types on typed opcodes (such as ADD_INT). The Setxx(index, is_xx) form is used to + * propagate types through non-typed opcodes such as PHI and MOVE. The is_xx flag + * tells whether our guess of the type is based on a previously typed definition. + * If so, the defined type takes precedence. Note that it's possible to have the same sreg + * show multiple defined types because dx treats constants as untyped bit patterns. + * The return value of the Setxx() helpers says whether or not the Setxx() action changed + * the current guess, and is used to know when to terminate the iterative walk. + */ bool SetFp(int index, bool is_fp); + bool SetFp(int index); bool SetCore(int index, bool is_core); + bool SetCore(int index); bool SetRef(int index, bool is_ref); + bool SetRef(int index); bool SetWide(int index, bool is_wide); + bool SetWide(int index); bool SetHigh(int index, bool is_high); + bool SetHigh(int index); + void AppendMIR(BasicBlock* bb, MIR* mir); void PrependMIR(BasicBlock* bb, MIR* mir); void InsertMIRAfter(BasicBlock* bb, MIR* current_mir, MIR* new_mir); diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 9e0159ecc0..e9db6a68d0 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -696,11 +696,11 @@ int Mir2Lir::AssignInsnOffsets() { for (lir = first_lir_insn_; lir != NULL; lir = NEXT_LIR(lir)) { lir->offset = offset; - if (lir->opcode >= 0) { + if (LIKELY(lir->opcode >= 0)) { if (!lir->flags.is_nop) { offset += lir->flags.size; } - } else if (lir->opcode == kPseudoPseudoAlign4) { + } else if (UNLIKELY(lir->opcode == kPseudoPseudoAlign4)) { if (offset & 0x2) { offset += 2; lir->operands[0] = 1; diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc index 25510684d1..32fac0b393 100644 --- a/compiler/dex/vreg_analysis.cc +++ b/compiler/dex/vreg_analysis.cc @@ -29,6 +29,16 @@ bool MIRGraph::SetFp(int index, bool is_fp) { return change; } +bool MIRGraph::SetFp(int index) { + bool change = false; + if (!reg_location_[index].fp) { + reg_location_[index].fp = true; + reg_location_[index].defined = true; + change = true; + } + return change; +} + bool MIRGraph::SetCore(int index, bool is_core) { bool change = false; if (is_core && !reg_location_[index].defined) { @@ -39,6 +49,16 @@ bool MIRGraph::SetCore(int index, bool is_core) { return change; } +bool MIRGraph::SetCore(int index) { + bool change = false; + if (!reg_location_[index].defined) { + reg_location_[index].core = true; + reg_location_[index].defined = true; + change = true; + } + return change; +} + bool MIRGraph::SetRef(int index, bool is_ref) { bool change = false; if (is_ref && !reg_location_[index].defined) { @@ -49,6 +69,16 @@ bool MIRGraph::SetRef(int index, bool is_ref) { return change; } +bool MIRGraph::SetRef(int index) { + bool change = false; + if (!reg_location_[index].defined) { + reg_location_[index].ref = true; + reg_location_[index].defined = true; + change = true; + } + return change; +} + bool MIRGraph::SetWide(int index, bool is_wide) { bool change = false; if (is_wide && !reg_location_[index].wide) { @@ -58,6 +88,15 @@ bool MIRGraph::SetWide(int index, bool is_wide) { return change; } +bool MIRGraph::SetWide(int index) { + bool change = false; + if (!reg_location_[index].wide) { + reg_location_[index].wide = true; + change = true; + } + return change; +} + bool MIRGraph::SetHigh(int index, bool is_high) { bool change = false; if (is_high && !reg_location_[index].high_word) { @@ -67,6 +106,16 @@ bool MIRGraph::SetHigh(int index, bool is_high) { return change; } +bool MIRGraph::SetHigh(int index) { + bool change = false; + if (!reg_location_[index].high_word) { + reg_location_[index].high_word = true; + change = true; + } + return change; +} + + /* * Infer types and sizes. We don't need to track change on sizes, * as it doesn't propagate. We're guaranteed at least one pass through @@ -84,21 +133,23 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb) { SSARepresentation *ssa_rep = mir->ssa_rep; if (ssa_rep) { int attrs = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; + const int* uses = ssa_rep->uses; + const int* defs = ssa_rep->defs; // Handle defs if (attrs & DF_DA) { if (attrs & DF_CORE_A) { - changed |= SetCore(ssa_rep->defs[0], true); + changed |= SetCore(defs[0]); } if (attrs & DF_REF_A) { - changed |= SetRef(ssa_rep->defs[0], true); + changed |= SetRef(defs[0]); } if (attrs & DF_A_WIDE) { - reg_location_[ssa_rep->defs[0]].wide = true; - reg_location_[ssa_rep->defs[1]].wide = true; - reg_location_[ssa_rep->defs[1]].high_word = true; - DCHECK_EQ(SRegToVReg(ssa_rep->defs[0])+1, - SRegToVReg(ssa_rep->defs[1])); + reg_location_[defs[0]].wide = true; + reg_location_[defs[1]].wide = true; + reg_location_[defs[1]].high_word = true; + DCHECK_EQ(SRegToVReg(defs[0])+1, + SRegToVReg(defs[1])); } } @@ -106,17 +157,17 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb) { int next = 0; if (attrs & DF_UA) { if (attrs & DF_CORE_A) { - changed |= SetCore(ssa_rep->uses[next], true); + changed |= SetCore(uses[next]); } if (attrs & DF_REF_A) { - changed |= SetRef(ssa_rep->uses[next], true); + changed |= SetRef(uses[next]); } if (attrs & DF_A_WIDE) { - reg_location_[ssa_rep->uses[next]].wide = true; - reg_location_[ssa_rep->uses[next + 1]].wide = true; - reg_location_[ssa_rep->uses[next + 1]].high_word = true; - DCHECK_EQ(SRegToVReg(ssa_rep->uses[next])+1, - SRegToVReg(ssa_rep->uses[next + 1])); + reg_location_[uses[next]].wide = true; + reg_location_[uses[next + 1]].wide = true; + reg_location_[uses[next + 1]].high_word = true; + DCHECK_EQ(SRegToVReg(uses[next])+1, + SRegToVReg(uses[next + 1])); next += 2; } else { next++; @@ -124,17 +175,17 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb) { } if (attrs & DF_UB) { if (attrs & DF_CORE_B) { - changed |= SetCore(ssa_rep->uses[next], true); + changed |= SetCore(uses[next]); } if (attrs & DF_REF_B) { - changed |= SetRef(ssa_rep->uses[next], true); + changed |= SetRef(uses[next]); } if (attrs & DF_B_WIDE) { - reg_location_[ssa_rep->uses[next]].wide = true; - reg_location_[ssa_rep->uses[next + 1]].wide = true; - reg_location_[ssa_rep->uses[next + 1]].high_word = true; - DCHECK_EQ(SRegToVReg(ssa_rep->uses[next])+1, - SRegToVReg(ssa_rep->uses[next + 1])); + reg_location_[uses[next]].wide = true; + reg_location_[uses[next + 1]].wide = true; + reg_location_[uses[next + 1]].high_word = true; + DCHECK_EQ(SRegToVReg(uses[next])+1, + SRegToVReg(uses[next + 1])); next += 2; } else { next++; @@ -142,17 +193,17 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb) { } if (attrs & DF_UC) { if (attrs & DF_CORE_C) { - changed |= SetCore(ssa_rep->uses[next], true); + changed |= SetCore(uses[next]); } if (attrs & DF_REF_C) { - changed |= SetRef(ssa_rep->uses[next], true); + changed |= SetRef(uses[next]); } if (attrs & DF_C_WIDE) { - reg_location_[ssa_rep->uses[next]].wide = true; - reg_location_[ssa_rep->uses[next + 1]].wide = true; - reg_location_[ssa_rep->uses[next + 1]].high_word = true; - DCHECK_EQ(SRegToVReg(ssa_rep->uses[next])+1, - SRegToVReg(ssa_rep->uses[next + 1])); + reg_location_[uses[next]].wide = true; + reg_location_[uses[next + 1]].wide = true; + reg_location_[uses[next + 1]].high_word = true; + DCHECK_EQ(SRegToVReg(uses[next])+1, + SRegToVReg(uses[next + 1])); } } @@ -162,27 +213,27 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb) { (mir->dalvikInsn.opcode == Instruction::RETURN_OBJECT)) { switch (cu_->shorty[0]) { case 'I': - changed |= SetCore(ssa_rep->uses[0], true); + changed |= SetCore(uses[0]); break; case 'J': - changed |= SetCore(ssa_rep->uses[0], true); - changed |= SetCore(ssa_rep->uses[1], true); - reg_location_[ssa_rep->uses[0]].wide = true; - reg_location_[ssa_rep->uses[1]].wide = true; - reg_location_[ssa_rep->uses[1]].high_word = true; + changed |= SetCore(uses[0]); + changed |= SetCore(uses[1]); + reg_location_[uses[0]].wide = true; + reg_location_[uses[1]].wide = true; + reg_location_[uses[1]].high_word = true; break; case 'F': - changed |= SetFp(ssa_rep->uses[0], true); + changed |= SetFp(uses[0]); break; case 'D': - changed |= SetFp(ssa_rep->uses[0], true); - changed |= SetFp(ssa_rep->uses[1], true); - reg_location_[ssa_rep->uses[0]].wide = true; - reg_location_[ssa_rep->uses[1]].wide = true; - reg_location_[ssa_rep->uses[1]].high_word = true; + changed |= SetFp(uses[0]); + changed |= SetFp(uses[1]); + reg_location_[uses[0]].wide = true; + reg_location_[uses[1]].wide = true; + reg_location_[uses[1]].high_word = true; break; case 'L': - changed |= SetRef(ssa_rep->uses[0], true); + changed |= SetRef(uses[0]); break; default: break; } @@ -206,10 +257,10 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb) { SSARepresentation* tgt_rep = move_result_mir->ssa_rep; DCHECK(tgt_rep != NULL); tgt_rep->fp_def[0] = true; - changed |= SetFp(tgt_rep->defs[0], true); + changed |= SetFp(tgt_rep->defs[0]); if (shorty[0] == 'D') { tgt_rep->fp_def[1] = true; - changed |= SetFp(tgt_rep->defs[1], true); + changed |= SetFp(tgt_rep->defs[1]); } } } @@ -217,8 +268,8 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb) { // If this is a non-static invoke, mark implicit "this" if (((mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC) && (mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC_RANGE))) { - reg_location_[ssa_rep->uses[next]].defined = true; - reg_location_[ssa_rep->uses[next]].ref = true; + reg_location_[uses[next]].defined = true; + reg_location_[uses[next]].ref = true; next++; } uint32_t cpos = 1; @@ -229,28 +280,28 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb) { case 'D': ssa_rep->fp_use[i] = true; ssa_rep->fp_use[i+1] = true; - reg_location_[ssa_rep->uses[i]].wide = true; - reg_location_[ssa_rep->uses[i+1]].wide = true; - reg_location_[ssa_rep->uses[i+1]].high_word = true; - DCHECK_EQ(SRegToVReg(ssa_rep->uses[i])+1, SRegToVReg(ssa_rep->uses[i+1])); + reg_location_[uses[i]].wide = true; + reg_location_[uses[i+1]].wide = true; + reg_location_[uses[i+1]].high_word = true; + DCHECK_EQ(SRegToVReg(uses[i])+1, SRegToVReg(uses[i+1])); i++; break; case 'J': - reg_location_[ssa_rep->uses[i]].wide = true; - reg_location_[ssa_rep->uses[i+1]].wide = true; - reg_location_[ssa_rep->uses[i+1]].high_word = true; - DCHECK_EQ(SRegToVReg(ssa_rep->uses[i])+1, SRegToVReg(ssa_rep->uses[i+1])); - changed |= SetCore(ssa_rep->uses[i], true); + reg_location_[uses[i]].wide = true; + reg_location_[uses[i+1]].wide = true; + reg_location_[uses[i+1]].high_word = true; + DCHECK_EQ(SRegToVReg(uses[i])+1, SRegToVReg(uses[i+1])); + changed |= SetCore(uses[i]); i++; break; case 'F': ssa_rep->fp_use[i] = true; break; case 'L': - changed |= SetRef(ssa_rep->uses[i], true); + changed |= SetRef(uses[i]); break; default: - changed |= SetCore(ssa_rep->uses[i], true); + changed |= SetCore(uses[i]); break; } i++; @@ -260,11 +311,11 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb) { for (int i = 0; ssa_rep->fp_use && i< ssa_rep->num_uses; i++) { if (ssa_rep->fp_use[i]) - changed |= SetFp(ssa_rep->uses[i], true); + changed |= SetFp(uses[i]); } for (int i = 0; ssa_rep->fp_def && i< ssa_rep->num_defs; i++) { if (ssa_rep->fp_def[i]) - changed |= SetFp(ssa_rep->defs[i], true); + changed |= SetFp(defs[i]); } // Special-case handling for moves & Phi if (attrs & (DF_IS_MOVE | DF_NULL_TRANSFER_N)) { @@ -276,14 +327,14 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb) { */ bool is_phi = (static_cast(mir->dalvikInsn.opcode) == kMirOpPhi); - RegLocation rl_temp = reg_location_[ssa_rep->defs[0]]; + RegLocation rl_temp = reg_location_[defs[0]]; bool defined_fp = rl_temp.defined && rl_temp.fp; bool defined_core = rl_temp.defined && rl_temp.core; bool defined_ref = rl_temp.defined && rl_temp.ref; bool is_wide = rl_temp.wide || ((attrs & DF_A_WIDE) != 0); bool is_high = is_phi && rl_temp.wide && rl_temp.high_word; for (int i = 0; i < ssa_rep->num_uses; i++) { - rl_temp = reg_location_[ssa_rep->uses[i]]; + rl_temp = reg_location_[uses[i]]; defined_fp |= rl_temp.defined && rl_temp.fp; defined_core |= rl_temp.defined && rl_temp.core; defined_ref |= rl_temp.defined && rl_temp.ref; @@ -303,26 +354,26 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb) { << " has both fp and core/ref uses for same def."; cu_->disable_opt |= (1 << kPromoteRegs); } - changed |= SetFp(ssa_rep->defs[0], defined_fp); - changed |= SetCore(ssa_rep->defs[0], defined_core); - changed |= SetRef(ssa_rep->defs[0], defined_ref); - changed |= SetWide(ssa_rep->defs[0], is_wide); - changed |= SetHigh(ssa_rep->defs[0], is_high); + changed |= SetFp(defs[0], defined_fp); + changed |= SetCore(defs[0], defined_core); + changed |= SetRef(defs[0], defined_ref); + changed |= SetWide(defs[0], is_wide); + changed |= SetHigh(defs[0], is_high); if (attrs & DF_A_WIDE) { - changed |= SetWide(ssa_rep->defs[1], true); - changed |= SetHigh(ssa_rep->defs[1], true); + changed |= SetWide(defs[1]); + changed |= SetHigh(defs[1]); } for (int i = 0; i < ssa_rep->num_uses; i++) { - changed |= SetFp(ssa_rep->uses[i], defined_fp); - changed |= SetCore(ssa_rep->uses[i], defined_core); - changed |= SetRef(ssa_rep->uses[i], defined_ref); - changed |= SetWide(ssa_rep->uses[i], is_wide); - changed |= SetHigh(ssa_rep->uses[i], is_high); + changed |= SetFp(uses[i], defined_fp); + changed |= SetCore(uses[i], defined_core); + changed |= SetRef(uses[i], defined_ref); + changed |= SetWide(uses[i], is_wide); + changed |= SetHigh(uses[i], is_high); } if (attrs & DF_A_WIDE) { DCHECK_EQ(ssa_rep->num_uses, 2); - changed |= SetWide(ssa_rep->uses[1], true); - changed |= SetHigh(ssa_rep->uses[1], true); + changed |= SetWide(uses[1]); + changed |= SetHigh(uses[1]); } } } -- cgit v1.2.3-59-g8ed1b From 252254b130067cd7a5071865e793966871ae0246 Mon Sep 17 00:00:00 2001 From: buzbee Date: Sun, 8 Sep 2013 16:20:53 -0700 Subject: More Quick compile-time tuning: labels & branches This CL represents a roughly 3.5% performance improvement for the compile phase of dex2oat. Move of the gain comes from avoiding the generation of dex boundary LIR labels unless a debug listing is requested. The other significant change is moving from a basic block ending branch model of "always generate a fall-through branch, and then delete it if we can" to a "only generate a fall-through branch if we need it" model. The data motivating these changes follow. Note that two area of potentially attractive gain remain: restructing the assembler model and reworking the register handling utilities. These will be addressed in subsequent CLs. --- data follows The Quick compiler's assembler has shown up on profile reports a bit more than seems reasonable. We've tried a few quick fixes to apparently hot portions of the code, but without much gain. So, I've been looking at the assembly process at a somewhat higher level. There look to be several potentially good opportunities. First, an analysis of the makeup of the LIR graph showed a surprisingly high proportion of LIR pseudo ops. Using the boot classpath as a basis, we get: 32.8% of all LIR nodes are pseudo ops. 10.4% are LIR instructions which require pc-relative fixups. 11.8% are LIR instructions that have been nop'd by the various optimization passes. Looking only at the LIR pseudo ops, we get: kPseudoDalvikByteCodeBoundary 43.46% kPseudoNormalBlockLabel 21.14% kPseudoSafepointPC 20.20% kPseudoThrowTarget 6.94% kPseudoTarget 3.03% kPseudoSuspendTarget 1.95% kPseudoMethodExit 1.26% kPseudoMethodEntry 1.26% kPseudoExportedPC 0.37% kPseudoCaseLabel 0.30% kPseudoBarrier 0.07% kPseudoIntrinsicRetry 0.02% Total LIR count: 10167292 The standout here is the Dalvik opcode boundary marker. This is just a label inserted at the beginning of the codegen for each Dalvik bytecode. If we're also doing a verbose listing, this is also where we hang the pretty-print disassembly string. However, this label was also being used as a convenient way to find the target of switch case statements (and, I think at one point was used in the Mir->GBC conversion process). This CL moves the use of kPseudoDalvikByteCodeBoundary labels to only verbose listing runs, and replaces the codegen uses of the label with the kPseudoNormalBlockLabel attached to the basic block that contains the switch case target. Great savings here - 14.3% reduction in the number of LIR nodes needed. After this CL, our LIR pseudo proportions drop to 21.6% of all LIR. That's still a lot, but much better. Possible further improvements via combining normal labels with kPseudoSafepointPC labels where appropriate, and also perhaps reduce memory usage by using a short-hand form for labels rather than a full LIR node. Also, many of the basic block labels are no longer branch targets by the time we get to assembly - cheaper to delete, or just ingore? Here's the "after" LIR pseudo op breakdown: kPseudoNormalBlockLabel 37.39% kPseudoSafepointPC 35.72% kPseudoThrowTarget 12.28% kPseudoTarget 5.36% kPseudoSuspendTarget 3.45% kPseudoMethodEntry 2.24% kPseudoMethodExit 2.22% kPseudoExportedPC 0.65% kPseudoCaseLabel 0.53% kPseudoBarrier 0.12% kPseudoIntrinsicRetry 0.04% Total LIR count: 5748232 Not done in this CL, but it will be worth experimenting with actually deleting LIR nodes from the graph when they are optimized away, rather than just setting the NOP bit. Keeping them around is invaluable during debugging - but when not debugging it may pay off if the cost of node removal is less than the cost of traversing through dead nodes in subsequent passes. Next up (and partially in this CL - but mostly to be done in follow-on CLs) is the overall assembly process. Inherited from the trace JIT, the Quick compiler has a fairly simple-minded approach to instruction assembly. First, a pass is made over the LIR list to assign offsets to each instruction. Then, the assembly pass is made - which generates the actual machine instruction bit patterns and pushes the instruction data into the code_buffer. However, the code generator takes the "always optimistic" approach to instruction selection and emits the shortest instruction. If, during assembly, we find that a branch or load doesn't reach, that short-form instruction is replaces with a longer sequence. Of course, this invalidates the previously-computed offset calculations. Assembly thus is an iterative process: compute offsets and then assemble until we survive an assembly pass without invalidation. This seems like a likely candidate for improvement. First, I analyzed the number of retries required, and the reason for invalidation over the boot classpath load. The results: more than half of methods don't require a retry, and very few require more than 1 extra pass: 5 or more: 6 of 96334 4 or more: 22 of 96334 3 or more: 140 of 96334 2 or more: 1794 of 96334 - 2% 1 or more: 40911 of 96334 - 40% 0 retries: 55423 of 96334 - 58% The interesting group here is the one that requires 1 retry. Looking at the reason, we see three typical reasons: 1. A cbnz/cbz doesn't reach (only 7 bits of offset) 2. A 16-bit Thumb1 unconditional branch doesn't reach. 3. An unconditional branch which branches to the next instruction is encountered, and deleted. The first 2 cases are the cost of the optimistic strategy - nothing much to change there. However, the interesting case is #3 - dead branch elimination. A further analysis of the single retry group showed that 42% of the methods (16305) that required a single retry did so *only* because of dead branch elimination. The big question here is why so many dead branches survive to the assembly stage. We have a dead branch elimination pass which is supposed to catch these - perhaps it's not working correctly, should be moved later in the optimization process, or perhaps run multiple times. Other things to consider: o Combine the offset generation pass with the assembly pass. Skip pc-relative fixup assembly (other than assigning offset), but push LIR* for them into work list. Following the main pass, zip through the work list and assemble the pc-relative instructions (now that we know the offsets). This would significantly cut back on traversal costs. o Store the assembled bits into both the code buffer and the LIR. In the event we have to retry, only the pc-relative instructions would need to be assembled, and we'd finish with a pass over the LIR just to dumb the bits into the code buffer. Change-Id: I50029d216fa14f273f02b6f1c8b6a0dde5a7d6a6 --- compiler/dex/growable_array.h | 5 --- compiler/dex/quick/arm/assemble_arm.cc | 4 +-- compiler/dex/quick/arm/call_arm.cc | 7 ++-- compiler/dex/quick/arm/int_arm.cc | 16 ++++++--- compiler/dex/quick/codegen_util.cc | 54 +++++++++++++++++-------------- compiler/dex/quick/gen_common.cc | 3 -- compiler/dex/quick/local_optimizations.cc | 47 +++------------------------ compiler/dex/quick/mips/assemble_mips.cc | 4 +-- compiler/dex/quick/mir_to_lir.cc | 35 ++++++++++---------- compiler/dex/quick/mir_to_lir.h | 5 ++- compiler/dex/quick/x86/assemble_x86.cc | 2 +- 11 files changed, 75 insertions(+), 107 deletions(-) (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/growable_array.h b/compiler/dex/growable_array.h index 9053285af0..8e2abfbaf1 100644 --- a/compiler/dex/growable_array.h +++ b/compiler/dex/growable_array.h @@ -150,11 +150,6 @@ class GrowableArray { size_t Size() const { return num_used_; } - void SetSize(size_t new_size) { - Resize(new_size); - num_used_ = new_size; - } - T* GetRawStorage() const { return elem_list_; } static void* operator new(size_t size, ArenaAllocator* arena) { diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc index 0649c9f319..8ba56dfa0e 100644 --- a/compiler/dex/quick/arm/assemble_arm.cc +++ b/compiler/dex/quick/arm/assemble_arm.cc @@ -1170,7 +1170,7 @@ AssemblerStatus ArmMir2Lir::AssembleInstructions(uintptr_t start_addr) { lir->operands[0] = delta >> 1; if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && lir->operands[0] == 0) { // Useless branch - lir->flags.is_nop = true; + NopLIR(lir); res = kRetryAll; } } else if (lir->opcode == kThumbBUncond) { @@ -1188,7 +1188,7 @@ AssemblerStatus ArmMir2Lir::AssembleInstructions(uintptr_t start_addr) { lir->operands[0] = delta >> 1; if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && lir->operands[0] == -1) { // Useless branch - lir->flags.is_nop = true; + NopLIR(lir); res = kRetryAll; } } diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index e0e198a50d..bba2ec5c4e 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -120,9 +120,10 @@ MIR* ArmMir2Lir::GetNextMir(BasicBlock** p_bb, MIR* mir) { // TODO: move to common code void ArmMir2Lir::GenPrintLabel(MIR* mir) { /* Mark the beginning of a Dalvik instruction for line tracking */ - char* inst_str = cu_->verbose ? - mir_graph_->GetDalvikDisassembly(mir) : NULL; - MarkBoundary(mir->offset, inst_str); + if (cu_->verbose) { + char* inst_str = mir_graph_->GetDalvikDisassembly(mir); + MarkBoundary(mir->offset, inst_str); + } } MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir, diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index f2ff58ee0a..bd659e6c2b 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -234,11 +234,17 @@ void ArmMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { rl_false = LoadValue(rl_false, kCoreReg); rl_result = EvalLoc(rl_dest, kCoreReg, true); OpRegImm(kOpCmp, rl_src.low_reg, 0); - OpIT(kCondEq, "E"); - LIR* l1 = OpRegCopy(rl_result.low_reg, rl_true.low_reg); - l1->flags.is_nop = false; // Make sure this instruction isn't optimized away - LIR* l2 = OpRegCopy(rl_result.low_reg, rl_false.low_reg); - l2->flags.is_nop = false; // Make sure this instruction isn't optimized away + if (rl_result.low_reg == rl_true.low_reg) { // Is the "true" case already in place? + OpIT(kCondNe, ""); + OpRegCopy(rl_result.low_reg, rl_false.low_reg); + } else if (rl_result.low_reg == rl_false.low_reg) { // False case in place? + OpIT(kCondEq, ""); + OpRegCopy(rl_result.low_reg, rl_true.low_reg); + } else { // Normal - select between the two. + OpIT(kCondEq, "E"); + OpRegCopy(rl_result.low_reg, rl_true.low_reg); + OpRegCopy(rl_result.low_reg, rl_false.low_reg); + } GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact } StoreValue(rl_dest, rl_result); diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index e9db6a68d0..3aa2f647c2 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -55,9 +55,32 @@ bool Mir2Lir::FastInstance(uint32_t field_idx, bool is_put, int* field_offset, b field_idx, mir_graph_->GetCurrentDexCompilationUnit(), is_put, field_offset, is_volatile); } +/* Remove a LIR from the list. */ +void Mir2Lir::UnlinkLIR(LIR* lir) { + if (UNLIKELY(lir == first_lir_insn_)) { + first_lir_insn_ = lir->next; + if (lir->next != NULL) { + lir->next->prev = NULL; + } else { + DCHECK(lir->next == NULL); + DCHECK(lir == last_lir_insn_); + last_lir_insn_ = NULL; + } + } else if (lir == last_lir_insn_) { + last_lir_insn_ = lir->prev; + lir->prev->next = NULL; + } else if ((lir->prev != NULL) && (lir->next != NULL)) { + lir->prev->next = lir->next; + lir->next->prev = lir->prev; + } +} + /* Convert an instruction to a NOP */ void Mir2Lir::NopLIR(LIR* lir) { lir->flags.is_nop = true; + if (!cu_->verbose) { + UnlinkLIR(lir); + } } void Mir2Lir::SetMemRefType(LIR* lir, bool is_load, int mem_type) { @@ -782,20 +805,16 @@ void Mir2Lir::AssembleLIR() { /* * Insert a kPseudoCaseLabel at the beginning of the Dalvik * offset vaddr. This label will be used to fix up the case - * branch table during the assembly phase. Be sure to set - * all resource flags on this to prevent code motion across - * target boundaries. KeyVal is just there for debugging. + * branch table during the assembly phase. All resource flags + * are set to prevent code motion. KeyVal is just there for debugging. */ LIR* Mir2Lir::InsertCaseLabel(int vaddr, int keyVal) { - SafeMap::iterator it; - LIR* boundary_lir = boundary_map_.Get(vaddr); - if (boundary_lir == NULL) { - LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr; - } + LIR* boundary_lir = &block_label_list_[mir_graph_->FindBlock(vaddr)->id]; LIR* new_label = static_cast(arena_->Alloc(sizeof(LIR), ArenaAllocator::kAllocLIR)); new_label->dalvik_offset = vaddr; new_label->opcode = kPseudoCaseLabel; new_label->operands[0] = keyVal; + new_label->def_mask = ENCODE_ALL; InsertLIRAfter(boundary_lir, new_label); return new_label; } @@ -880,18 +899,9 @@ void Mir2Lir::DumpPackedSwitchTable(const uint16_t* table) { } } -/* - * Set up special LIR to mark a Dalvik byte-code instruction start and - * record it in the boundary_map. NOTE: in cases such as kMirOpCheck in - * which we split a single Dalvik instruction, only the first MIR op - * associated with a Dalvik PC should be entered into the map. - */ -LIR* Mir2Lir::MarkBoundary(int offset, const char* inst_str) { - LIR* res = NewLIR1(kPseudoDalvikByteCodeBoundary, reinterpret_cast(inst_str)); - if (boundary_map_.Get(offset) == NULL) { - boundary_map_.Put(offset, res); - } - return res; +/* Set up special LIR to mark a Dalvik byte-code instruction start for pretty printing */ +void Mir2Lir::MarkBoundary(int offset, const char* inst_str) { + NewLIR1(kPseudoDalvikByteCodeBoundary, reinterpret_cast(inst_str)); } bool Mir2Lir::EvaluateBranch(Instruction::Code opcode, int32_t src1, int32_t src2) { @@ -946,7 +956,6 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena throw_launchpads_(arena, 2048, kGrowableArrayThrowLaunchPads), suspend_launchpads_(arena, 4, kGrowableArraySuspendLaunchPads), intrinsic_launchpads_(arena, 2048, kGrowableArrayMisc), - boundary_map_(arena, 0, kGrowableArrayMisc), data_offset_(0), total_size_(0), block_label_list_(NULL), @@ -963,8 +972,6 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena promotion_map_ = static_cast (arena_->Alloc((cu_->num_dalvik_registers + cu_->num_compiler_temps + 1) * sizeof(promotion_map_[0]), ArenaAllocator::kAllocRegAlloc)); - // Pre-fill with nulls. - boundary_map_.SetSize(cu->code_item->insns_size_in_code_units_); } void Mir2Lir::Materialize() { @@ -1091,5 +1098,4 @@ void Mir2Lir::InsertLIRAfter(LIR* current_lir, LIR* new_lir) { new_lir->next->prev = new_lir; } - } // namespace art diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index aa45d98cf6..4dd55d763a 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -127,13 +127,11 @@ void Mir2Lir::GenCompareAndBranch(Instruction::Code opcode, RegLocation rl_src1, InexpensiveConstantInt(mir_graph_->ConstantValue(rl_src2))) { // OK - convert this to a compare immediate and branch OpCmpImmBranch(cond, rl_src1.low_reg, mir_graph_->ConstantValue(rl_src2), taken); - OpUnconditionalBranch(fall_through); return; } } rl_src2 = LoadValue(rl_src2, kCoreReg); OpCmpBranch(cond, rl_src1.low_reg, rl_src2.low_reg, taken); - OpUnconditionalBranch(fall_through); } void Mir2Lir::GenCompareZeroAndBranch(Instruction::Code opcode, RegLocation rl_src, LIR* taken, @@ -164,7 +162,6 @@ void Mir2Lir::GenCompareZeroAndBranch(Instruction::Code opcode, RegLocation rl_s LOG(FATAL) << "Unexpected opcode " << opcode; } OpCmpImmBranch(cond, rl_src.low_reg, 0, taken); - OpUnconditionalBranch(fall_through); } void Mir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src) { diff --git a/compiler/dex/quick/local_optimizations.cc b/compiler/dex/quick/local_optimizations.cc index 41adb946a2..cb7694de68 100644 --- a/compiler/dex/quick/local_optimizations.cc +++ b/compiler/dex/quick/local_optimizations.cc @@ -168,7 +168,7 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { if (check_lir->operands[0] != native_reg_id) { ConvertMemOpIntoMove(check_lir, check_lir->operands[0], native_reg_id); } - check_lir->flags.is_nop = true; + NopLIR(check_lir); } } else if (alias_condition == ENCODE_DALVIK_REG) { /* Must alias */ @@ -187,7 +187,7 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { native_reg_id) { ConvertMemOpIntoMove(check_lir, check_lir->operands[0], native_reg_id); } - check_lir->flags.is_nop = true; + NopLIR(check_lir); } else { /* * Destinaions are of different types - @@ -201,7 +201,7 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { stop_here = true; } else if (!is_this_lir_load && !is_check_lir_load) { /* WAW - nuke the earlier store */ - this_lir->flags.is_nop = true; + NopLIR(this_lir); stop_here = true; } /* Partial overlap */ @@ -256,7 +256,7 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { * top-down order. */ InsertLIRBefore(check_lir, new_store_lir); - this_lir->flags.is_nop = true; + NopLIR(this_lir); } break; } else if (!check_lir->flags.is_nop) { @@ -452,7 +452,7 @@ void Mir2Lir::ApplyLoadHoisting(LIR* head_lir, LIR* tail_lir) { * is never the first LIR on the list */ InsertLIRBefore(cur_lir, new_load_lir); - this_lir->flags.is_nop = true; + NopLIR(this_lir); } } } @@ -467,41 +467,4 @@ void Mir2Lir::ApplyLocalOptimizations(LIR* head_lir, LIR* tail_lir) { } } -/* - * Nop any unconditional branches that go to the next instruction. - * Note: new redundant branches may be inserted later, and we'll - * use a check in final instruction assembly to nop those out. - */ -void Mir2Lir::RemoveRedundantBranches() { - LIR* this_lir; - - for (this_lir = first_lir_insn_; this_lir != last_lir_insn_; this_lir = NEXT_LIR(this_lir)) { - /* Branch to the next instruction */ - if (IsUnconditionalBranch(this_lir)) { - LIR* next_lir = this_lir; - - while (true) { - next_lir = NEXT_LIR(next_lir); - - /* - * Is the branch target the next instruction? - */ - if (next_lir == this_lir->target) { - this_lir->flags.is_nop = true; - break; - } - - /* - * Found real useful stuff between the branch and the target. - * Need to explicitly check the last_lir_insn_ here because it - * might be the last real instruction. - */ - if (!is_pseudo_opcode(next_lir->opcode) || - (next_lir == last_lir_insn_)) - break; - } - } - } -} - } // namespace art diff --git a/compiler/dex/quick/mips/assemble_mips.cc b/compiler/dex/quick/mips/assemble_mips.cc index cd25232c21..dbd668b330 100644 --- a/compiler/dex/quick/mips/assemble_mips.cc +++ b/compiler/dex/quick/mips/assemble_mips.cc @@ -503,7 +503,7 @@ void MipsMir2Lir::ConvertShortToLongBranch(LIR* lir) { if (!unconditional) { InsertLIRBefore(lir, hop_target); } - lir->flags.is_nop = true; + NopLIR(lir); } /* @@ -561,7 +561,7 @@ AssemblerStatus MipsMir2Lir::AssembleInstructions(uintptr_t start_addr) { RawLIR(lir->dalvik_offset, kMipsAddu, lir->operands[0], lir->operands[0], r_RA); InsertLIRBefore(lir, new_addu); - lir->flags.is_nop = true; + NopLIR(lir); res = kRetryAll; } } else if (lir->opcode == kMipsDeltaLo) { diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc index 7c79f59853..e1ac1365f0 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -735,16 +735,16 @@ bool Mir2Lir::MethodBlockCodeGen(BasicBlock* bb) { current_dalvik_offset_ = mir->offset; int opcode = mir->dalvikInsn.opcode; - LIR* boundary_lir; // Mark the beginning of a Dalvik instruction for line tracking. - char* inst_str = cu_->verbose ? - mir_graph_->GetDalvikDisassembly(mir) : NULL; - boundary_lir = MarkBoundary(mir->offset, inst_str); + if (cu_->verbose) { + char* inst_str = mir_graph_->GetDalvikDisassembly(mir); + MarkBoundary(mir->offset, inst_str); + } // Remember the first LIR for this block. if (head_lir == NULL) { - head_lir = boundary_lir; - // Set the first boundary_lir as a scheduling barrier. + head_lir = &block_label_list_[bb->id]; + // Set the first label as a scheduling barrier. head_lir->def_mask = ENCODE_ALL; } @@ -770,11 +770,6 @@ bool Mir2Lir::MethodBlockCodeGen(BasicBlock* bb) { if (head_lir) { // Eliminate redundant loads/stores and delay stores into later slots. ApplyLocalOptimizations(head_lir, last_lir_insn_); - - // Generate an unconditional branch to the fallthrough block. - if (bb->fall_through) { - OpUnconditionalBranch(&block_label_list_[bb->fall_through->id]); - } } return false; } @@ -815,8 +810,18 @@ void Mir2Lir::MethodMIR2LIR() { ArenaAllocator::kAllocLIR)); PreOrderDfsIterator iter(mir_graph_); - for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { - MethodBlockCodeGen(bb); + BasicBlock* curr_bb = iter.Next(); + BasicBlock* next_bb = iter.Next(); + while (curr_bb != NULL) { + MethodBlockCodeGen(curr_bb); + // If the fall_through block is no longer laid out consecutively, drop in a branch. + if ((curr_bb->fall_through != NULL) && (curr_bb->fall_through != next_bb)) { + OpUnconditionalBranch(&block_label_list_[curr_bb->fall_through->id]); + } + curr_bb = next_bb; + do { + next_bb = iter.Next(); + } while ((next_bb != NULL) && (next_bb->block_type == kDead)); } HandleSuspendLaunchPads(); @@ -824,10 +829,6 @@ void Mir2Lir::MethodMIR2LIR() { HandleThrowLaunchPads(); HandleIntrinsicLaunchPads(); - - if (!(cu_->disable_opt & (1 << kSafeOptimizations))) { - RemoveRedundantBranches(); - } } } // namespace art diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 981bbe6e7d..5b4813416b 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -274,8 +274,9 @@ class Mir2Lir : public Backend { void ProcessSwitchTables(); void DumpSparseSwitchTable(const uint16_t* table); void DumpPackedSwitchTable(const uint16_t* table); - LIR* MarkBoundary(int offset, const char* inst_str); + void MarkBoundary(int offset, const char* inst_str); void NopLIR(LIR* lir); + void UnlinkLIR(LIR* lir); bool EvaluateBranch(Instruction::Code opcode, int src1, int src2); bool IsInexpensiveConstant(RegLocation rl_src); ConditionCode FlipComparisonOrder(ConditionCode before); @@ -302,7 +303,6 @@ class Mir2Lir : public Backend { void ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir); void ApplyLoadHoisting(LIR* head_lir, LIR* tail_lir); void ApplyLocalOptimizations(LIR* head_lir, LIR* tail_lir); - void RemoveRedundantBranches(); // Shared by all targets - implemented in ralloc_util.cc int GetSRegHi(int lowSreg); @@ -727,7 +727,6 @@ class Mir2Lir : public Backend { GrowableArray throw_launchpads_; GrowableArray suspend_launchpads_; GrowableArray intrinsic_launchpads_; - GrowableArray boundary_map_; /* * Holds mapping from native PC to dex PC for safepoints where we may deoptimize. * Native PC is on the return address of the safepointed operation. Dex PC is for diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc index e8834320a9..3e768837ff 100644 --- a/compiler/dex/quick/x86/assemble_x86.cc +++ b/compiler/dex/quick/x86/assemble_x86.cc @@ -1237,7 +1237,7 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(uintptr_t start_addr) { delta = target - pc; if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && delta == 0) { // Useless branch - lir->flags.is_nop = true; + NopLIR(lir); if (kVerbosePcFixup) { LOG(INFO) << "Retry for useless branch at " << lir->offset; } -- cgit v1.2.3-59-g8ed1b From bd663de599b16229085759366c56e2ed5a1dc7ec Mon Sep 17 00:00:00 2001 From: buzbee Date: Tue, 10 Sep 2013 15:41:31 -0700 Subject: Compile-time tuning: register/bb utilities This CL yeilds about a 4% improvement in the compilation phase of dex2oat (single-threaded; multi-threaded compilation is more difficult to accurately measure). The register utilities could stand to be completely rewritten, but this gets most of the easy benefit. Next up: the assembly phase. Change-Id: Ife5a474e9b1a6d9e501e888dda6749d34eb77e96 --- compiler/dex/growable_array.h | 10 ++++++++ compiler/dex/mir_graph.cc | 17 +++++++----- compiler/dex/mir_graph.h | 2 +- compiler/dex/quick/arm/codegen_arm.h | 1 - compiler/dex/quick/arm/target_arm.cc | 5 ---- compiler/dex/quick/codegen_util.cc | 2 ++ compiler/dex/quick/mips/codegen_mips.h | 1 - compiler/dex/quick/mips/target_mips.cc | 5 ---- compiler/dex/quick/mir_to_lir-inl.h | 5 ++++ compiler/dex/quick/mir_to_lir.h | 4 ++- compiler/dex/quick/ralloc_util.cc | 47 +++++++++++++++------------------- compiler/dex/quick/x86/codegen_x86.h | 1 - compiler/dex/quick/x86/target_x86.cc | 5 ---- 13 files changed, 52 insertions(+), 53 deletions(-) (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/growable_array.h b/compiler/dex/growable_array.h index 8e2abfbaf1..639120a2ba 100644 --- a/compiler/dex/growable_array.h +++ b/compiler/dex/growable_array.h @@ -131,6 +131,11 @@ class GrowableArray { elem_list_[index]++; } + /* + * Remove an existing element from list. If there are more than one copy + * of the element, only the first one encountered will be deleted. + */ + // TODO: consider renaming this. void Delete(T element) { bool found = false; for (size_t i = 0; i < num_used_ - 1; i++) { @@ -150,6 +155,11 @@ class GrowableArray { size_t Size() const { return num_used_; } + void SetSize(size_t new_size) { + Resize(new_size); + num_used_ = new_size; + } + T* GetRawStorage() const { return elem_list_; } static void* operator new(size_t size, ArenaAllocator* arena) { diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index 81702e3842..c72283e689 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -99,6 +99,7 @@ MIRGraph::MIRGraph(CompilationUnit* cu, ArenaAllocator* arena) cur_block_(NULL), num_blocks_(0), current_code_item_(NULL), + block_map_(arena, 0, kGrowableArrayMisc), current_method_(kInvalidEntry), current_offset_(kInvalidEntry), def_count_(0), @@ -210,18 +211,18 @@ BasicBlock* MIRGraph::FindBlock(unsigned int code_offset, bool split, bool creat BasicBlock** immed_pred_block_p) { BasicBlock* bb; unsigned int i; - SafeMap::iterator it; - it = block_map_.find(code_offset); - if (it != block_map_.end()) { - return it->second; - } else if (!create) { + if (code_offset >= cu_->code_item->insns_size_in_code_units_) { return NULL; } + bb = block_map_.Get(code_offset); + if ((bb != NULL) || !create) { + return bb; + } if (split) { - for (i = 0; i < block_list_.Size(); i++) { - bb = block_list_.Get(i); + for (i = block_list_.Size(); i > 0; i--) { + bb = block_list_.Get(i - 1); if (bb->block_type != kDalvikByteCode) continue; /* Check if a branch jumps into the middle of an existing block */ if ((code_offset > bb->start_offset) && (bb->last_mir_insn != NULL) && @@ -518,6 +519,8 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ // TODO: need to rework expansion of block list & try_block_addr when inlining activated. block_list_.Resize(block_list_.Size() + current_code_item_->insns_size_in_code_units_); + block_map_.SetSize(block_map_.Size() + current_code_item_->insns_size_in_code_units_); + // TODO: replace with explicit resize routine. Using automatic extension side effect for now. try_block_addr_->SetBit(current_code_item_->insns_size_in_code_units_); try_block_addr_->ClearBit(current_code_item_->insns_size_in_code_units_); diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 15e15c380f..0244daec9d 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -728,7 +728,7 @@ class MIRGraph { BasicBlock* cur_block_; int num_blocks_; const DexFile::CodeItem* current_code_item_; - SafeMap block_map_; // FindBlock lookup cache. + GrowableArray block_map_; // FindBlock lookup cache. std::vector m_units_; // List of methods included in this graph typedef std::pair MIRLocation; // Insert point, (m_unit_ index, offset) std::vector method_stack_; // Include stack diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h index 291319f258..1954fbac51 100644 --- a/compiler/dex/quick/arm/codegen_arm.h +++ b/compiler/dex/quick/arm/codegen_arm.h @@ -51,7 +51,6 @@ class ArmMir2Lir : public Mir2Lir { int AllocTypedTempPair(bool fp_hint, int reg_class); int S2d(int low_reg, int high_reg); int TargetReg(SpecialTargetRegister reg); - RegisterInfo* GetRegInfo(int reg); RegLocation GetReturnAlt(); RegLocation GetReturnWideAlt(); RegLocation LocCReturn(); diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc index 6cc3052da1..203a8cc55d 100644 --- a/compiler/dex/quick/arm/target_arm.cc +++ b/compiler/dex/quick/arm/target_arm.cc @@ -691,11 +691,6 @@ RegLocation ArmMir2Lir::GetReturnAlt() { return res; } -ArmMir2Lir::RegisterInfo* ArmMir2Lir::GetRegInfo(int reg) { - return ARM_FPREG(reg) ? ®_pool_->FPRegs[reg & ARM_FP_REG_MASK] - : ®_pool_->core_regs[reg]; -} - /* To be used when explicitly managing register use */ void ArmMir2Lir::LockCallTemps() { LockTemp(r0); diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 3aa2f647c2..f13ab2db01 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -956,6 +956,8 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena throw_launchpads_(arena, 2048, kGrowableArrayThrowLaunchPads), suspend_launchpads_(arena, 4, kGrowableArraySuspendLaunchPads), intrinsic_launchpads_(arena, 2048, kGrowableArrayMisc), + tempreg_info_(arena, 20, kGrowableArrayMisc), + reginfo_map_(arena, 64, kGrowableArrayMisc), data_offset_(0), total_size_(0), block_label_list_(NULL), diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h index b9cb720962..8d0b347a34 100644 --- a/compiler/dex/quick/mips/codegen_mips.h +++ b/compiler/dex/quick/mips/codegen_mips.h @@ -52,7 +52,6 @@ class MipsMir2Lir : public Mir2Lir { int AllocTypedTempPair(bool fp_hint, int reg_class); int S2d(int low_reg, int high_reg); int TargetReg(SpecialTargetRegister reg); - RegisterInfo* GetRegInfo(int reg); RegLocation GetReturnAlt(); RegLocation GetReturnWideAlt(); RegLocation LocCReturn(); diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc index 4ee5b23eb9..8e768dcf18 100644 --- a/compiler/dex/quick/mips/target_mips.cc +++ b/compiler/dex/quick/mips/target_mips.cc @@ -399,11 +399,6 @@ RegLocation MipsMir2Lir::GetReturnAlt() { return res; } -MipsMir2Lir::RegisterInfo* MipsMir2Lir::GetRegInfo(int reg) { - return MIPS_FPREG(reg) ? ®_pool_->FPRegs[reg & MIPS_FP_REG_MASK] - : ®_pool_->core_regs[reg]; -} - /* To be used when explicitly managing register use */ void MipsMir2Lir::LockCallTemps() { LockTemp(rMIPS_ARG0); diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h index f9ec19951e..0ca8d8de11 100644 --- a/compiler/dex/quick/mir_to_lir-inl.h +++ b/compiler/dex/quick/mir_to_lir-inl.h @@ -201,6 +201,11 @@ inline void Mir2Lir::SetupResourceMasks(LIR* lir) { SetupTargetResourceMasks(lir); } +inline art::Mir2Lir::RegisterInfo* Mir2Lir::GetRegInfo(int reg) { + DCHECK(reginfo_map_.Get(reg) != NULL); + return reginfo_map_.Get(reg); +} + } // namespace art #endif // ART_COMPILER_DEX_QUICK_MIR_TO_LIR_INL_H_ diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 5b4813416b..fdbc1d02b3 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -374,6 +374,7 @@ class Mir2Lir : public Backend { int SRegOffset(int s_reg); RegLocation GetReturnWide(bool is_double); RegLocation GetReturn(bool is_float); + RegisterInfo* GetRegInfo(int reg); // Shared by all targets - implemented in gen_common.cc. bool HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div, @@ -550,7 +551,6 @@ class Mir2Lir : public Backend { virtual int AllocTypedTempPair(bool fp_hint, int reg_class) = 0; virtual int S2d(int low_reg, int high_reg) = 0; virtual int TargetReg(SpecialTargetRegister reg) = 0; - virtual RegisterInfo* GetRegInfo(int reg) = 0; virtual RegLocation GetReturnAlt() = 0; virtual RegLocation GetReturnWideAlt() = 0; virtual RegLocation LocCReturn() = 0; @@ -727,6 +727,8 @@ class Mir2Lir : public Backend { GrowableArray throw_launchpads_; GrowableArray suspend_launchpads_; GrowableArray intrinsic_launchpads_; + GrowableArray tempreg_info_; + GrowableArray reginfo_map_; /* * Holds mapping from native PC to dex PC for safepoints where we may deoptimize. * Native PC is on the return address of the safepointed operation. Dex PC is for diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc index db110aabd5..a0f22fc576 100644 --- a/compiler/dex/quick/ralloc_util.cc +++ b/compiler/dex/quick/ralloc_util.cc @@ -28,13 +28,9 @@ namespace art { * live until it is either explicitly killed or reallocated. */ void Mir2Lir::ResetRegPool() { - for (int i = 0; i < reg_pool_->num_core_regs; i++) { - if (reg_pool_->core_regs[i].is_temp) - reg_pool_->core_regs[i].in_use = false; - } - for (int i = 0; i < reg_pool_->num_fp_regs; i++) { - if (reg_pool_->FPRegs[i].is_temp) - reg_pool_->FPRegs[i].in_use = false; + GrowableArray::Iterator iter(&tempreg_info_); + for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) { + info->in_use = false; } // Reset temp tracking sanity check. if (kIsDebugBuild) { @@ -48,13 +44,21 @@ void Mir2Lir::ResetRegPool() { */ void Mir2Lir::CompilerInitPool(RegisterInfo* regs, int* reg_nums, int num) { for (int i = 0; i < num; i++) { - regs[i].reg = reg_nums[i]; + uint32_t reg_number = reg_nums[i]; + regs[i].reg = reg_number; regs[i].in_use = false; regs[i].is_temp = false; regs[i].pair = false; regs[i].live = false; regs[i].dirty = false; regs[i].s_reg = INVALID_SREG; + size_t map_size = reginfo_map_.Size(); + if (reg_number >= map_size) { + for (uint32_t i = 0; i < ((reg_number - map_size) + 1); i++) { + reginfo_map_.Insert(NULL); + } + } + reginfo_map_.Put(reg_number, ®s[i]); } } @@ -551,24 +555,13 @@ void Mir2Lir::ResetDefTracking() { } void Mir2Lir::ClobberAllRegs() { - RegisterInfo* p; - for (p = reg_pool_->core_regs; p < reg_pool_->core_regs + reg_pool_->num_core_regs; p++) { - if (p->is_temp) { - p->live = false; - p->s_reg = INVALID_SREG; - p->def_start = NULL; - p->def_end = NULL; - p->pair = false; - } - } - for (p = reg_pool_->FPRegs; p < reg_pool_->FPRegs + reg_pool_->num_fp_regs; p++) { - if (p->is_temp) { - p->live = false; - p->s_reg = INVALID_SREG; - p->def_start = NULL; - p->def_end = NULL; - p->pair = false; - } + GrowableArray::Iterator iter(&tempreg_info_); + for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) { + info->live = false; + info->s_reg = INVALID_SREG; + info->def_start = NULL; + info->def_end = NULL; + info->pair = false; } } @@ -624,11 +617,13 @@ void Mir2Lir::MarkLive(int reg, int s_reg) { void Mir2Lir::MarkTemp(int reg) { RegisterInfo* info = GetRegInfo(reg); + tempreg_info_.Insert(info); info->is_temp = true; } void Mir2Lir::UnmarkTemp(int reg) { RegisterInfo* info = GetRegInfo(reg); + tempreg_info_.Delete(info); info->is_temp = false; } diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index 478654d0b4..0f281106b2 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -52,7 +52,6 @@ class X86Mir2Lir : public Mir2Lir { int AllocTypedTempPair(bool fp_hint, int reg_class); int S2d(int low_reg, int high_reg); int TargetReg(SpecialTargetRegister reg); - RegisterInfo* GetRegInfo(int reg); RegLocation GetReturnAlt(); RegLocation GetReturnWideAlt(); RegLocation LocCReturn(); diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index 26accab360..94dd759e91 100644 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -375,11 +375,6 @@ RegLocation X86Mir2Lir::GetReturnAlt() { return res; } -X86Mir2Lir::RegisterInfo* X86Mir2Lir::GetRegInfo(int reg) { - return X86_FPREG(reg) ? ®_pool_->FPRegs[reg & X86_FP_REG_MASK] - : ®_pool_->core_regs[reg]; -} - /* To be used when explicitly managing register use */ void X86Mir2Lir::LockCallTemps() { LockTemp(rX86_ARG0); -- cgit v1.2.3-59-g8ed1b From 8b2c0b9abc3f520495f4387ea040132ba85cae69 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 19 Sep 2013 02:56:49 -0700 Subject: Use class def index from java.lang.Class. Bug: 10244719 Depends on: https://googleplex-android-review.git.corp.google.com/362363 This removes the computation of the dex file index, when necessary this is computed by searching the dex file. Its only necessary in dalvik.system.DexFile.defineClassNative and DexFile::FindInClassPath, the latter not showing up significantly in profiling with this change. Change-Id: I20c73a3b17d86286428ab0fd21bc13f51f36c85c --- compiler/dex/compiler_ir.h | 2 +- compiler/dex/dex_to_dex_compiler.cc | 2 +- compiler/dex/frontend.cc | 6 +- compiler/dex/frontend.h | 2 +- compiler/dex/mir_graph.cc | 2 +- compiler/dex/mir_graph.h | 2 +- compiler/dex/quick/codegen_util.cc | 22 ++-- compiler/driver/compiler_driver.cc | 49 +++++---- compiler/driver/compiler_driver.h | 27 +++-- compiler/driver/dex_compilation_unit.cc | 2 +- compiler/driver/dex_compilation_unit.h | 6 +- compiler/image_writer.cc | 1 + compiler/llvm/compiler_llvm.cc | 4 +- compiler/sea_ir/frontend.cc | 6 +- compiler/sea_ir/ir/sea.cc | 4 +- compiler/sea_ir/ir/sea.h | 6 +- oatdump/oatdump.cc | 32 +++--- runtime/Android.mk | 1 + runtime/class_linker.cc | 111 ++++++++++----------- runtime/class_linker.h | 4 +- runtime/class_linker_test.cc | 12 +-- runtime/dex_file.cc | 91 +++++------------ runtime/dex_file.h | 44 +++----- .../entrypoints/quick/quick_invoke_entrypoints.cc | 2 +- runtime/mirror/art_method-inl.h | 2 +- runtime/mirror/class.cc | 23 ++--- runtime/mirror/class.h | 31 ++++-- runtime/mirror/dex_cache.h | 1 + runtime/mirror/proxy.h | 3 + runtime/mirror/string.h | 2 +- runtime/native/dalvik_system_DexFile.cc | 2 +- runtime/native/java_lang_Class.cc | 31 ------ runtime/native/java_lang_DexCache.cc | 56 +++++++++++ runtime/oat_file.cc | 2 +- runtime/oat_file.h | 2 +- runtime/object_utils.h | 87 +++++++--------- runtime/runtime.cc | 5 +- runtime/thread.cc | 2 +- runtime/verifier/method_verifier.cc | 96 +++++++++--------- runtime/verifier/method_verifier.h | 19 ++-- runtime/verifier/method_verifier_test.cc | 3 +- test/100-reflect2/expected.txt | 2 +- 42 files changed, 397 insertions(+), 412 deletions(-) create mode 100644 runtime/native/java_lang_DexCache.cc (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h index 26d0923baa..6607562b13 100644 --- a/compiler/dex/compiler_ir.h +++ b/compiler/dex/compiler_ir.h @@ -77,7 +77,7 @@ struct CompilationUnit { ClassLinker* class_linker; // Linker to resolve fields and methods. const DexFile* dex_file; // DexFile containing the method being compiled. jobject class_loader; // compiling method's class loader. - uint32_t class_def_idx; // compiling method's defining class definition index. + uint16_t class_def_idx; // compiling method's defining class definition index. uint32_t method_idx; // compiling method's index into method_ids of DexFile. const DexFile::CodeItem* code_item; // compiling method's DexFile code_item. uint32_t access_flags; // compiling method's access flags. diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index ffd7905dfe..abafbc5830 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -280,7 +280,7 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, extern "C" void ArtCompileDEX(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file, art::DexToDexCompilationLevel dex_to_dex_compilation_level) { if (dex_to_dex_compilation_level != art::kDontDexToDexCompile) { diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index 23036495ce..fefcab9e87 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -110,7 +110,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, const CompilerBackend compiler_backend, const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file #if defined(ART_USE_PORTABLE_COMPILER) , llvm::LlvmCompilationUnit* llvm_compilation_unit @@ -273,7 +273,7 @@ CompiledMethod* CompileOneMethod(CompilerDriver& compiler, const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, @@ -292,7 +292,7 @@ extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file) { // TODO: check method fingerprint here to determine appropriate backend type. Until then, use build default art::CompilerBackend backend = compiler.GetCompilerBackend(); diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h index bafa46892c..6c33d109e3 100644 --- a/compiler/dex/frontend.h +++ b/compiler/dex/frontend.h @@ -117,7 +117,7 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_dex_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index c72283e689..c234298a88 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -504,7 +504,7 @@ BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, int cur_ /* Parse a Dex method and insert it into the MIRGraph at the current insert point. */ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint32_t class_def_idx, + InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file) { current_code_item_ = code_item; method_stack_.push_back(std::make_pair(current_method_, current_offset_)); diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 0244daec9d..9d4ab98f67 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -357,7 +357,7 @@ class MIRGraph { * actually the index of the method in the m_units_ array). */ void InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint32_t class_def_idx, + InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file); /* Find existing block */ diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index f13ab2db01..4ce752fb39 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -385,11 +385,12 @@ void Mir2Lir::InstallLiteralPools() { while (data_lir != NULL) { uint32_t target = data_lir->operands[0]; cu_->compiler_driver->AddCodePatch(cu_->dex_file, - cu_->method_idx, - cu_->invoke_type, - target, - static_cast(data_lir->operands[1]), - code_buffer_.size()); + cu_->class_def_idx, + cu_->method_idx, + cu_->invoke_type, + target, + static_cast(data_lir->operands[1]), + code_buffer_.size()); const DexFile::MethodId& id = cu_->dex_file->GetMethodId(target); // unique based on target to ensure code deduplication works uint32_t unique_patch_value = reinterpret_cast(&id); @@ -400,11 +401,12 @@ void Mir2Lir::InstallLiteralPools() { while (data_lir != NULL) { uint32_t target = data_lir->operands[0]; cu_->compiler_driver->AddMethodPatch(cu_->dex_file, - cu_->method_idx, - cu_->invoke_type, - target, - static_cast(data_lir->operands[1]), - code_buffer_.size()); + cu_->class_def_idx, + cu_->method_idx, + cu_->invoke_type, + target, + static_cast(data_lir->operands[1]), + code_buffer_.size()); const DexFile::MethodId& id = cu_->dex_file->GetMethodId(target); // unique based on target to ensure code deduplication works uint32_t unique_patch_value = reinterpret_cast(&id); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 8d521de72f..658370f1fd 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -293,7 +293,7 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); @@ -301,7 +301,7 @@ extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& compi const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); @@ -310,7 +310,7 @@ extern "C" art::CompiledMethod* ArtCompileDEX(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); @@ -319,7 +319,7 @@ extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); @@ -540,7 +540,7 @@ void CompilerDriver::CompileOne(const mirror::ArtMethod* method, base::TimingLog Thread* self = Thread::Current(); jobject jclass_loader; const DexFile* dex_file; - uint32_t class_def_idx; + uint16_t class_def_idx; { ScopedObjectAccessUnchecked soa(self); ScopedLocalRef @@ -1304,13 +1304,15 @@ bool CompilerDriver::IsSafeCast(const MethodReference& mr, uint32_t dex_pc) { void CompilerDriver::AddCodePatch(const DexFile* dex_file, - uint32_t referrer_method_idx, - InvokeType referrer_invoke_type, - uint32_t target_method_idx, - InvokeType target_invoke_type, - size_t literal_offset) { + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + InvokeType referrer_invoke_type, + uint32_t target_method_idx, + InvokeType target_invoke_type, + size_t literal_offset) { MutexLock mu(Thread::Current(), compiled_methods_lock_); code_to_patch_.push_back(new PatchInformation(dex_file, + referrer_class_def_idx, referrer_method_idx, referrer_invoke_type, target_method_idx, @@ -1318,13 +1320,15 @@ void CompilerDriver::AddCodePatch(const DexFile* dex_file, literal_offset)); } void CompilerDriver::AddMethodPatch(const DexFile* dex_file, - uint32_t referrer_method_idx, - InvokeType referrer_invoke_type, - uint32_t target_method_idx, - InvokeType target_invoke_type, - size_t literal_offset) { + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + InvokeType referrer_invoke_type, + uint32_t target_method_idx, + InvokeType target_invoke_type, + size_t literal_offset) { MutexLock mu(Thread::Current(), compiled_methods_lock_); methods_to_patch_.push_back(new PatchInformation(dex_file, + referrer_class_def_idx, referrer_method_idx, referrer_invoke_type, target_method_idx, @@ -1625,10 +1629,12 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ */ mirror::DexCache* dex_cache = manager->GetClassLinker()->FindDexCache(*manager->GetDexFile()); std::string error_msg; - if (verifier::MethodVerifier::VerifyClass(manager->GetDexFile(), + const DexFile* dex_file = manager->GetDexFile(); + const DexFile::ClassDef* class_def = &dex_file->GetClassDef(class_def_index); + if (verifier::MethodVerifier::VerifyClass(dex_file, dex_cache, soa.Decode(manager->GetClassLoader()), - class_def_index, error_msg, true) == + class_def, true, &error_msg) == verifier::MethodVerifier::kHardFailure) { const DexFile::ClassDef& class_def = manager->GetDexFile()->GetClassDef(class_def_index); LOG(ERROR) << "Verification failed on class " @@ -2137,7 +2143,8 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl } // If successfully initialized place in SSB array. if (klass->IsInitialized()) { - klass->GetDexCache()->GetInitializedStaticStorage()->Set(klass->GetDexTypeIndex(), klass); + int32_t ssb_index = klass->GetDexTypeIndex(); + klass->GetDexCache()->GetInitializedStaticStorage()->Set(ssb_index, klass); } } // Record the final class status if necessary. @@ -2264,7 +2271,7 @@ void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_fil } void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint32_t class_def_idx, + InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, DexToDexCompilationLevel dex_to_dex_compilation_level) { @@ -2387,13 +2394,13 @@ void CompilerDriver::SetBitcodeFileName(std::string const& filename) { void CompilerDriver::AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, - size_t class_def_index) { + uint16_t class_def_index) { WriterMutexLock mu(self, freezing_constructor_lock_); freezing_constructor_classes_.insert(ClassReference(dex_file, class_def_index)); } bool CompilerDriver::RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, - size_t class_def_index) { + uint16_t class_def_index) { ReaderMutexLock mu(self, freezing_constructor_lock_); return freezing_constructor_classes_.count(ClassReference(dex_file, class_def_index)) != 0; } diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index b4ec0c134b..66c9cbf91a 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -145,8 +145,9 @@ class CompilerDriver { CompiledMethod* GetCompiledMethod(MethodReference ref) const LOCKS_EXCLUDED(compiled_methods_lock_); - void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, size_t class_def_index); - bool RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, size_t class_def_index); + void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, + uint16_t class_def_index); + bool RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, uint16_t class_def_index); // Callbacks from compiler to see what runtime checks must be generated. @@ -192,6 +193,7 @@ class CompilerDriver { // Record patch information for later fix up. void AddCodePatch(const DexFile* dex_file, + uint16_t referrer_class_def_idx, uint32_t referrer_method_idx, InvokeType referrer_invoke_type, uint32_t target_method_idx, @@ -199,6 +201,7 @@ class CompilerDriver { size_t literal_offset) LOCKS_EXCLUDED(compiled_methods_lock_); void AddMethodPatch(const DexFile* dex_file, + uint16_t referrer_class_def_idx, uint32_t referrer_method_idx, InvokeType referrer_invoke_type, uint32_t target_method_idx, @@ -249,6 +252,9 @@ class CompilerDriver { const DexFile& GetDexFile() const { return *dex_file_; } + uint16_t GetReferrerClassDefIdx() const { + return referrer_class_def_idx_; + } uint32_t GetReferrerMethodIdx() const { return referrer_method_idx_; } @@ -267,12 +273,14 @@ class CompilerDriver { private: PatchInformation(const DexFile* dex_file, + uint16_t referrer_class_def_idx, uint32_t referrer_method_idx, InvokeType referrer_invoke_type, uint32_t target_method_idx, InvokeType target_invoke_type, size_t literal_offset) : dex_file_(dex_file), + referrer_class_def_idx_(referrer_class_def_idx), referrer_method_idx_(referrer_method_idx), referrer_invoke_type_(referrer_invoke_type), target_method_idx_(target_method_idx), @@ -281,12 +289,13 @@ class CompilerDriver { CHECK(dex_file_ != NULL); } - const DexFile* dex_file_; - uint32_t referrer_method_idx_; - InvokeType referrer_invoke_type_; - uint32_t target_method_idx_; - InvokeType target_invoke_type_; - size_t literal_offset_; + const DexFile* const dex_file_; + const uint16_t referrer_class_def_idx_; + const uint32_t referrer_method_idx_; + const InvokeType referrer_invoke_type_; + const uint32_t target_method_idx_; + const InvokeType target_invoke_type_; + const size_t literal_offset_; friend class CompilerDriver; DISALLOW_COPY_AND_ASSIGN(PatchInformation); @@ -358,7 +367,7 @@ class CompilerDriver { ThreadPool& thread_pool, base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_); void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx, + InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, DexToDexCompilationLevel dex_to_dex_compilation_level) LOCKS_EXCLUDED(compiled_methods_lock_); diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc index eb8941b15f..c441d09ab2 100644 --- a/compiler/driver/dex_compilation_unit.cc +++ b/compiler/driver/dex_compilation_unit.cc @@ -39,7 +39,7 @@ DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu, ClassLinker* class_linker, const DexFile& dex_file, const DexFile::CodeItem* code_item, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, uint32_t access_flags) : cu_(cu), diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h index 465139b34f..3df50ffec6 100644 --- a/compiler/driver/dex_compilation_unit.h +++ b/compiler/driver/dex_compilation_unit.h @@ -36,7 +36,7 @@ class DexCompilationUnit { DexCompilationUnit(CompilationUnit* cu, jobject class_loader, ClassLinker* class_linker, const DexFile& dex_file, const DexFile::CodeItem* code_item, - uint32_t class_def_idx, uint32_t method_idx, uint32_t access_flags); + uint16_t class_def_idx, uint32_t method_idx, uint32_t access_flags); CompilationUnit* GetCompilationUnit() const { return cu_; @@ -54,7 +54,7 @@ class DexCompilationUnit { return dex_file_; } - uint32_t GetClassDefIndex() const { + uint16_t GetClassDefIndex() const { return class_def_idx_; } @@ -108,7 +108,7 @@ class DexCompilationUnit { const DexFile* const dex_file_; const DexFile::CodeItem* const code_item_; - const uint32_t class_def_idx_; + const uint16_t class_def_idx_; const uint32_t dex_method_idx_; const uint32_t access_flags_; diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index d1859e6f98..f82c6fb40f 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -699,6 +699,7 @@ void ImageWriter::PatchOatCodeAndMethods() { void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); const void* oat_code = class_linker->GetOatCodeFor(patch->GetDexFile(), + patch->GetReferrerClassDefIdx(), patch->GetReferrerMethodIdx()); OatHeader& oat_header = const_cast(oat_file_->GetOatHeader()); // TODO: make this Thumb2 specific diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc index 0df3c476fc..d59afd48b7 100644 --- a/compiler/llvm/compiler_llvm.cc +++ b/compiler/llvm/compiler_llvm.cc @@ -40,7 +40,7 @@ void CompileOneMethod(CompilerDriver& driver, const CompilerBackend compilerBackend, const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, llvm::LlvmCompilationUnit* llvm_info); } @@ -203,7 +203,7 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file) { diff --git a/compiler/sea_ir/frontend.cc b/compiler/sea_ir/frontend.cc index 93f6f25461..3512911f43 100644 --- a/compiler/sea_ir/frontend.cc +++ b/compiler/sea_ir/frontend.cc @@ -41,7 +41,7 @@ static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler, const CompilerBackend compiler_backend, const DexFile::CodeItem* code_item, uint32_t method_access_flags, InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file #if defined(ART_USE_PORTABLE_COMPILER) , llvm::LlvmCompilationUnit* llvm_compilation_unit @@ -69,7 +69,7 @@ CompiledMethod* SeaIrCompileOneMethod(CompilerDriver& compiler, const DexFile::CodeItem* code_item, uint32_t method_access_flags, InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, @@ -86,7 +86,7 @@ extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t method_access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file) { // TODO: Check method fingerprint here to determine appropriate backend type. // Until then, use build default diff --git a/compiler/sea_ir/ir/sea.cc b/compiler/sea_ir/ir/sea.cc index 5ccaba6ad9..0734b21f12 100644 --- a/compiler/sea_ir/ir/sea.cc +++ b/compiler/sea_ir/ir/sea.cc @@ -191,7 +191,7 @@ void SeaGraph::InsertSignatureNodes(const art::DexFile::CodeItem* code_item, Reg } void SeaGraph::BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, - const art::DexFile& dex_file, uint32_t class_def_idx, + const art::DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx, uint32_t method_access_flags) { code_item_ = code_item; class_def_idx_ = class_def_idx; @@ -409,7 +409,7 @@ CodeGenData* SeaGraph::GenerateLLVM(const std::string& function_name, CodeGenData* SeaGraph::CompileMethod( const std::string& function_name, - const art::DexFile::CodeItem* code_item, uint32_t class_def_idx, + const art::DexFile::CodeItem* code_item, uint16_t class_def_idx, uint32_t method_idx, uint32_t method_access_flags, const art::DexFile& dex_file) { // Two passes: Builds the intermediate structure (non-SSA) of the sea-ir for the function. BuildMethodSeaGraph(code_item, dex_file, class_def_idx, method_idx, method_access_flags); diff --git a/compiler/sea_ir/ir/sea.h b/compiler/sea_ir/ir/sea.h index 92c2043dbd..26b16be019 100644 --- a/compiler/sea_ir/ir/sea.h +++ b/compiler/sea_ir/ir/sea.h @@ -262,7 +262,7 @@ class SeaGraph: IVisitable { static SeaGraph* GetGraph(const art::DexFile&); CodeGenData* CompileMethod(const std::string& function_name, - const art::DexFile::CodeItem* code_item, uint32_t class_def_idx, + const art::DexFile::CodeItem* code_item, uint16_t class_def_idx, uint32_t method_idx, uint32_t method_access_flags, const art::DexFile& dex_file); // Returns all regions corresponding to this SeaGraph. std::vector* GetRegions() { @@ -288,7 +288,7 @@ class SeaGraph: IVisitable { } TypeInference* ti_; - uint32_t class_def_idx_; + uint16_t class_def_idx_; uint32_t method_idx_; uint32_t method_access_flags_; @@ -311,7 +311,7 @@ class SeaGraph: IVisitable { // Builds the non-SSA sea-ir representation of the function @code_item from @dex_file // with class id @class_def_idx and method id @method_idx. void BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, - const art::DexFile& dex_file, uint32_t class_def_idx, + const art::DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx, uint32_t method_access_flags); // Computes immediate dominators for each region. // Precondition: ComputeMethodSeaGraph() diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index cf1b6af809..fc9e00c2cb 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -176,9 +176,10 @@ class OatDumper { CHECK(oat_dex_file != NULL); UniquePtr dex_file(oat_dex_file->OpenDexFile()); if (dex_file.get() != NULL) { - uint32_t class_def_index; - bool found = dex_file->FindClassDefIndex(mh.GetDeclaringClassDescriptor(), class_def_index); - if (found) { + const DexFile::ClassDef* class_def = + dex_file->FindClassDef(mh.GetDeclaringClassDescriptor()); + if (class_def != NULL) { + uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def); const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_index); CHECK(oat_class != NULL); size_t method_index = m->GetMethodIndex(); @@ -284,18 +285,17 @@ class OatDumper { } ClassDataItemIterator it(dex_file, class_data); SkipAllFields(it); - uint32_t class_def_idx = dex_file.GetIndexForClassDef(class_def); uint32_t class_method_idx = 0; while (it.HasNextDirectMethod()) { const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx); - DumpOatMethod(os, class_def_idx, class_method_idx, oat_method, dex_file, + DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetMemberAccessFlags()); class_method_idx++; it.Next(); } while (it.HasNextVirtualMethod()) { const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx); - DumpOatMethod(os, class_def_idx, class_method_idx, oat_method, dex_file, + DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetMemberAccessFlags()); class_method_idx++; it.Next(); @@ -304,7 +304,8 @@ class OatDumper { os << std::flush; } - void DumpOatMethod(std::ostream& os, uint32_t class_def_idx, uint32_t class_method_index, + void DumpOatMethod(std::ostream& os, const DexFile::ClassDef& class_def, + uint32_t class_method_index, const OatFile::OatMethod& oat_method, const DexFile& dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code_item, uint32_t method_access_flags) { @@ -323,7 +324,8 @@ class OatDumper { indent1_os << "VERIFIER TYPE ANALYSIS:\n"; Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count); std::ostream indent2_os(&indent2_filter); - DumpVerifier(indent2_os, dex_method_idx, &dex_file, class_def_idx, code_item, method_access_flags); + DumpVerifier(indent2_os, dex_method_idx, &dex_file, class_def, code_item, + method_access_flags); } { indent1_os << "OAT DATA:\n"; @@ -363,7 +365,7 @@ class OatDumper { oat_method.GetCode() != NULL ? "..." : ""); Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count); std::ostream indent2_os(&indent2_filter); - DumpCode(indent2_os, oat_method, dex_method_idx, &dex_file, class_def_idx, code_item, + DumpCode(indent2_os, oat_method, dex_method_idx, &dex_file, class_def, code_item, method_access_flags); } } @@ -554,7 +556,7 @@ class OatDumper { void DumpVRegsAtDexPc(std::ostream& os, const OatFile::OatMethod& oat_method, uint32_t dex_method_idx, const DexFile* dex_file, - uint32_t class_def_idx, const DexFile::CodeItem* code_item, + const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item, uint32_t method_access_flags, uint32_t dex_pc) { static UniquePtr verifier; static const DexFile* verified_dex_file = NULL; @@ -563,7 +565,7 @@ class OatDumper { ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file); mirror::ClassLoader* class_loader = NULL; - verifier.reset(new verifier::MethodVerifier(dex_file, dex_cache, class_loader, class_def_idx, + verifier.reset(new verifier::MethodVerifier(dex_file, dex_cache, class_loader, &class_def, code_item, dex_method_idx, NULL, method_access_flags, true, true)); verifier->Verify(); @@ -615,21 +617,21 @@ class OatDumper { } void DumpVerifier(std::ostream& os, uint32_t dex_method_idx, const DexFile* dex_file, - uint32_t class_def_idx, const DexFile::CodeItem* code_item, + const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item, uint32_t method_access_flags) { if ((method_access_flags & kAccNative) == 0) { ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file); mirror::ClassLoader* class_loader = NULL; verifier::MethodVerifier::VerifyMethodAndDump(os, dex_method_idx, dex_file, dex_cache, - class_loader, class_def_idx, code_item, NULL, + class_loader, &class_def, code_item, NULL, method_access_flags); } } void DumpCode(std::ostream& os, const OatFile::OatMethod& oat_method, uint32_t dex_method_idx, const DexFile* dex_file, - uint32_t class_def_idx, const DexFile::CodeItem* code_item, + const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item, uint32_t method_access_flags) { const void* code = oat_method.GetCode(); size_t code_size = oat_method.GetCodeSize(); @@ -647,7 +649,7 @@ class OatDumper { if (dex_pc != DexFile::kDexNoIndex) { DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset); if (kDumpVRegs) { - DumpVRegsAtDexPc(os, oat_method, dex_method_idx, dex_file, class_def_idx, code_item, + DumpVRegsAtDexPc(os, oat_method, dex_method_idx, dex_file, class_def, code_item, method_access_flags, dex_pc); } } diff --git a/runtime/Android.mk b/runtime/Android.mk index e324060ecb..5edf7592d9 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -91,6 +91,7 @@ LIBART_COMMON_SRC_FILES := \ native/dalvik_system_VMStack.cc \ native/dalvik_system_Zygote.cc \ native/java_lang_Class.cc \ + native/java_lang_DexCache.cc \ native/java_lang_Object.cc \ native/java_lang_Runtime.cc \ native/java_lang_String.cc \ diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index c19f8724bb..15eab9d165 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -475,40 +475,33 @@ void ClassLinker::FinishInit() { // as the types of the field can't be resolved prior to the runtime being // fully initialized mirror::Class* java_lang_ref_Reference = GetClassRoot(kJavaLangRefReference); - mirror::Class* java_lang_ref_ReferenceQueue = FindSystemClass("Ljava/lang/ref/ReferenceQueue;"); - mirror::Class* java_lang_ref_FinalizerReference = FindSystemClass("Ljava/lang/ref/FinalizerReference;"); - - const DexFile& java_lang_dex = *java_lang_ref_Reference->GetDexCache()->GetDexFile(); + mirror::Class* java_lang_ref_FinalizerReference = + FindSystemClass("Ljava/lang/ref/FinalizerReference;"); mirror::ArtField* pendingNext = java_lang_ref_Reference->GetInstanceField(0); FieldHelper fh(pendingNext, this); CHECK_STREQ(fh.GetName(), "pendingNext"); - CHECK_EQ(java_lang_dex.GetFieldId(pendingNext->GetDexFieldIndex()).type_idx_, - java_lang_ref_Reference->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); mirror::ArtField* queue = java_lang_ref_Reference->GetInstanceField(1); fh.ChangeField(queue); CHECK_STREQ(fh.GetName(), "queue"); - CHECK_EQ(java_lang_dex.GetFieldId(queue->GetDexFieldIndex()).type_idx_, - java_lang_ref_ReferenceQueue->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/ref/ReferenceQueue;"); mirror::ArtField* queueNext = java_lang_ref_Reference->GetInstanceField(2); fh.ChangeField(queueNext); CHECK_STREQ(fh.GetName(), "queueNext"); - CHECK_EQ(java_lang_dex.GetFieldId(queueNext->GetDexFieldIndex()).type_idx_, - java_lang_ref_Reference->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); mirror::ArtField* referent = java_lang_ref_Reference->GetInstanceField(3); fh.ChangeField(referent); CHECK_STREQ(fh.GetName(), "referent"); - CHECK_EQ(java_lang_dex.GetFieldId(referent->GetDexFieldIndex()).type_idx_, - GetClassRoot(kJavaLangObject)->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/Object;"); mirror::ArtField* zombie = java_lang_ref_FinalizerReference->GetInstanceField(2); fh.ChangeField(zombie); CHECK_STREQ(fh.GetName(), "zombie"); - CHECK_EQ(java_lang_dex.GetFieldId(zombie->GetDexFieldIndex()).type_idx_, - GetClassRoot(kJavaLangObject)->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/Object;"); gc::Heap* heap = Runtime::Current()->GetHeap(); heap->SetReferenceOffsets(referent->GetOffset(), @@ -1234,8 +1227,10 @@ mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Cl return NULL; } mirror::Class* klass = k->AsClass(); - klass->SetPrimitiveType(Primitive::kPrimNot); // default to not being primitive + klass->SetPrimitiveType(Primitive::kPrimNot); // Default to not being primitive. klass->SetClassSize(class_size); + klass->SetDexClassDefIndex(DexFile::kDexNoIndex16); // Default to no valid class def index. + klass->SetDexTypeIndex(DexFile::kDexNoIndex16); // Default to no valid type index. return klass; } @@ -1499,26 +1494,21 @@ size_t ClassLinker::SizeOfClass(const DexFile& dex_file, return size; } -const OatFile::OatClass* ClassLinker::GetOatClass(const DexFile& dex_file, const char* descriptor) { - DCHECK(descriptor != NULL); +const OatFile::OatClass* ClassLinker::GetOatClass(const DexFile& dex_file, uint16_t class_def_idx) { + DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16); const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file); - CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << descriptor; + CHECK(oat_file != NULL) << dex_file.GetLocation(); const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation()); - CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << descriptor; - uint32_t class_def_index; - bool found = dex_file.FindClassDefIndex(descriptor, class_def_index); - CHECK(found) << dex_file.GetLocation() << " " << descriptor; - const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_index); - CHECK(oat_class != NULL) << dex_file.GetLocation() << " " << descriptor; + CHECK(oat_dex_file != NULL) << dex_file.GetLocation(); + const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_idx); + CHECK(oat_class != NULL) << dex_file.GetLocation() << " " << class_def_idx; return oat_class; } -static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint32_t method_idx) { - const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); - const DexFile::TypeId& type_id = dex_file.GetTypeId(method_id.class_idx_); - const DexFile::ClassDef* class_def = dex_file.FindClassDef(dex_file.GetTypeDescriptor(type_id)); - CHECK(class_def != NULL); - const byte* class_data = dex_file.GetClassData(*class_def); +static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16_t class_def_idx, + uint32_t method_idx) { + const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx); + const byte* class_data = dex_file.GetClassData(class_def); CHECK(class_data != NULL); ClassDataItemIterator it(dex_file, class_data); // Skip fields @@ -1572,11 +1562,13 @@ const OatFile::OatMethod ClassLinker::GetOatMethodFor(const mirror::ArtMethod* m } CHECK(found) << "Didn't find oat method index for virtual method: " << PrettyMethod(method); } - ClassHelper kh(declaring_class); - UniquePtr oat_class(GetOatClass(kh.GetDexFile(), kh.GetDescriptor())); + UniquePtr + oat_class(GetOatClass(*declaring_class->GetDexCache()->GetDexFile(), + declaring_class->GetDexClassDefIndex())); CHECK(oat_class.get() != NULL); DCHECK_EQ(oat_method_index, GetOatMethodIndexFromMethodIndex(*declaring_class->GetDexCache()->GetDexFile(), + method->GetDeclaringClass()->GetDexClassDefIndex(), method->GetDexMethodIndex())); return oat_class->GetOatMethod(oat_method_index); @@ -1600,12 +1592,11 @@ const void* ClassLinker::GetOatCodeFor(const mirror::ArtMethod* method) { return result; } -const void* ClassLinker::GetOatCodeFor(const DexFile& dex_file, uint32_t method_idx) { - const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); - const char* descriptor = dex_file.GetTypeDescriptor(dex_file.GetTypeId(method_id.class_idx_)); - uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, method_idx); - UniquePtr oat_class(GetOatClass(dex_file, descriptor)); - CHECK(oat_class.get() != NULL); +const void* ClassLinker::GetOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, + uint32_t method_idx) { + UniquePtr oat_class(GetOatClass(dex_file, class_def_idx)); + CHECK(oat_class.get() != nullptr); + uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx); return oat_class->GetOatMethod(oat_method_idx).GetCode(); } @@ -1642,7 +1633,7 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) { // OAT file unavailable return; } - UniquePtr oat_class(GetOatClass(dex_file, kh.GetDescriptor())); + UniquePtr oat_class(GetOatClass(dex_file, klass->GetDexClassDefIndex())); CHECK(oat_class.get() != NULL); ClassDataItemIterator it(dex_file, class_data); // Skip fields @@ -1734,6 +1725,7 @@ void ClassLinker::LoadClass(const DexFile& dex_file, DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot); klass->SetStatus(mirror::Class::kStatusIdx, NULL); + klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def)); klass->SetDexTypeIndex(dex_class_def.class_idx_); // Load fields fields. @@ -1781,7 +1773,7 @@ void ClassLinker::LoadClass(const DexFile& dex_file, UniquePtr oat_class; if (Runtime::Current()->IsStarted() && !Runtime::Current()->UseCompileTimeClassPath()) { - oat_class.reset(GetOatClass(dex_file, descriptor)); + oat_class.reset(GetOatClass(dex_file, klass->GetDexClassDefIndex())); } // Load methods. @@ -1876,7 +1868,8 @@ mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file if (klass->GetClassLoader() != NULL) { // All non-boot finalizer methods are flagged klass->SetFinalizable(); } else { - StringPiece klass_descriptor(dex_file.StringByTypeIdx(klass->GetDexTypeIndex())); + ClassHelper kh(klass.get()); + StringPiece klass_descriptor(kh.GetDescriptor()); // The Enum class declares a "final" finalize() method to prevent subclasses from // introducing a finalizer. We don't want to set the finalizable flag for Enum or its // subclasses, so we exclude it here. @@ -2342,12 +2335,16 @@ mirror::Class* ClassLinker::LookupClassFromImage(const char* descriptor) { const DexFile* dex_file = dex_cache->GetDexFile(); // First search using the class def map, but don't bother for non-class types. if (descriptor[0] == 'L') { - const DexFile::ClassDef* class_def = dex_file->FindClassDef(descriptor); - if (class_def != NULL) { - mirror::Class* klass = dex_cache->GetResolvedType(class_def->class_idx_); - if (klass != NULL) { - self->EndAssertNoThreadSuspension(old_no_suspend_cause); - return klass; + const DexFile::StringId* descriptor_string_id = dex_file->FindStringId(descriptor); + if (descriptor_string_id != NULL) { + const DexFile::TypeId* type_id = + dex_file->FindTypeId(dex_file->GetIndexForStringId(*descriptor_string_id)); + if (type_id != NULL) { + mirror::Class* klass = dex_cache->GetResolvedType(dex_file->GetIndexForTypeId(*type_id)); + if (klass != NULL) { + self->EndAssertNoThreadSuspension(old_no_suspend_cause); + return klass; + } } } } @@ -2458,8 +2455,9 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure; std::string error_msg; if (!preverified) { - verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg, - Runtime::Current()->IsCompiler()); + verifier_failure = verifier::MethodVerifier::VerifyClass(klass, + Runtime::Current()->IsCompiler(), + &error_msg); } if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) { if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) { @@ -2530,7 +2528,6 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class } } - const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file); // Make this work with gtests, which do not set up the image properly. // TODO: we should clean up gtests to set up the image path properly. @@ -2542,9 +2539,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation()); CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass); const char* descriptor = ClassHelper(klass).GetDescriptor(); - uint32_t class_def_index; - bool found = dex_file.FindClassDefIndex(descriptor, class_def_index); - CHECK(found) << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor; + uint16_t class_def_index = klass->GetDexClassDefIndex(); UniquePtr oat_class(oat_dex_file->GetOatClass(class_def_index)); CHECK(oat_class.get() != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor; @@ -2657,8 +2652,6 @@ mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name, klass->SetStatus(mirror::Class::kStatusIdx, self); - klass->SetDexTypeIndex(DexFile::kDexNoIndex16); - // Instance fields are inherited, but we add a couple of static fields... { mirror::ObjectArray* sfields = AllocArtFieldArray(self, 2); @@ -3265,10 +3258,8 @@ bool ClassLinker::LinkClass(SirtRef& klass, bool ClassLinker::LoadSuperAndInterfaces(SirtRef& klass, const DexFile& dex_file) { CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus()); - StringPiece descriptor(dex_file.StringByTypeIdx(klass->GetDexTypeIndex())); - const DexFile::ClassDef* class_def = dex_file.FindClassDef(descriptor); - CHECK(class_def != NULL); - uint16_t super_class_idx = class_def->superclass_idx_; + const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex()); + uint16_t super_class_idx = class_def.superclass_idx_; if (super_class_idx != DexFile::kDexNoIndex16) { mirror::Class* super_class = ResolveType(dex_file, super_class_idx, klass.get()); if (super_class == NULL) { @@ -3284,7 +3275,7 @@ bool ClassLinker::LoadSuperAndInterfaces(SirtRef& klass, const De } klass->SetSuperClass(super_class); } - const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(*class_def); + const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(class_def); if (interfaces != NULL) { for (size_t i = 0; i < interfaces->Size(); i++) { uint16_t idx = interfaces->GetTypeItem(i).type_idx_; diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 20efbb43a9..3ffcf14447 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -329,7 +329,7 @@ class ClassLinker { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Get the oat code for a method from a method index. - const void* GetOatCodeFor(const DexFile& dex_file, uint32_t method_idx) + const void* GetOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); pid_t GetClassesLockOwner(); // For SignalCatcher. @@ -424,7 +424,7 @@ class ClassLinker { void FixupStaticTrampolines(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Finds the associated oat class for a dex_file and descriptor - const OatFile::OatClass* GetOatClass(const DexFile& dex_file, const char* descriptor) + const OatFile::OatClass* GetOatClass(const DexFile& dex_file, uint16_t class_def_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void RegisterDexFileLocked(const DexFile& dex_file, SirtRef& dex_cache) diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 0fa0ffbc56..bea1139679 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -508,6 +508,7 @@ struct ClassOffsets : public CheckOffsets { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_), "dexClassDefIndex")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_), "dexTypeIndex")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_instance_fields_), "numReferenceInstanceFields")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_static_fields_), "numReferenceStaticFields")); @@ -570,10 +571,6 @@ struct ProxyOffsets : public CheckOffsets { struct ClassClassOffsets : public CheckOffsets { ClassClassOffsets() : CheckOffsets(true, "Ljava/lang/Class;") { - // padding 32-bit - CHECK_EQ(OFFSETOF_MEMBER(mirror::ClassClass, padding_) + 4, - OFFSETOF_MEMBER(mirror::ClassClass, serialVersionUID_)); - // alphabetical 64-bit offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassClass, serialVersionUID_), "serialVersionUID")); }; @@ -585,11 +582,11 @@ struct StringClassOffsets : public CheckOffsets { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, ASCII_), "ASCII")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, CASE_INSENSITIVE_ORDER_), "CASE_INSENSITIVE_ORDER")); - // padding 32-bit - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, REPLACEMENT_CHAR_), "REPLACEMENT_CHAR")); - // alphabetical 64-bit offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, serialVersionUID_), "serialVersionUID")); + + // alphabetical 32-bit + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, REPLACEMENT_CHAR_), "REPLACEMENT_CHAR")); }; }; @@ -606,6 +603,7 @@ struct ArtMethodClassOffsets : public CheckOffsets { struct DexCacheOffsets : public CheckOffsets { DexCacheOffsets() : CheckOffsets(false, "Ljava/lang/DexCache;") { // alphabetical references + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_), "dex")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, initialized_static_storage_), "initializedStaticStorage")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, location_), "location")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_), "resolvedFields")); diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 4fd9a608c1..e81c456ccf 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -48,7 +48,7 @@ namespace art { const byte DexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' }; const byte DexFile::kDexMagicVersion[] = { '0', '3', '5', '\0' }; -DexFile::ClassPathEntry DexFile::FindInClassPath(const StringPiece& descriptor, +DexFile::ClassPathEntry DexFile::FindInClassPath(const char* descriptor, const ClassPath& class_path) { for (size_t i = 0; i != class_path.size(); ++i) { const DexFile* dex_file = class_path[i]; @@ -251,56 +251,11 @@ DexFile::~DexFile() { // the global reference table is otherwise empty! } -class ScopedJniMonitorLock { - public: - ScopedJniMonitorLock(JNIEnv* env, jobject locked) : env_(env), locked_(locked) { - env->MonitorEnter(locked_); - } - ~ScopedJniMonitorLock() { - env_->MonitorExit(locked_); - } - private: - JNIEnv* const env_; - const jobject locked_; -}; - -jobject DexFile::GetDexObject(JNIEnv* env) const { - { - ScopedJniMonitorLock lock(env, WellKnownClasses::com_android_dex_Dex); - if (dex_object_ != NULL) { - return dex_object_; - } - } - void* address = const_cast(reinterpret_cast(begin_)); - jobject byte_buffer = env->NewDirectByteBuffer(address, size_); - if (byte_buffer == NULL) { - return NULL; - } - - ScopedJniMonitorLock lock(env, WellKnownClasses::com_android_dex_Dex); - // Re-test to see if someone beat us to the creation when we had the lock released. - if (dex_object_ != NULL) { - return dex_object_; - } - jvalue args[1]; - args[0].l = byte_buffer; - jobject local = env->CallStaticObjectMethodA(WellKnownClasses::com_android_dex_Dex, - WellKnownClasses::com_android_dex_Dex_create, - args); - if (local == NULL) { - return NULL; - } - - dex_object_ = env->NewGlobalRef(local); - return dex_object_; -} - bool DexFile::Init() { InitMembers(); if (!CheckMagicAndVersion()) { return false; } - InitIndex(); return true; } @@ -351,28 +306,36 @@ uint32_t DexFile::GetVersion() const { return atoi(version); } -void DexFile::InitIndex() { - CHECK_EQ(index_.size(), 0U) << GetLocation(); - for (size_t i = 0; i < NumClassDefs(); ++i) { - const ClassDef& class_def = GetClassDef(i); - const char* descriptor = GetClassDescriptor(class_def); - index_.Put(descriptor, i); +const DexFile::ClassDef* DexFile::FindClassDef(const char* descriptor) const { + size_t num_class_defs = NumClassDefs(); + if (num_class_defs == 0) { + return NULL; } -} - -bool DexFile::FindClassDefIndex(const StringPiece& descriptor, uint32_t& idx) const { - Index::const_iterator it = index_.find(descriptor); - if (it == index_.end()) { - return false; + const StringId* string_id = FindStringId(descriptor); + if (string_id == NULL) { + return NULL; } - idx = it->second; - return true; + const TypeId* type_id = FindTypeId(GetIndexForStringId(*string_id)); + if (type_id == NULL) { + return NULL; + } + uint16_t type_idx = GetIndexForTypeId(*type_id); + for (size_t i = 0; i < num_class_defs; ++i) { + const ClassDef& class_def = GetClassDef(i); + if (class_def.class_idx_ == type_idx) { + return &class_def; + } + } + return NULL; } -const DexFile::ClassDef* DexFile::FindClassDef(const StringPiece& descriptor) const { - uint32_t idx; - if (FindClassDefIndex(descriptor, idx)) { - return &GetClassDef(idx); +const DexFile::ClassDef* DexFile::FindClassDef(uint16_t type_idx) const { + size_t num_class_defs = NumClassDefs(); + for (size_t i = 0; i < num_class_defs; ++i) { + const ClassDef& class_def = GetClassDef(i); + if (class_def.class_idx_ == type_idx) { + return &class_def; + } } return NULL; } diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 26635ae255..7be5cb848f 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -339,7 +339,7 @@ class DexFile { typedef std::vector ClassPath; // Search a collection of DexFiles for a descriptor - static ClassPathEntry FindInClassPath(const StringPiece& descriptor, + static ClassPathEntry FindInClassPath(const char* descriptor, const ClassPath& class_path); // Returns the checksum of a file for comparison with GetLocationChecksum(). @@ -376,10 +376,6 @@ class DexFile { return location_checksum_; } - // Returns a com.android.dex.Dex object corresponding to the mapped-in dex file. - // Used by managed code to implement annotations. - jobject GetDexObject(JNIEnv* env) const; - const Header& GetHeader() const { DCHECK(header_ != NULL) << GetLocation(); return *header_; @@ -584,12 +580,12 @@ class DexFile { } // Returns the ClassDef at the specified index. - const ClassDef& GetClassDef(uint32_t idx) const { + const ClassDef& GetClassDef(uint16_t idx) const { DCHECK_LT(idx, NumClassDefs()) << GetLocation(); return class_defs_[idx]; } - uint32_t GetIndexForClassDef(const ClassDef& class_def) const { + uint16_t GetIndexForClassDef(const ClassDef& class_def) const { CHECK_GE(&class_def, class_defs_) << GetLocation(); CHECK_LT(&class_def, class_defs_ + header_->class_defs_size_) << GetLocation(); return &class_def - class_defs_; @@ -601,10 +597,10 @@ class DexFile { } // Looks up a class definition by its class descriptor. - const ClassDef* FindClassDef(const StringPiece& descriptor) const; + const ClassDef* FindClassDef(const char* descriptor) const; - // Looks up a class definition index by its class descriptor. - bool FindClassDefIndex(const StringPiece& descriptor, uint32_t& idx) const; + // Looks up a class definition by its type index. + const ClassDef* FindClassDef(uint16_t type_idx) const; const TypeList* GetInterfacesList(const ClassDef& class_def) const { if (class_def.interfaces_off_ == 0) { @@ -809,6 +805,14 @@ class DexFile { bool DisableWrite() const; + const byte* Begin() const { + return begin_; + } + + size_t Size() const { + return size_; + } + private: // Opens a .dex file static const DexFile* OpenFile(const std::string& filename, @@ -840,7 +844,6 @@ class DexFile { location_(location), location_checksum_(location_checksum), mem_map_(mem_map), - dex_object_(NULL), modification_lock("DEX modification lock"), header_(0), string_ids_(0), @@ -853,23 +856,12 @@ class DexFile { CHECK_GT(size_, 0U) << GetLocation(); } - const byte* Begin() const { - return begin_; - } - - size_t Size() const { - return size_; - } - // Top-level initializer that calls other Init methods. bool Init(); // Caches pointers into to the various file sections. void InitMembers(); - // Builds the index of descriptors to class definitions. - void InitIndex(); - // Returns true if the header magic and version numbers are of the expected values. bool CheckMagicAndVersion() const; @@ -877,10 +869,6 @@ class DexFile { DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb, void* context, const byte* stream, LocalInfo* local_in_reg) const; - // The index of descriptors to class definition indexes (as opposed to type id indexes) - typedef SafeMap Index; - Index index_; - // The base address of the memory mapping. const byte* const begin_; @@ -898,10 +886,6 @@ class DexFile { // Manages the underlying memory allocation. UniquePtr mem_map_; - // A cached com.android.dex.Dex instance, possibly NULL. Use GetDexObject. - // TODO: this is mutable as it shouldn't be here. We should move it to the dex cache or similar. - mutable jobject dex_object_; - // The DEX-to-DEX compiler uses this lock to ensure thread safety when // enabling write access to a read-only DEX file. // TODO: move to Locks::dex_file_modification_lock. diff --git a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc index 1d8022f803..07c1c015aa 100644 --- a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc @@ -32,7 +32,7 @@ extern "C" uint64_t artInvokeInterfaceTrampoline(mirror::ArtMethod* interface_me Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtMethod* method; - if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex16)) { + if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) { method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method); if (UNLIKELY(method == NULL)) { FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h index 224b2ba0d4..ccf3e59f18 100644 --- a/runtime/mirror/art_method-inl.h +++ b/runtime/mirror/art_method-inl.h @@ -178,7 +178,7 @@ inline uint32_t ArtMethod::GetOatNativeGcMapOffset() const { } inline bool ArtMethod::IsRuntimeMethod() const { - return GetDexMethodIndex() == DexFile::kDexNoIndex16; + return GetDexMethodIndex() == DexFile::kDexNoIndex; } inline bool ArtMethod::IsCalleeSaveMethod() const { diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 328c67deb1..c128eded0a 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -119,7 +119,10 @@ void Class::SetDexCache(DexCache* new_dex_cache) { } void Class::SetClassSize(size_t new_class_size) { - DCHECK_GE(new_class_size, GetClassSize()) << " class=" << PrettyTypeOf(this); + if (kIsDebugBuild && (new_class_size < GetClassSize())) { + DumpClass(LOG(ERROR), kDumpClassFullDetail); + CHECK_GE(new_class_size, GetClassSize()) << " class=" << PrettyTypeOf(this); + } SetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size, false); } @@ -291,22 +294,8 @@ bool Class::IsInSamePackage(const Class* that) const { return true; } // Compare the package part of the descriptor string. - if (LIKELY(!klass1->IsProxyClass() && !klass2->IsProxyClass())) { - ClassHelper kh(klass1); - const DexFile* dex_file1 = &kh.GetDexFile(); - const DexFile::TypeId* type_id1 = &dex_file1->GetTypeId(klass1->GetDexTypeIndex()); - const char* descriptor1 = dex_file1->GetTypeDescriptor(*type_id1); - kh.ChangeClass(klass2); - const DexFile* dex_file2 = &kh.GetDexFile(); - const DexFile::TypeId* type_id2 = &dex_file2->GetTypeId(klass2->GetDexTypeIndex()); - const char* descriptor2 = dex_file2->GetTypeDescriptor(*type_id2); - return IsInSamePackage(descriptor1, descriptor2); - } - ClassHelper kh(klass1); - std::string descriptor1(kh.GetDescriptor()); - kh.ChangeClass(klass2); - std::string descriptor2(kh.GetDescriptor()); - return IsInSamePackage(descriptor1, descriptor2); + return IsInSamePackage(ClassHelper(klass1).GetDescriptor(), + ClassHelper(klass2).GetDescriptor()); } bool Class::IsClassClass() const { diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 99f3850b9b..d97b603ad8 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -726,6 +726,14 @@ class MANAGED Class : public StaticStorageBase { return GetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), false); } + uint16_t GetDexClassDefIndex() const { + return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), false); + } + + void SetDexClassDefIndex(uint16_t class_def_idx) { + SetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), class_def_idx, false); + } + uint16_t GetDexTypeIndex() const { return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), false); } @@ -807,7 +815,7 @@ class MANAGED Class : public StaticStorageBase { // If class verify fails, we must return same error on subsequent tries. Class* verify_error_class_; - // virtual methods defined in this class; invoked through vtable + // Virtual methods defined in this class; invoked through vtable. ObjectArray* virtual_methods_; // Virtual method table (vtable), for use by "invoke-virtual". The vtable from the superclass is @@ -816,24 +824,28 @@ class MANAGED Class : public StaticStorageBase { // virtual_ methods_ for miranda methods. ObjectArray* vtable_; - // access flags; low 16 bits are defined by VM spec + // Access flags; low 16 bits are defined by VM spec. uint32_t access_flags_; // Total size of the Class instance; used when allocating storage on gc heap. // See also object_size_. size_t class_size_; - // tid used to check for recursive invocation + // Tid used to check for recursive invocation. pid_t clinit_thread_id_; - // type index from dex file + // ClassDef index in dex file, -1 if no class definition such as an array. + // TODO: really 16bits + int32_t dex_class_def_idx_; + + // Type index in dex file. // TODO: really 16bits - uint32_t dex_type_idx_; + int32_t dex_type_idx_; - // number of instance fields that are object refs + // Number of instance fields that are object refs. size_t num_reference_instance_fields_; - // number of static fields that are object refs + // Number of static fields that are object refs, size_t num_reference_static_fields_; // Total object size; used when allocating storage on gc heap. @@ -841,7 +853,7 @@ class MANAGED Class : public StaticStorageBase { // See also class_size_. size_t object_size_; - // primitive type value, or Primitive::kPrimNot (0); set for generated prim classes + // Primitive type value, or Primitive::kPrimNot (0); set for generated primitive classes. Primitive::Type primitive_type_; // Bitmap of offsets of ifields. @@ -850,7 +862,7 @@ class MANAGED Class : public StaticStorageBase { // Bitmap of offsets of sfields. uint32_t reference_static_offsets_; - // state of class initialization + // State of class initialization. Status status_; // TODO: ? @@ -873,7 +885,6 @@ std::ostream& operator<<(std::ostream& os, const Class::Status& rhs); class MANAGED ClassClass : public Class { private: - int32_t padding_; int64_t serialVersionUID_; friend struct art::ClassClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ClassClass); diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index 6cfab9e425..0522f134af 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -164,6 +164,7 @@ class MANAGED DexCache : public Object { } private: + Object* dex_; ObjectArray* initialized_static_storage_; String* location_; ObjectArray* resolved_fields_; diff --git a/runtime/mirror/proxy.h b/runtime/mirror/proxy.h index 7c5bc39429..18a84dcbdb 100644 --- a/runtime/mirror/proxy.h +++ b/runtime/mirror/proxy.h @@ -25,6 +25,8 @@ struct ProxyOffsets; namespace mirror { +// All proxy objects have a class which is a synthesized proxy class. The synthesized proxy class +// has the static fields used to implement reflection on proxy objects. class MANAGED SynthesizedProxyClass : public Class { public: ObjectArray* GetInterfaces() { @@ -41,6 +43,7 @@ class MANAGED SynthesizedProxyClass : public Class { DISALLOW_IMPLICIT_CONSTRUCTORS(SynthesizedProxyClass); }; +// C++ mirror of java.lang.reflect.Proxy. class MANAGED Proxy : public Object { private: Object* h_; diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index 01d8f318ff..1879f04bef 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -156,8 +156,8 @@ class MANAGED StringClass : public Class { private: CharArray* ASCII_; Object* CASE_INSENSITIVE_ORDER_; - uint32_t REPLACEMENT_CHAR_; int64_t serialVersionUID_; + uint32_t REPLACEMENT_CHAR_; friend struct art::StringClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(StringClass); }; diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 2f4e427bb6..d2a6c0edb4 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -150,7 +150,7 @@ static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, j return NULL; } const std::string descriptor(DotToDescriptor(class_name.c_str())); - const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor); + const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str()); if (dex_class_def == NULL) { VLOG(class_linker) << "Failed to find dex_class_def"; return NULL; diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index a7296996da..d3011cb013 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -78,35 +78,6 @@ static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean return soa.AddLocalReference(c); } -static jint Class_getAnnotationDirectoryOffset(JNIEnv* env, jclass javaClass) { - ScopedObjectAccess soa(env); - mirror::Class* c = DecodeClass(soa, javaClass); - if (c->IsPrimitive() || c->IsArrayClass() || c->IsProxyClass()) { - return 0; // primitive, array and proxy classes don't have class definitions - } - const DexFile::ClassDef* class_def = ClassHelper(c).GetClassDef(); - if (class_def == NULL) { - return 0; // not found - } else { - return class_def->annotations_off_; - } -} - -static jobject Class_getDex(JNIEnv* env, jobject javaClass) { - ScopedObjectAccess soa(env); - mirror::Class* c = DecodeClass(soa, javaClass); - - mirror::DexCache* dex_cache = c->GetDexCache(); - if (dex_cache == NULL) { - return NULL; - } - const DexFile* dex_file = dex_cache->GetDexFile(); - if (dex_file == NULL) { - return NULL; - } - return dex_file->GetDexObject(env); -} - static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) { ScopedObjectAccess soa(env); mirror::Class* c = DecodeClass(soa, javaThis); @@ -122,8 +93,6 @@ static jobjectArray Class_getProxyInterfaces(JNIEnv* env, jobject javaThis) { static JNINativeMethod gMethods[] = { NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"), - NATIVE_METHOD(Class, getAnnotationDirectoryOffset, "()I"), - NATIVE_METHOD(Class, getDex, "()Lcom/android/dex/Dex;"), NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"), NATIVE_METHOD(Class, getProxyInterfaces, "()[Ljava/lang/Class;"), }; diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc new file mode 100644 index 0000000000..f8eeb2906e --- /dev/null +++ b/runtime/native/java_lang_DexCache.cc @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dex_file.h" +#include "mirror/dex_cache.h" +#include "mirror/object-inl.h" +#include "scoped_thread_state_change.h" +#include "well_known_classes.h" + +namespace art { + +static jobject DexCache_getDexNative(JNIEnv* env, jobject javaDexCache) { + ScopedObjectAccess soa(env); + mirror::DexCache* dex_cache = soa.Decode(javaDexCache); + // Should only be called while holding the lock on the dex cache. + DCHECK_EQ(dex_cache->GetThinLockId(), soa.Self()->GetThinLockId()); + const DexFile* dex_file = dex_cache->GetDexFile(); + if (dex_file == NULL) { + return NULL; + } + void* address = const_cast(reinterpret_cast(dex_file->Begin())); + jobject byte_buffer = env->NewDirectByteBuffer(address, dex_file->Size()); + if (byte_buffer == NULL) { + DCHECK(soa.Self()->IsExceptionPending()); + return NULL; + } + + jvalue args[1]; + args[0].l = byte_buffer; + return env->CallStaticObjectMethodA(WellKnownClasses::com_android_dex_Dex, + WellKnownClasses::com_android_dex_Dex_create, + args); +} + +static JNINativeMethod gMethods[] = { + NATIVE_METHOD(DexCache, getDexNative, "()Lcom/android/dex/Dex;"), +}; + +void register_java_lang_DexCache(JNIEnv* env) { + REGISTER_NATIVE_METHODS("java/lang/DexCache"); +} + +} // namespace art diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index afa823dbd9..4c970172b4 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -365,7 +365,7 @@ const DexFile* OatFile::OatDexFile::OpenDexFile() const { dex_file_location_checksum_); } -const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const { +const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) const { uint32_t oat_class_offset = oat_class_offsets_pointer_[class_def_index]; const byte* oat_class_pointer = oat_file_->Begin() + oat_class_offset; diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 325ebb2914..bbd2615b66 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -183,7 +183,7 @@ class OatFile { } // Returns the OatClass for the class specified by the given DexFile class_def_index. - const OatClass* GetOatClass(uint32_t class_def_index) const; + const OatClass* GetOatClass(uint16_t class_def_index) const; ~OatDexFile(); diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 29102437a2..6ee3016179 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -68,8 +68,7 @@ class ClassHelper { public: ClassHelper(const mirror::Class* c = NULL, ClassLinker* l = NULL) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - : class_def_(NULL), - class_linker_(l), + : class_linker_(l), dex_cache_(NULL), dex_file_(NULL), interface_type_list_(NULL), @@ -92,7 +91,6 @@ class ClassHelper { } klass_ = new_c; interface_type_list_ = NULL; - class_def_ = NULL; } // The returned const char* is only guaranteed to be valid for the lifetime of the ClassHelper. @@ -108,7 +106,7 @@ class ClassHelper { return descriptor_.c_str(); } else { const DexFile& dex_file = GetDexFile(); - const DexFile::TypeId& type_id = dex_file.GetTypeId(klass_->GetDexTypeIndex()); + const DexFile::TypeId& type_id = dex_file.GetTypeId(GetClassDef()->class_idx_); return dex_file.GetTypeDescriptor(type_id); } } @@ -124,14 +122,13 @@ class ClassHelper { return descriptor_.c_str(); } - const DexFile::ClassDef* GetClassDef() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const DexFile::ClassDef* result = class_def_; - if (result == NULL) { - result = GetDexFile().FindClassDef(GetDescriptor()); - class_def_ = result; + const DexFile::ClassDef* GetClassDef() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(klass_ != nullptr); + uint16_t class_def_idx = klass_->GetDexClassDefIndex(); + if (class_def_idx == DexFile::kDexNoIndex16) { + return nullptr; } - return result; + return &GetDexFile().GetClassDef(class_def_idx); } uint32_t NumDirectInterfaces() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -187,7 +184,7 @@ class ClassHelper { const char* GetSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { std::string descriptor(GetDescriptor()); const DexFile& dex_file = GetDexFile(); - const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor); + const DexFile::ClassDef* dex_class_def = GetClassDef(); CHECK(dex_class_def != NULL); return dex_file.GetSourceFile(*dex_class_def); } @@ -242,7 +239,6 @@ class ClassHelper { return result; } - const DexFile::ClassDef* class_def_; ClassLinker* class_linker_; mirror::DexCache* dex_cache_; const DexFile* dex_file_; @@ -327,12 +323,15 @@ class FieldHelper { // If you need it longer, copy it into a std::string. const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - uint16_t type_idx = field_->GetDeclaringClass()->GetDexTypeIndex(); - if (type_idx != DexFile::kDexNoIndex16) { + uint32_t field_index = field_->GetDexFieldIndex(); + if (!field_->GetDeclaringClass()->IsProxyClass()) { const DexFile& dex_file = GetDexFile(); - return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)); + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); + return dex_file.GetFieldDeclaringClassDescriptor(field_id); } else { - // Most likely a proxy class. + DCHECK(field_->IsStatic()); + DCHECK_LT(field_index, 2U); + // 0 == Class[] interfaces; 1 == Class[][] throws; ClassHelper kh(field_->GetDeclaringClass()); declaring_class_descriptor_ = kh.GetDescriptor(); return declaring_class_descriptor_.c_str(); @@ -418,7 +417,7 @@ class MethodHelper { const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); uint32_t dex_method_idx = method_->GetDexMethodIndex(); - if (dex_method_idx != DexFile::kDexNoIndex16) { + if (dex_method_idx != DexFile::kDexNoIndex) { return dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx)); } else { Runtime* runtime = Runtime::Current(); @@ -464,21 +463,19 @@ class MethodHelper { const std::string GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); uint32_t dex_method_idx = method_->GetDexMethodIndex(); - if (dex_method_idx != DexFile::kDexNoIndex16) { + if (dex_method_idx != DexFile::kDexNoIndex) { return dex_file.GetMethodSignature(dex_file.GetMethodId(dex_method_idx)); } else { return ""; } } - const DexFile::ProtoId& GetPrototype() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile::ProtoId& GetPrototype() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); return dex_file.GetMethodPrototype(dex_file.GetMethodId(method_->GetDexMethodIndex())); } - const DexFile::TypeList* GetParameterTypeList() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile::TypeList* GetParameterTypeList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile::ProtoId& proto = GetPrototype(); return GetDexFile().GetProtoParameters(proto); } @@ -491,8 +488,7 @@ class MethodHelper { return GetClassFromTypeIdx(return_type_idx); } - const char* GetReturnTypeDescriptor() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const char* GetReturnTypeDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); const DexFile::MethodId& method_id = dex_file.GetMethodId(method_->GetDexMethodIndex()); const DexFile::ProtoId& proto_id = dex_file.GetMethodPrototype(method_id); @@ -500,8 +496,7 @@ class MethodHelper { return dex_file.GetTypeDescriptor(dex_file.GetTypeId(return_type_idx)); } - int32_t GetLineNumFromDexPC(uint32_t dex_pc) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + int32_t GetLineNumFromDexPC(uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (dex_pc == DexFile::kDexNoIndex) { return method_->IsNative() ? -2 : -1; } else { @@ -510,35 +505,29 @@ class MethodHelper { } } - const char* GetDeclaringClassDescriptor() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::Class* klass = method_->GetDeclaringClass(); - DCHECK(!klass->IsProxyClass()); - uint16_t type_idx = klass->GetDexTypeIndex(); + const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); - return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)); + uint32_t dex_method_idx = method_->GetDexMethodIndex(); + if (dex_method_idx != DexFile::kDexNoIndex) { + return dex_file.GetMethodDeclaringClassDescriptor(dex_file.GetMethodId(dex_method_idx)); + } else { + return ""; + } } - const char* GetDeclaringClassSourceFile() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const char* descriptor = GetDeclaringClassDescriptor(); - const DexFile& dex_file = GetDexFile(); - const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor); - CHECK(dex_class_def != NULL); - return dex_file.GetSourceFile(*dex_class_def); + const char* GetDeclaringClassSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return ClassHelper(method_->GetDeclaringClass()).GetSourceFile(); } - uint32_t GetClassDefIndex() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const char* descriptor = GetDeclaringClassDescriptor(); - const DexFile& dex_file = GetDexFile(); - uint32_t index; - CHECK(dex_file.FindClassDefIndex(descriptor, index)); - return index; + uint16_t GetClassDefIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return method_->GetDeclaringClass()->GetDexClassDefIndex(); } - mirror::ClassLoader* GetClassLoader() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile::ClassDef& GetClassDef() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetDexFile().GetClassDef(GetClassDefIndex()); + } + + mirror::ClassLoader* GetClassLoader() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return method_->GetDeclaringClass()->GetClassLoader(); } diff --git a/runtime/runtime.cc b/runtime/runtime.cc index c37b7830c8..05f4566d85 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1007,6 +1007,7 @@ void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) { REGISTER(register_dalvik_system_VMStack); REGISTER(register_dalvik_system_Zygote); REGISTER(register_java_lang_Class); + REGISTER(register_java_lang_DexCache); REGISTER(register_java_lang_Object); REGISTER(register_java_lang_Runtime); REGISTER(register_java_lang_String); @@ -1175,7 +1176,7 @@ mirror::ArtMethod* Runtime::CreateResolutionMethod() { method(self, down_cast(method_class->AllocObject(self))); method->SetDeclaringClass(method_class); // TODO: use a special method for resolution method saves - method->SetDexMethodIndex(DexFile::kDexNoIndex16); + method->SetDexMethodIndex(DexFile::kDexNoIndex); // When compiling, the code pointer will get set later when the image is loaded. Runtime* r = Runtime::Current(); ClassLinker* cl = r->GetClassLinker(); @@ -1191,7 +1192,7 @@ mirror::ArtMethod* Runtime::CreateCalleeSaveMethod(InstructionSet instruction_se method(self, down_cast(method_class->AllocObject(self))); method->SetDeclaringClass(method_class); // TODO: use a special method for callee saves - method->SetDexMethodIndex(DexFile::kDexNoIndex16); + method->SetDexMethodIndex(DexFile::kDexNoIndex); method->SetEntryPointFromCompiledCode(NULL); if ((instruction_set == kThumb2) || (instruction_set == kArm)) { uint32_t ref_spills = (1 << art::arm::R5) | (1 << art::arm::R6) | (1 << art::arm::R7) | diff --git a/runtime/thread.cc b/runtime/thread.cc index d7d4b1fa97..68370508d3 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1816,7 +1816,7 @@ class CatchBlockStackVisitor : public StackVisitor { uint32_t new_dex_pc = dex_pc + inst->SizeInCodeUnits(); ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, m, new_dex_pc); verifier::MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), - mh.GetClassDefIndex(), code_item, + &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, true); verifier.Verify(); std::vector kinds = verifier.DescribeVRegs(dex_pc); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index fa00c61017..9811926b16 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -74,50 +74,51 @@ void PcToRegisterLineTable::Init(RegisterTrackingMode mode, InstructionFlags* fl } MethodVerifier::FailureKind MethodVerifier::VerifyClass(const mirror::Class* klass, - std::string& error, - bool allow_soft_failures) { + bool allow_soft_failures, + std::string* error) { if (klass->IsVerified()) { return kNoFailure; } mirror::Class* super = klass->GetSuperClass(); if (super == NULL && StringPiece(ClassHelper(klass).GetDescriptor()) != "Ljava/lang/Object;") { - error = "Verifier rejected class "; - error += PrettyDescriptor(klass); - error += " that has no super class"; + *error = "Verifier rejected class "; + *error += PrettyDescriptor(klass); + *error += " that has no super class"; return kHardFailure; } if (super != NULL && super->IsFinal()) { - error = "Verifier rejected class "; - error += PrettyDescriptor(klass); - error += " that attempts to sub-class final class "; - error += PrettyDescriptor(super); + *error = "Verifier rejected class "; + *error += PrettyDescriptor(klass); + *error += " that attempts to sub-class final class "; + *error += PrettyDescriptor(super); return kHardFailure; } ClassHelper kh(klass); const DexFile& dex_file = kh.GetDexFile(); - uint32_t class_def_idx; - if (!dex_file.FindClassDefIndex(kh.GetDescriptor(), class_def_idx)) { - error = "Verifier rejected class "; - error += PrettyDescriptor(klass); - error += " that isn't present in dex file "; - error += dex_file.GetLocation(); + const DexFile::ClassDef* class_def = kh.GetClassDef(); + if (class_def == NULL) { + *error = "Verifier rejected class "; + *error += PrettyDescriptor(klass); + *error += " that isn't present in dex file "; + *error += dex_file.GetLocation(); return kHardFailure; } return VerifyClass(&dex_file, kh.GetDexCache(), klass->GetClassLoader(), - class_def_idx, error, - allow_soft_failures); + class_def, + allow_soft_failures, + error); } MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, mirror::DexCache* dex_cache, mirror::ClassLoader* class_loader, - uint32_t class_def_idx, - std::string& error, - bool allow_soft_failures) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx); - const byte* class_data = dex_file->GetClassData(class_def); + const DexFile::ClassDef* class_def, + bool allow_soft_failures, + std::string* error) { + DCHECK(class_def != nullptr); + const byte* class_data = dex_file->GetClassData(*class_def); if (class_data == NULL) { // empty class, probably a marker interface return kNoFailure; @@ -139,7 +140,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, continue; } previous_direct_method_idx = method_idx; - InvokeType type = it.GetMethodInvokeType(class_def); + InvokeType type = it.GetMethodInvokeType(*class_def); mirror::ArtMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader, NULL, type); if (method == NULL) { @@ -151,7 +152,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, dex_file, dex_cache, class_loader, - class_def_idx, + class_def, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags(), @@ -160,12 +161,12 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, if (result == kHardFailure) { hard_fail = true; if (error_count > 0) { - error += "\n"; + *error += "\n"; } - error = "Verifier rejected class "; - error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - error += " due to bad method "; - error += PrettyMethod(method_idx, *dex_file); + *error = "Verifier rejected class "; + *error += PrettyDescriptor(dex_file->GetClassDescriptor(*class_def)); + *error += " due to bad method "; + *error += PrettyMethod(method_idx, *dex_file); } ++error_count; } @@ -181,7 +182,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, continue; } previous_virtual_method_idx = method_idx; - InvokeType type = it.GetMethodInvokeType(class_def); + InvokeType type = it.GetMethodInvokeType(*class_def); mirror::ArtMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader, NULL, type); if (method == NULL) { @@ -193,7 +194,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, dex_file, dex_cache, class_loader, - class_def_idx, + class_def, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags(), @@ -202,12 +203,12 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, if (result == kHardFailure) { hard_fail = true; if (error_count > 0) { - error += "\n"; + *error += "\n"; } - error = "Verifier rejected class "; - error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - error += " due to bad method "; - error += PrettyMethod(method_idx, *dex_file); + *error = "Verifier rejected class "; + *error += PrettyDescriptor(dex_file->GetClassDescriptor(*class_def)); + *error += " due to bad method "; + *error += PrettyMethod(method_idx, *dex_file); } ++error_count; } @@ -224,7 +225,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, const DexFile* dex_file, mirror::DexCache* dex_cache, mirror::ClassLoader* class_loader, - uint32_t class_def_idx, + const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags, @@ -232,7 +233,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, MethodVerifier::FailureKind result = kNoFailure; uint64_t start_ns = NanoTime(); - MethodVerifier verifier_(dex_file, dex_cache, class_loader, class_def_idx, code_item, method_idx, + MethodVerifier verifier_(dex_file, dex_cache, class_loader, class_def, code_item, method_idx, method, method_access_flags, true, allow_soft_failures); if (verifier_.Verify()) { // Verification completed, however failures may be pending that didn't cause the verification @@ -267,11 +268,12 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_idx, const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, + mirror::ClassLoader* class_loader, + const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags) { - MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item, + MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def, code_item, dex_method_idx, method, method_access_flags, true, true); verifier.Verify(); verifier.DumpFailures(os); @@ -280,7 +282,8 @@ void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_i } MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, + mirror::ClassLoader* class_loader, + const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, uint32_t dex_method_idx, mirror::ArtMethod* method, uint32_t method_access_flags, bool can_load_classes, @@ -293,7 +296,7 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_ca dex_file_(dex_file), dex_cache_(dex_cache), class_loader_(class_loader), - class_def_idx_(class_def_idx), + class_def_(class_def), code_item_(code_item), declaring_class_(NULL), interesting_dex_pc_(-1), @@ -306,13 +309,14 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_ca allow_soft_failures_(allow_soft_failures), has_check_casts_(false), has_virtual_or_interface_invokes_(false) { + DCHECK(class_def != NULL); } void MethodVerifier::FindLocksAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc, std::vector& monitor_enter_dex_pcs) { MethodHelper mh(m); MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), - mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(), + &mh.GetClassDef(), mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, true); verifier.interesting_dex_pc_ = dex_pc; verifier.monitor_enter_dex_pcs_ = &monitor_enter_dex_pcs; @@ -334,7 +338,7 @@ mirror::ArtField* MethodVerifier::FindAccessedFieldAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc) { MethodHelper mh(m); MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), - mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(), + &mh.GetClassDef(), mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, true); return verifier.FindAccessedFieldAtDexPc(dex_pc); } @@ -362,7 +366,7 @@ mirror::ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(mirror::ArtMethod* m uint32_t dex_pc) { MethodHelper mh(m); MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), - mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(), + &mh.GetClassDef(), mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, true); return verifier.FindInvokedMethodAtDexPc(dex_pc); } @@ -448,7 +452,7 @@ std::ostream& MethodVerifier::Fail(VerifyError error) { // marked as rejected to prevent it from being compiled. case VERIFY_ERROR_BAD_CLASS_HARD: { if (Runtime::Current()->IsCompiler()) { - ClassReference ref(dex_file_, class_def_idx_); + ClassReference ref(dex_file_, dex_file_->GetIndexForClassDef(*class_def_)); AddRejectedClass(ref); } have_pending_hard_failure_ = true; diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 70442fbc04..073a2f76be 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -145,17 +145,19 @@ class MethodVerifier { }; /* Verify a class. Returns "kNoFailure" on success. */ - static FailureKind VerifyClass(const mirror::Class* klass, std::string& error, - bool allow_soft_failures) + static FailureKind VerifyClass(const mirror::Class* klass, bool allow_soft_failures, + std::string* error) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static FailureKind VerifyClass(const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, - std::string& error, bool allow_soft_failures) + mirror::ClassLoader* class_loader, + const DexFile::ClassDef* class_def, + bool allow_soft_failures, std::string* error) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static void VerifyMethodAndDump(std::ostream& os, uint32_t method_idx, const DexFile* dex_file, mirror::DexCache* dex_cache, mirror::ClassLoader* class_loader, - uint32_t class_def_idx, const DexFile::CodeItem* code_item, + const DexFile::ClassDef* class_def, + const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -222,7 +224,7 @@ class MethodVerifier { } MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, + mirror::ClassLoader* class_loader, const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, uint32_t method_idx, mirror::ArtMethod* method, uint32_t access_flags, bool can_load_classes, bool allow_soft_failures) @@ -262,7 +264,8 @@ class MethodVerifier { */ static FailureKind VerifyMethod(uint32_t method_idx, const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, + mirror::ClassLoader* class_loader, + const DexFile::ClassDef* class_def_idx, const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags, bool allow_soft_failures) @@ -690,7 +693,7 @@ class MethodVerifier { mirror::DexCache* dex_cache_ GUARDED_BY(Locks::mutator_lock_); // The class loader for the declaring class of the method. mirror::ClassLoader* class_loader_ GUARDED_BY(Locks::mutator_lock_); - const uint32_t class_def_idx_; // The class def index of the declaring class of the method. + const DexFile::ClassDef* const class_def_; // The class def of the declaring class of the method. const DexFile::CodeItem* const code_item_; // The code item containing the code for the method. const RegType* declaring_class_; // Lazily computed reg type of the method's declaring class. // Instruction widths and flags, one entry per code unit. diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc index 611b7c06eb..a56abba3cf 100644 --- a/runtime/verifier/method_verifier_test.cc +++ b/runtime/verifier/method_verifier_test.cc @@ -34,7 +34,8 @@ class MethodVerifierTest : public CommonTest { // Verify the class std::string error_msg; - ASSERT_TRUE(MethodVerifier::VerifyClass(klass, error_msg, true) == MethodVerifier::kNoFailure) << error_msg; + ASSERT_TRUE(MethodVerifier::VerifyClass(klass, true, &error_msg) == MethodVerifier::kNoFailure) + << error_msg; } void VerifyDexFile(const DexFile* dex) diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt index 3d87ebc559..967f167f37 100644 --- a/test/100-reflect2/expected.txt +++ b/test/100-reflect2/expected.txt @@ -35,7 +35,7 @@ z (class java.lang.Character) 62 (class java.lang.Long) 14 (class java.lang.Short) [public java.lang.String(), java.lang.String(int,int,char[]), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int)] -[private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final char java.lang.String.REPLACEMENT_CHAR, private static final long java.lang.String.serialVersionUID] +[private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final long java.lang.String.serialVersionUID, private static final char java.lang.String.REPLACEMENT_CHAR] [void java.lang.String._getChars(int,int,char[],int), public char java.lang.String.charAt(int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public volatile int java.lang.String.compareTo(java.lang.Object), public native int java.lang.String.compareTo(java.lang.String), public int java.lang.String.compareToIgnoreCase(java.lang.String), public java.lang.String java.lang.String.concat(java.lang.String), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public void java.lang.String.getBytes(int,int,byte[],int), public [B java.lang.String.getBytes(), public [B java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public [B java.lang.String.getBytes(java.nio.charset.Charset), public void java.lang.String.getChars(int,int,char[],int), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public native java.lang.String java.lang.String.intern(), public boolean java.lang.String.isEmpty(), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public boolean java.lang.String.matches(java.lang.String), public int java.lang.String.offsetByCodePoints(int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public [C java.lang.String.toCharArray(), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.failedBoundsCheck(int,int,int), private native int java.lang.String.fastIndexOf(int,int), private char java.lang.String.foldCase(char), public static transient java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static transient java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), private java.lang.StringIndexOutOfBoundsException java.lang.String.indexAndLength(int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int,int,char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.startEndAndLength(int,int), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(long), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int)] [] [interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence] -- cgit v1.2.3-59-g8ed1b From d91d6d6a80748f277fd938a412211e5af28913b1 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 25 Sep 2013 20:26:14 -0700 Subject: Introduce Signature type to avoid string comparisons. Method resolution currently creates strings to then compare with strings formed from methods in other dex files. The temporary strings are purely created for the sake of comparisons. This change creates a new Signature type that represents a method signature but not as a string. This type supports comparisons and so can be used when searching for methods in resolution. With this change malloc is no longer the hottest method during dex2oat (now its memset) and allocations during verification have been reduced. The verifier is commonly what is populating the dex cache for methods and fields not declared in the dex file itself. Change-Id: I5ef0542823fbcae868aaa4a2457e8da7df0e9dae --- compiler/dex/quick/codegen_util.cc | 12 +-- compiler/dex/quick/mir_to_lir.h | 4 +- compiler/driver/compiler_driver.cc | 5 +- runtime/class_linker.cc | 22 ++--- runtime/class_linker_test.cc | 21 ++--- runtime/common_throws.cc | 2 +- runtime/common_throws.h | 3 +- runtime/debugger.cc | 2 +- runtime/dex_file-inl.h | 4 + runtime/dex_file.cc | 66 ++++++++------- runtime/dex_file.h | 95 ++++++++++++++++++++-- runtime/dex_file_test.cc | 27 +++--- runtime/jni_internal.cc | 1 + runtime/mirror/class.cc | 64 ++++++++++++++- runtime/mirror/class.h | 35 +++++--- runtime/object_utils.h | 41 +--------- runtime/trace.cc | 2 +- runtime/utils.cc | 22 +++-- runtime/verifier/method_verifier.cc | 4 +- test/Android.mk | 2 +- .../CreateMethodSignature.java | 20 ----- test/GetMethodSignature/GetMethodSignature.java | 20 +++++ 22 files changed, 301 insertions(+), 173 deletions(-) delete mode 100644 test/CreateMethodSignature/CreateMethodSignature.java create mode 100644 test/GetMethodSignature/GetMethodSignature.java (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 4ce752fb39..6e49f0bc54 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -248,12 +248,12 @@ void Mir2Lir::DumpPromotionMap() { } /* Dump a mapping table */ -void Mir2Lir::DumpMappingTable(const char* table_name, const std::string& descriptor, - const std::string& name, const std::string& signature, +void Mir2Lir::DumpMappingTable(const char* table_name, const char* descriptor, + const char* name, const Signature& signature, const std::vector& v) { if (v.size() > 0) { std::string line(StringPrintf("\n %s %s%s_%s_table[%zu] = {", table_name, - descriptor.c_str(), name.c_str(), signature.c_str(), v.size())); + descriptor, name, signature.ToString().c_str(), v.size())); std::replace(line.begin(), line.end(), ';', '_'); LOG(INFO) << line; for (uint32_t i = 0; i < v.size(); i+=2) { @@ -293,9 +293,9 @@ void Mir2Lir::CodegenDump() { const DexFile::MethodId& method_id = cu_->dex_file->GetMethodId(cu_->method_idx); - std::string signature(cu_->dex_file->GetMethodSignature(method_id)); - std::string name(cu_->dex_file->GetMethodName(method_id)); - std::string descriptor(cu_->dex_file->GetMethodDeclaringClassDescriptor(method_id)); + const Signature signature = cu_->dex_file->GetMethodSignature(method_id); + const char* name = cu_->dex_file->GetMethodName(method_id); + const char* descriptor(cu_->dex_file->GetMethodDeclaringClassDescriptor(method_id)); // Dump mapping tables DumpMappingTable("PC2Dex_MappingTable", descriptor, name, signature, pc2dex_mapping_table_); diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 401e3d5f93..7d6f968da5 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -283,8 +283,8 @@ class Mir2Lir : public Backend { bool EvaluateBranch(Instruction::Code opcode, int src1, int src2); bool IsInexpensiveConstant(RegLocation rl_src); ConditionCode FlipComparisonOrder(ConditionCode before); - void DumpMappingTable(const char* table_name, const std::string& descriptor, - const std::string& name, const std::string& signature, + void DumpMappingTable(const char* table_name, const char* descriptor, + const char* name, const Signature& signature, const std::vector& v); void InstallLiteralPools(); void InstallSwitchTables(); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index e227715605..056be1fb04 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1227,8 +1227,9 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui if (name != NULL) { uint16_t return_type_idx; std::vector param_type_idxs; - bool success = dexfile->CreateTypeList(&return_type_idx, ¶m_type_idxs, - cm_dexfile->GetMethodSignature(cm_method_id)); + bool success = + dexfile->CreateTypeList(cm_dexfile->GetMethodSignature(cm_method_id).ToString(), + &return_type_idx, ¶m_type_idxs); if (success) { const DexFile::ProtoId* sig = dexfile->FindProtoId(return_type_idx, param_type_idxs); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 6aae63ee2c..17a179f2d9 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -2823,12 +2823,12 @@ static void CheckProxyConstructor(mirror::ArtMethod* constructor) CHECK(constructor->IsConstructor()); MethodHelper mh(constructor); CHECK_STREQ(mh.GetName(), ""); - CHECK_EQ(mh.GetSignature(), std::string("(Ljava/lang/reflect/InvocationHandler;)V")); + CHECK_STREQ(mh.GetSignature().ToString().c_str(), "(Ljava/lang/reflect/InvocationHandler;)V"); DCHECK(constructor->IsPublic()); } mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self, SirtRef& klass, - SirtRef& prototype) { + SirtRef& prototype) { // Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden // prototype method prototype->GetDeclaringClass()->GetDexCache()->SetResolvedMethod(prototype->GetDexMethodIndex(), @@ -2892,7 +2892,7 @@ static bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics, } if (!can_init_statics) { // Check if there's a class initializer. - mirror::ArtMethod* clinit = klass->FindDeclaredDirectMethod("", "()V"); + mirror::ArtMethod* clinit = klass->FindClassInitializer(); if (clinit != NULL) { return false; } @@ -3039,7 +3039,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, } } - mirror::ArtMethod* clinit = klass->FindDeclaredDirectMethod("", "()V"); + mirror::ArtMethod* clinit = klass->FindClassInitializer(); if (clinit != NULL) { CHECK(can_init_statics); if (LIKELY(Runtime::Current()->IsStarted())) { @@ -3992,11 +3992,11 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, } mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, - uint32_t method_idx, - mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, - const mirror::ArtMethod* referrer, - InvokeType type) { + uint32_t method_idx, + mirror::DexCache* dex_cache, + mirror::ClassLoader* class_loader, + const mirror::ArtMethod* referrer, + InvokeType type) { DCHECK(dex_cache != NULL); // Check for hit in the dex cache. mirror::ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx); @@ -4031,7 +4031,7 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, if (resolved == NULL) { // Search by name, which works across dex files. const char* name = dex_file.StringDataByIdx(method_id.name_idx_); - std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL)); + const Signature signature = dex_file.GetMethodSignature(method_id); switch (type) { case kDirect: // Fall-through. case kStatic: @@ -4061,7 +4061,7 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, // We failed to find the method which means either an access error, an incompatible class // change, or no such method. First try to find the method among direct and virtual methods. const char* name = dex_file.StringDataByIdx(method_id.name_idx_); - std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL)); + const Signature signature = dex_file.GetMethodSignature(method_id); switch (type) { case kDirect: case kStatic: diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index bea1139679..ad9347fee1 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -152,7 +152,7 @@ class ClassLinkerTest : public CommonTest { EXPECT_TRUE(method != NULL); EXPECT_TRUE(method->GetClass() != NULL); EXPECT_TRUE(mh.GetName() != NULL); - EXPECT_TRUE(mh.GetSignature() != NULL); + EXPECT_TRUE(mh.GetSignature() != Signature::NoSignature()); EXPECT_TRUE(method->GetDexCacheStrings() != NULL); EXPECT_TRUE(method->GetDexCacheResolvedMethods() != NULL); @@ -942,15 +942,16 @@ TEST_F(ClassLinkerTest, Interfaces) { EXPECT_TRUE(K->IsAssignableFrom(B)); EXPECT_TRUE(J->IsAssignableFrom(B)); - mirror::ArtMethod* Ii = I->FindVirtualMethod("i", "()V"); - mirror::ArtMethod* Jj1 = J->FindVirtualMethod("j1", "()V"); - mirror::ArtMethod* Jj2 = J->FindVirtualMethod("j2", "()V"); - mirror::ArtMethod* Kj1 = K->FindInterfaceMethod("j1", "()V"); - mirror::ArtMethod* Kj2 = K->FindInterfaceMethod("j2", "()V"); - mirror::ArtMethod* Kk = K->FindInterfaceMethod("k", "()V"); - mirror::ArtMethod* Ai = A->FindVirtualMethod("i", "()V"); - mirror::ArtMethod* Aj1 = A->FindVirtualMethod("j1", "()V"); - mirror::ArtMethod* Aj2 = A->FindVirtualMethod("j2", "()V"); + const Signature void_sig = I->GetDexCache()->GetDexFile()->CreateSignature("()V"); + mirror::ArtMethod* Ii = I->FindVirtualMethod("i", void_sig); + mirror::ArtMethod* Jj1 = J->FindVirtualMethod("j1", void_sig); + mirror::ArtMethod* Jj2 = J->FindVirtualMethod("j2", void_sig); + mirror::ArtMethod* Kj1 = K->FindInterfaceMethod("j1", void_sig); + mirror::ArtMethod* Kj2 = K->FindInterfaceMethod("j2", void_sig); + mirror::ArtMethod* Kk = K->FindInterfaceMethod("k", void_sig); + mirror::ArtMethod* Ai = A->FindVirtualMethod("i", void_sig); + mirror::ArtMethod* Aj1 = A->FindVirtualMethod("j1", void_sig); + mirror::ArtMethod* Aj2 = A->FindVirtualMethod("j2", void_sig); ASSERT_TRUE(Ii != NULL); ASSERT_TRUE(Jj1 != NULL); ASSERT_TRUE(Jj2 != NULL); diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index 26ce5be1ec..189e3edc0f 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -265,7 +265,7 @@ void ThrowNoSuchFieldError(const StringPiece& scope, mirror::Class* c, // NoSuchMethodError void ThrowNoSuchMethodError(InvokeType type, mirror::Class* c, const StringPiece& name, - const StringPiece& signature) { + const Signature& signature) { std::ostringstream msg; ClassHelper kh(c); msg << "No " << type << " method " << name << signature diff --git a/runtime/common_throws.h b/runtime/common_throws.h index 99c6343cdd..1d77e2d625 100644 --- a/runtime/common_throws.h +++ b/runtime/common_throws.h @@ -27,6 +27,7 @@ class ArtMethod; class Class; class Object; } // namespace mirror +class Signature; class StringPiece; class ThrowLocation; @@ -140,7 +141,7 @@ void ThrowNoSuchFieldError(const StringPiece& scope, mirror::Class* c, // NoSuchMethodError void ThrowNoSuchMethodError(InvokeType type, mirror::Class* c, const StringPiece& name, - const StringPiece& signature) + const Signature& signature) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void ThrowNoSuchMethodError(uint32_t method_idx) diff --git a/runtime/debugger.cc b/runtime/debugger.cc index e57137fb96..ae57aa34ec 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -1287,7 +1287,7 @@ JDWP::JdwpError Dbg::OutputDeclaredMethods(JDWP::RefTypeId class_id, bool with_g MethodHelper mh(m); expandBufAddMethodId(pReply, ToMethodId(m)); expandBufAddUtf8String(pReply, mh.GetName()); - expandBufAddUtf8String(pReply, mh.GetSignature()); + expandBufAddUtf8String(pReply, mh.GetSignature().ToString()); if (with_generic) { static const char genericSignature[1] = ""; expandBufAddUtf8String(pReply, genericSignature); diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h index 2ee9244bf2..c57a1e7582 100644 --- a/runtime/dex_file-inl.h +++ b/runtime/dex_file-inl.h @@ -47,6 +47,10 @@ inline StringPiece DexFile::StringDataAsStringPieceByIdx(uint32_t idx) const { return StringPiece(data, static_cast(length)); } +inline const Signature DexFile::GetMethodSignature(const MethodId& method_id) const { + return Signature(this, GetProtoId(method_id.proto_idx_)); +} + inline const DexFile::TryItem* DexFile::GetTryItems(const CodeItem& code_item, uint32_t offset) { const uint16_t* insns_end_ = &code_item.insns_[code_item.insns_size_in_code_units_]; return reinterpret_cast diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 098ab674f4..275dcc5a03 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -503,8 +503,8 @@ const DexFile::ProtoId* DexFile::FindProtoId(uint16_t return_type_idx, } // Given a signature place the type ids into the given vector -bool DexFile::CreateTypeList(uint16_t* return_type_idx, std::vector* param_type_idxs, - const std::string& signature) const { +bool DexFile::CreateTypeList(const StringPiece& signature, uint16_t* return_type_idx, + std::vector* param_type_idxs) const { if (signature[0] != '(') { return false; } @@ -518,6 +518,7 @@ bool DexFile::CreateTypeList(uint16_t* return_type_idx, std::vector* p process_return = true; continue; } + // TODO: avoid building a string. std::string descriptor; descriptor += c; while (c == '[') { // process array prefix @@ -557,35 +558,18 @@ bool DexFile::CreateTypeList(uint16_t* return_type_idx, std::vector* p return false; // failed to correctly parse return type } -// Materializes the method descriptor for a method prototype. Method -// descriptors are not stored directly in the dex file. Instead, one -// must assemble the descriptor from references in the prototype. -std::string DexFile::CreateMethodSignature(uint32_t proto_idx, int32_t* unicode_length) const { - const ProtoId& proto_id = GetProtoId(proto_idx); - std::string descriptor; - descriptor.push_back('('); - const TypeList* type_list = GetProtoParameters(proto_id); - size_t parameter_length = 0; - if (type_list != NULL) { - // A non-zero number of arguments. Append the type names. - for (size_t i = 0; i < type_list->Size(); ++i) { - const TypeItem& type_item = type_list->GetTypeItem(i); - uint32_t type_idx = type_item.type_idx_; - uint32_t type_length; - const char* name = StringByTypeIdx(type_idx, &type_length); - parameter_length += type_length; - descriptor.append(name); - } +const Signature DexFile::CreateSignature(const StringPiece& signature) const { + uint16_t return_type_idx; + std::vector param_type_indices; + bool success = CreateTypeList(signature, &return_type_idx, ¶m_type_indices); + if (!success) { + return Signature::NoSignature(); } - descriptor.push_back(')'); - uint32_t return_type_idx = proto_id.return_type_idx_; - uint32_t return_type_length; - const char* name = StringByTypeIdx(return_type_idx, &return_type_length); - descriptor.append(name); - if (unicode_length != NULL) { - *unicode_length = parameter_length + return_type_length + 2; // 2 for ( and ) + const ProtoId* proto_id = FindProtoId(return_type_idx, param_type_indices); + if (proto_id == NULL) { + return Signature::NoSignature(); } - return descriptor; + return Signature(this, *proto_id); } int32_t DexFile::GetLineNumFromPC(const mirror::ArtMethod* method, uint32_t rel_pc) const { @@ -831,6 +815,30 @@ bool DexFile::LineNumForPcCb(void* raw_context, uint32_t address, uint32_t line_ } } +std::string Signature::ToString() const { + if (dex_file_ == nullptr) { + CHECK(proto_id_ == nullptr); + return ""; + } + const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_); + std::string result; + if (params == nullptr) { + result += "()"; + } else { + result += "("; + for (uint32_t i = 0; i < params->Size(); ++i) { + result += dex_file_->StringByTypeIdx(params->GetTypeItem(i).type_idx_); + } + result += ")"; + } + result += dex_file_->StringByTypeIdx(proto_id_->return_type_idx_); + return result; +} + +std::ostream& operator<<(std::ostream& os, const Signature& sig) { + return os << sig.ToString(); +} + // Decodes the header section from the class data bytes. void ClassDataItemIterator::ReadClassDataHeader() { CHECK(ptr_pos_ != NULL); diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 4534b41e92..40e4c72772 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -40,6 +40,7 @@ namespace mirror { class DexCache; } // namespace mirror class ClassLinker; +class Signature; class StringPiece; class ZipArchive; @@ -559,10 +560,8 @@ class DexFile { return GetProtoId(method_id.proto_idx_); } - // Returns the signature of a method id. - const std::string GetMethodSignature(const MethodId& method_id) const { - return CreateMethodSignature(method_id.proto_idx_, NULL); - } + // Returns a representation of the signature of a method id. + const Signature GetMethodSignature(const MethodId& method_id) const; // Returns the name of a method id. const char* GetMethodName(const MethodId& method_id) const { @@ -656,15 +655,16 @@ class DexFile { } // Looks up a proto id for a given return type and signature type list - const ProtoId* FindProtoId(uint16_t return_type_id, + const ProtoId* FindProtoId(uint16_t return_type_idx, const std::vector& signature_type_idxs_) const; // Given a signature place the type ids into the given vector, returns true on success - bool CreateTypeList(uint16_t* return_type_idx, std::vector* param_type_idxs, - const std::string& signature) const; + bool CreateTypeList(const StringPiece& signature, uint16_t* return_type_idx, + std::vector* param_type_idxs) const; - // Given a proto_idx decode the type list and return type into a method signature - std::string CreateMethodSignature(uint32_t proto_idx, int32_t* unicode_length) const; + // Create a Signature from the given string signature or return Signature::NoSignature if not + // possible. + const Signature CreateSignature(const StringPiece& signature) const; // Returns the short form method descriptor for the given prototype. const char* GetShorty(uint32_t proto_idx) const { @@ -942,6 +942,83 @@ class DexFileParameterIterator { DISALLOW_IMPLICIT_CONSTRUCTORS(DexFileParameterIterator); }; +// Abstract the signature of a method. +class Signature { + public: + std::string ToString() const; + + static Signature NoSignature() { + return Signature(); + } + + bool operator==(const Signature& rhs) const { + if (dex_file_ == nullptr) { + return rhs.dex_file_ == nullptr; + } + if (rhs.dex_file_ == nullptr) { + return false; + } + if (dex_file_ == rhs.dex_file_) { + return proto_id_ == rhs.proto_id_; + } + StringPiece shorty(dex_file_->StringDataAsStringPieceByIdx(proto_id_->shorty_idx_)); + if (shorty != rhs.dex_file_->StringDataAsStringPieceByIdx(rhs.proto_id_->shorty_idx_)) { + return false; // Shorty mismatch. + } + if (shorty[0] == 'L') { + const DexFile::TypeId& return_type_id = dex_file_->GetTypeId(proto_id_->return_type_idx_); + const DexFile::TypeId& rhs_return_type_id = + rhs.dex_file_->GetTypeId(rhs.proto_id_->return_type_idx_); + if (dex_file_->StringDataAsStringPieceByIdx(return_type_id.descriptor_idx_) != + rhs.dex_file_->StringDataAsStringPieceByIdx(rhs_return_type_id.descriptor_idx_)) { + return false; // Return type mismatch. + } + } + if (shorty.find('L', 1) != StringPiece::npos) { + const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_); + const DexFile::TypeList* rhs_params = rhs.dex_file_->GetProtoParameters(*rhs.proto_id_); + // Both lists are empty or have contents, or else shorty is broken. + DCHECK_EQ(params == nullptr, rhs_params == nullptr); + if (params != nullptr) { + uint32_t params_size = params->Size(); + DCHECK_EQ(params_size, rhs_params->Size()); // Parameter list size must match. + for (uint32_t i = 0; i < params_size; ++i) { + const DexFile::TypeId& param_id = dex_file_->GetTypeId(params->GetTypeItem(i).type_idx_); + const DexFile::TypeId& rhs_param_id = + rhs.dex_file_->GetTypeId(rhs_params->GetTypeItem(i).type_idx_); + if (dex_file_->StringDataAsStringPieceByIdx(param_id.descriptor_idx_) != + rhs.dex_file_->StringDataAsStringPieceByIdx(rhs_param_id.descriptor_idx_)) { + return false; // Parameter type mismatch. + } + } + } + } + return true; + } + + bool operator!=(const Signature& rhs) const { + return !(*this == rhs); + } + + bool operator==(const StringPiece& rhs) const { + // TODO: Avoid temporary string allocation. + return ToString() == rhs; + } + + private: + Signature(const DexFile* dex, const DexFile::ProtoId& proto) : dex_file_(dex), proto_id_(&proto) { + } + + Signature() : dex_file_(nullptr), proto_id_(nullptr) { + } + + friend class DexFile; + + const DexFile* const dex_file_; + const DexFile::ProtoId* const proto_id_; +}; +std::ostream& operator<<(std::ostream& os, const Signature& sig); + // Iterate and decode class_data_item class ClassDataItemIterator { public: diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc index 32a8354d01..1b40529a08 100644 --- a/runtime/dex_file_test.cc +++ b/runtime/dex_file_test.cc @@ -137,14 +137,14 @@ TEST_F(DexFileTest, ClassDefs) { EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c1)); } -TEST_F(DexFileTest, CreateMethodSignature) { +TEST_F(DexFileTest, GetMethodSignature) { ScopedObjectAccess soa(Thread::Current()); - const DexFile* raw(OpenTestDexFile("CreateMethodSignature")); + const DexFile* raw(OpenTestDexFile("GetMethodSignature")); ASSERT_TRUE(raw != NULL); EXPECT_EQ(1U, raw->NumClassDefs()); const DexFile::ClassDef& class_def = raw->GetClassDef(0); - ASSERT_STREQ("LCreateMethodSignature;", raw->GetClassDescriptor(class_def)); + ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def)); const byte* class_data = raw->GetClassData(class_def); ASSERT_TRUE(class_data != NULL); @@ -156,11 +156,9 @@ TEST_F(DexFileTest, CreateMethodSignature) { { ASSERT_EQ(1U, it.NumDirectMethods()); const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); - uint32_t proto_idx = method_id.proto_idx_; const char* name = raw->StringDataByIdx(method_id.name_idx_); ASSERT_STREQ("", name); - int32_t length; - std::string signature(raw->CreateMethodSignature(proto_idx, &length)); + std::string signature(raw->GetMethodSignature(method_id).ToString()); ASSERT_EQ("()V", signature); } @@ -173,9 +171,7 @@ TEST_F(DexFileTest, CreateMethodSignature) { const char* name = raw->StringDataByIdx(method_id.name_idx_); ASSERT_STREQ("m1", name); - uint32_t proto_idx = method_id.proto_idx_; - int32_t length; - std::string signature(raw->CreateMethodSignature(proto_idx, &length)); + std::string signature(raw->GetMethodSignature(method_id).ToString()); ASSERT_EQ("(IDJLjava/lang/Object;)Ljava/lang/Float;", signature); } @@ -186,20 +182,18 @@ TEST_F(DexFileTest, CreateMethodSignature) { const char* name = raw->StringDataByIdx(method_id.name_idx_); ASSERT_STREQ("m2", name); - uint32_t proto_idx = method_id.proto_idx_; - int32_t length; - std::string signature(raw->CreateMethodSignature(proto_idx, &length)); - ASSERT_EQ("(ZSC)LCreateMethodSignature;", signature); + std::string signature(raw->GetMethodSignature(method_id).ToString()); + ASSERT_EQ("(ZSC)LGetMethodSignature;", signature); } } TEST_F(DexFileTest, FindStringId) { ScopedObjectAccess soa(Thread::Current()); - const DexFile* raw(OpenTestDexFile("CreateMethodSignature")); + const DexFile* raw(OpenTestDexFile("GetMethodSignature")); ASSERT_TRUE(raw != NULL); EXPECT_EQ(1U, raw->NumClassDefs()); - const char* strings[] = { "LCreateMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;", + const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;", "D", "I", "J", NULL }; for (size_t i = 0; strings[i] != NULL; i++) { const char* str = strings[i]; @@ -245,11 +239,10 @@ TEST_F(DexFileTest, FindMethodId) { const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_); const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_); const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature); - int32_t length; ASSERT_TRUE(found != NULL) << "Didn't find method " << i << ": " << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "." << java_lang_dex_file_->GetStringData(name) - << java_lang_dex_file_->CreateMethodSignature(to_find.proto_idx_, &length); + << java_lang_dex_file_->GetMethodSignature(to_find); EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i); } } diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 60fad6ee48..8be9b21cdf 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -228,6 +228,7 @@ static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class, const char* name, const char* sig, bool is_static) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Class* c = soa.Decode(jni_class); + DCHECK(c != nullptr); if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) { return NULL; } diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 287e8b0959..c6db5b9a61 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -325,7 +325,7 @@ void Class::SetClassLoader(ClassLoader* new_class_loader) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false); } -ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const StringPiece& signature) const { +ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const Signature& signature) const { // Check the current class before checking the interfaces. ArtMethod* method = FindDeclaredVirtualMethod(name, signature); if (method != NULL) { @@ -361,8 +361,19 @@ ArtMethod* Class::FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_me return NULL; } - ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) const { + MethodHelper mh; + for (size_t i = 0; i < NumDirectMethods(); ++i) { + ArtMethod* method = GetDirectMethod(i); + mh.ChangeMethod(method); + if (name == mh.GetNameAsStringPiece() && mh.GetSignature() == signature) { + return method; + } + } + return NULL; +} + +ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const Signature& signature) const { MethodHelper mh; for (size_t i = 0; i < NumDirectMethods(); ++i) { ArtMethod* method = GetDirectMethod(i); @@ -396,6 +407,16 @@ ArtMethod* Class::FindDirectMethod(const StringPiece& name, const StringPiece& s return NULL; } +ArtMethod* Class::FindDirectMethod(const StringPiece& name, const Signature& signature) const { + for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { + ArtMethod* method = klass->FindDeclaredDirectMethod(name, signature); + if (method != NULL) { + return method; + } + } + return NULL; +} + ArtMethod* Class::FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const { for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { ArtMethod* method = klass->FindDeclaredDirectMethod(dex_cache, dex_method_idx); @@ -406,8 +427,20 @@ ArtMethod* Class::FindDirectMethod(const DexCache* dex_cache, uint32_t dex_metho return NULL; } +ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const { + MethodHelper mh; + for (size_t i = 0; i < NumVirtualMethods(); ++i) { + ArtMethod* method = GetVirtualMethod(i); + mh.ChangeMethod(method); + if (name == mh.GetNameAsStringPiece() && mh.GetSignature() == signature) { + return method; + } + } + return NULL; +} + ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, - const StringPiece& signature) const { + const Signature& signature) const { MethodHelper mh; for (size_t i = 0; i < NumVirtualMethods(); ++i) { ArtMethod* method = GetVirtualMethod(i); @@ -441,6 +474,16 @@ ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const StringPiece& return NULL; } +ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const Signature& signature) const { + for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { + ArtMethod* method = klass->FindDeclaredVirtualMethod(name, signature); + if (method != NULL) { + return method; + } + } + return NULL; +} + ArtMethod* Class::FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const { for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { ArtMethod* method = klass->FindDeclaredVirtualMethod(dex_cache, dex_method_idx); @@ -451,6 +494,21 @@ ArtMethod* Class::FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_meth return NULL; } +ArtMethod* Class::FindClassInitializer() const { + for (size_t i = 0; i < NumDirectMethods(); ++i) { + ArtMethod* method = GetDirectMethod(i); + if (method->IsConstructor() && method->IsStatic()) { + if (kIsDebugBuild) { + MethodHelper mh(method); + CHECK_STREQ(mh.GetName(), ""); + CHECK_STREQ(mh.GetSignature().ToString().c_str(), "()V"); + } + return method; + } + } + return NULL; +} + ArtField* Class::FindDeclaredInstanceField(const StringPiece& name, const StringPiece& type) { // Is the field in this class? // Interfaces are not relevant because they can't contain instance fields. diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 4f8ab7d90a..586151de45 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -59,6 +59,7 @@ namespace art { struct ClassClassOffsets; struct ClassOffsets; +class Signature; class StringPiece; namespace mirror { @@ -565,39 +566,53 @@ class MANAGED Class : public StaticStorageBase { ArtMethod* FindVirtualMethodForInterface(ArtMethod* method) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE; - ArtMethod* FindInterfaceMethod(const StringPiece& name, const StringPiece& descriptor) const + ArtMethod* FindVirtualMethodForVirtualOrInterface(ArtMethod* method) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + ArtMethod* FindInterfaceMethod(const StringPiece& name, const Signature& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); ArtMethod* FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindVirtualMethodForVirtualOrInterface(ArtMethod* method) const + ArtMethod* FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const + ArtMethod* FindDeclaredDirectMethod(const StringPiece& name, const Signature& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindVirtualMethod(const StringPiece& name, const StringPiece& descriptor) const + ArtMethod* FindDirectMethod(const StringPiece& name, const StringPiece& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindDirectMethod(const StringPiece& name, const Signature& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) const + ArtMethod* FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDirectMethod(const StringPiece& name, const StringPiece& signature) const + ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const Signature& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + ArtMethod* FindVirtualMethod(const StringPiece& name, const StringPiece& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ArtMethod* FindVirtualMethod(const StringPiece& name, const Signature& signature) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + ArtMethod* FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + ArtMethod* FindClassInitializer() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + int32_t GetIfTableCount() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); IfTable* GetIfTable() const; diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 9e107a46d5..f83db903ff 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -504,13 +504,13 @@ class MethodHelper { return shorty_len_; } - const std::string GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const Signature GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); uint32_t dex_method_idx = method_->GetDexMethodIndex(); if (dex_method_idx != DexFile::kDexNoIndex) { return dex_file.GetMethodSignature(dex_file.GetMethodId(dex_method_idx)); } else { - return ""; + return Signature::NoSignature(); } } @@ -638,42 +638,7 @@ class MethodHelper { other_dex_file.StringDataAsStringPieceByIdx(other_mid.name_idx_)) { return false; // Name mismatch. } - const DexFile::ProtoId& proto_id = dex_file.GetMethodPrototype(mid); - const DexFile::ProtoId& other_proto_id = other_dex_file.GetMethodPrototype(other_mid); - if (dex_file.StringDataAsStringPieceByIdx(proto_id.shorty_idx_) != - other_dex_file.StringDataAsStringPieceByIdx(other_proto_id.shorty_idx_)) { - return false; // Shorty mismatch. - } - const DexFile::TypeId& return_type_id = dex_file.GetTypeId(proto_id.return_type_idx_); - const DexFile::TypeId& other_return_type_id = - other_dex_file.GetTypeId(other_proto_id.return_type_idx_); - if (dex_file.StringDataAsStringPieceByIdx(return_type_id.descriptor_idx_) != - other_dex_file.StringDataAsStringPieceByIdx(other_return_type_id.descriptor_idx_)) { - return false; // Return type mismatch. - } - const DexFile::TypeList* params = dex_file.GetProtoParameters(proto_id); - const DexFile::TypeList* other_params = other_dex_file.GetProtoParameters(other_proto_id); - if (params == nullptr) { - return other_params == nullptr; // Check both lists are empty. - } - if (other_params == nullptr) { - return false; // Parameter list size mismatch. - } - uint32_t params_size = params->Size(); - uint32_t other_params_size = other_params->Size(); - if (params_size != other_params_size) { - return false; // Parameter list size mismatch. - } - for (uint32_t i = 0; i < params_size; ++i) { - const DexFile::TypeId& param_id = dex_file.GetTypeId(params->GetTypeItem(i).type_idx_); - const DexFile::TypeId& other_param_id = - other_dex_file.GetTypeId(other_params->GetTypeItem(i).type_idx_); - if (dex_file.StringDataAsStringPieceByIdx(param_id.descriptor_idx_) != - other_dex_file.StringDataAsStringPieceByIdx(other_param_id.descriptor_idx_)) { - return false; // Parameter type mismatch. - } - } - return true; + return dex_file.GetMethodSignature(mid) == other_dex_file.GetMethodSignature(other_mid); } const DexFile::CodeItem* GetCodeItem() diff --git a/runtime/trace.cc b/runtime/trace.cc index 7b25306177..ec95a87146 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -667,7 +667,7 @@ void Trace::DumpMethodList(std::ostream& os, const std::set& mh.ChangeMethod(method); os << StringPrintf("%p\t%s\t%s\t%s\t%s\n", method, PrettyDescriptor(mh.GetDeclaringClassDescriptor()).c_str(), mh.GetName(), - mh.GetSignature().c_str(), mh.GetDeclaringClassSourceFile()); + mh.GetSignature().ToString().c_str(), mh.GetDeclaringClassSourceFile()); } } diff --git a/runtime/utils.cc b/runtime/utils.cc index 23dcde3065..b97239fd18 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -367,11 +367,13 @@ std::string PrettyMethod(const mirror::ArtMethod* m, bool with_signature) { result += '.'; result += mh.GetName(); if (with_signature) { - std::string signature(mh.GetSignature()); - if (signature == "") { - return result + signature; + const Signature signature = mh.GetSignature(); + std::string sig_as_string(signature.ToString()); + if (signature == Signature::NoSignature()) { + return result + sig_as_string; } - result = PrettyReturnType(signature.c_str()) + " " + result + PrettyArguments(signature.c_str()); + result = PrettyReturnType(sig_as_string.c_str()) + " " + result + + PrettyArguments(sig_as_string.c_str()); } return result; } @@ -385,11 +387,13 @@ std::string PrettyMethod(uint32_t method_idx, const DexFile& dex_file, bool with result += '.'; result += dex_file.GetMethodName(method_id); if (with_signature) { - std::string signature(dex_file.GetMethodSignature(method_id)); - if (signature == "") { - return result + signature; + const Signature signature = dex_file.GetMethodSignature(method_id); + std::string sig_as_string(signature.ToString()); + if (signature == Signature::NoSignature()) { + return result + sig_as_string; } - result = PrettyReturnType(signature.c_str()) + " " + result + PrettyArguments(signature.c_str()); + result = PrettyReturnType(sig_as_string.c_str()) + " " + result + + PrettyArguments(sig_as_string.c_str()); } return result; } @@ -641,7 +645,7 @@ std::string JniLongName(const mirror::ArtMethod* m) { long_name += JniShortName(m); long_name += "__"; - std::string signature(MethodHelper(m).GetSignature()); + std::string signature(MethodHelper(m).GetSignature().ToString()); signature.erase(0, 1); signature.erase(signature.begin() + signature.find(')'), signature.end()); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 6b13517fdc..36b409d142 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -2910,7 +2910,7 @@ const RegType& MethodVerifier::GetCaughtExceptionType() { } mirror::ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(uint32_t dex_method_idx, - MethodType method_type) { + MethodType method_type) { const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx); const RegType& klass_type = ResolveClassAndCheckAccess(method_id.class_idx_); if (klass_type.IsConflict()) { @@ -2927,7 +2927,7 @@ mirror::ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(uint32_t dex_meth mirror::ArtMethod* res_method = dex_cache_->GetResolvedMethod(dex_method_idx); if (res_method == NULL) { const char* name = dex_file_->GetMethodName(method_id); - std::string signature(dex_file_->CreateMethodSignature(method_id.proto_idx_, NULL)); + const Signature signature = dex_file_->GetMethodSignature(method_id); if (method_type == METHOD_DIRECT || method_type == METHOD_STATIC) { res_method = klass->FindDirectMethod(name, signature); diff --git a/test/Android.mk b/test/Android.mk index 6f498e8c02..08ec03a01a 100644 --- a/test/Android.mk +++ b/test/Android.mk @@ -23,8 +23,8 @@ include art/build/Android.common.mk TEST_DEX_DIRECTORIES := \ AbstractMethod \ AllFields \ - CreateMethodSignature \ ExceptionHandle \ + GetMethodSignature \ Interfaces \ Main \ MyClass \ diff --git a/test/CreateMethodSignature/CreateMethodSignature.java b/test/CreateMethodSignature/CreateMethodSignature.java deleted file mode 100644 index f6cd6ae6fd..0000000000 --- a/test/CreateMethodSignature/CreateMethodSignature.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -class CreateMethodSignature { - Float m1(int a, double b, long c, Object d) { return null; } - CreateMethodSignature m2(boolean x, short y, char z) { return null; } -} diff --git a/test/GetMethodSignature/GetMethodSignature.java b/test/GetMethodSignature/GetMethodSignature.java new file mode 100644 index 0000000000..c2ba948d60 --- /dev/null +++ b/test/GetMethodSignature/GetMethodSignature.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class GetMethodSignature { + Float m1(int a, double b, long c, Object d) { return null; } + GetMethodSignature m2(boolean x, short y, char z) { return null; } +} -- cgit v1.2.3-59-g8ed1b From b48819db07f9a0992a72173380c24249d7fc648a Mon Sep 17 00:00:00 2001 From: buzbee Date: Sat, 14 Sep 2013 16:15:25 -0700 Subject: Compile-time tuning: assembly phase Not as much compile-time gain from reworking the assembly phase as I'd hoped, but still worthwhile. Should see ~2% improvement thanks to the assembly rework. On the other hand, expect some huge gains for some application thanks to better detection of large machine-generated init methods. Thinkfree shows a 25% improvement. The major assembly change was to establish thread the LIR nodes that require fixup into a fixup chain. Only those are processed during the final assembly pass(es). This doesn't help for methods which only require a single pass to assemble, but does speed up the larger methods which required multiple assembly passes. Also replaced the block_map_ basic block lookup table (which contained space for a BasicBlock* for each dex instruction unit) with a block id map - cutting its space requirements by half in a 32-bit pointer environment. Changes: o Reduce size of LIR struct by 12.5% (one of the big memory users) o Repurpose the use/def portion of the LIR after optimization complete. o Encode instruction bits to LIR o Thread LIR nodes requiring pc fixup o Change follow-on assembly passes to only consider fixup LIRs o Switch on pc-rel fixup kind o Fast-path for small methods - single pass assembly o Avoid using cb[n]z for null checks (almost always exceed displacement) o Improve detection of large initialization methods. o Rework def/use flag setup. o Remove a sequential search from FindBlock using lookup table of 16-bit block ids rather than full block pointers. o Eliminate pcRelFixup and use fixup kind instead. o Add check for 16-bit overflow on dex offset. Change-Id: I4c6615f83fed46f84629ad6cfe4237205a9562b4 --- compiler/dex/compiler_enums.h | 21 + compiler/dex/frontend.cc | 7 +- compiler/dex/mir_analysis.cc | 8 + compiler/dex/mir_graph.cc | 78 +- compiler/dex/mir_graph.h | 27 +- compiler/dex/quick/arm/arm_lir.h | 4 +- compiler/dex/quick/arm/assemble_arm.cc | 1404 +++++++++++++++++------------ compiler/dex/quick/arm/codegen_arm.h | 10 +- compiler/dex/quick/arm/int_arm.cc | 15 +- compiler/dex/quick/arm/target_arm.cc | 117 +-- compiler/dex/quick/arm/utility_arm.cc | 2 - compiler/dex/quick/codegen_util.cc | 138 +-- compiler/dex/quick/gen_common.cc | 5 +- compiler/dex/quick/gen_invoke.cc | 4 +- compiler/dex/quick/local_optimizations.cc | 38 +- compiler/dex/quick/mips/assemble_mips.cc | 95 +- compiler/dex/quick/mips/codegen_mips.h | 5 +- compiler/dex/quick/mips/target_mips.cc | 15 +- compiler/dex/quick/mir_to_lir-inl.h | 45 +- compiler/dex/quick/mir_to_lir.cc | 4 +- compiler/dex/quick/mir_to_lir.h | 45 +- compiler/dex/quick/x86/assemble_x86.cc | 95 +- compiler/dex/quick/x86/codegen_x86.h | 5 +- compiler/dex/quick/x86/target_x86.cc | 23 +- 24 files changed, 1352 insertions(+), 858 deletions(-) (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h index 97a682f2aa..17b5bb5b19 100644 --- a/compiler/dex/compiler_enums.h +++ b/compiler/dex/compiler_enums.h @@ -412,6 +412,27 @@ enum OatBitMapKind { std::ostream& operator<<(std::ostream& os, const OatBitMapKind& kind); +// LIR fixup kinds for Arm +enum FixupKind { + kFixupNone, + kFixupLabel, // For labels we just adjust the offset. + kFixupLoad, // Mostly for imediates. + kFixupVLoad, // FP load which *may* be pc-relative. + kFixupCBxZ, // Cbz, Cbnz. + kFixupPushPop, // Not really pc relative, but changes size based on args. + kFixupCondBranch, // Conditional branch + kFixupT1Branch, // Thumb1 Unconditional branch + kFixupT2Branch, // Thumb2 Unconditional branch + kFixupBlx1, // Blx1 (start of Blx1/Blx2 pair). + kFixupBl1, // Bl1 (start of Bl1/Bl2 pair). + kFixupAdr, // Adr. + kFixupMovImmLST, // kThumb2MovImm16LST. + kFixupMovImmHST, // kThumb2MovImm16HST. + kFixupAlign4, // Align to 4-byte boundary. +}; + +std::ostream& operator<<(std::ostream& os, const FixupKind& kind); + } // namespace art #endif // ART_COMPILER_DEX_COMPILER_ENUMS_H_ diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index fefcab9e87..2952570436 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -117,6 +117,11 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, #endif ) { VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "..."; + if (code_item->insns_size_in_code_units_ >= 0x10000) { + LOG(INFO) << "Method size exceeds compiler limits: " << code_item->insns_size_in_code_units_ + << " in " << PrettyMethod(method_idx, dex_file); + return NULL; + } ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); CompilationUnit cu(&compiler.GetArenaPool()); @@ -151,7 +156,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, */ if (compiler_backend == kPortable) { - // Fused long branches not currently usseful in bitcode. + // Fused long branches not currently useful in bitcode. cu.disable_opt |= (1 << kBranchFusing); } diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc index 8472a3c011..8597172881 100644 --- a/compiler/dex/mir_analysis.cc +++ b/compiler/dex/mir_analysis.cc @@ -1032,6 +1032,14 @@ bool MIRGraph::SkipCompilation(Runtime::CompilerFilter compiler_filter) { */ if (GetNumDalvikInsns() > Runtime::Current()->GetHugeMethodThreshold()) { skip_compilation = true; + // If we're got a huge number of basic blocks, don't bother with further analysis. + if (static_cast(num_blocks_) > (Runtime::Current()->GetHugeMethodThreshold() / 2)) { + return true; + } + } else if (GetNumDalvikInsns() > Runtime::Current()->GetLargeMethodThreshold() && + /* If it's large and contains no branches, it's likely to be machine generated initialization */ + (GetBranchCount() == 0)) { + return true; } else if (compiler_filter == Runtime::kSpeed) { // If not huge, compile. return false; diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index c234298a88..fb306de0c1 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -96,10 +96,9 @@ MIRGraph::MIRGraph(CompilationUnit* cu, ArenaAllocator* arena) try_block_addr_(NULL), entry_block_(NULL), exit_block_(NULL), - cur_block_(NULL), num_blocks_(0), current_code_item_(NULL), - block_map_(arena, 0, kGrowableArrayMisc), + dex_pc_to_block_map_(arena, 0, kGrowableArrayMisc), current_method_(kInvalidEntry), current_offset_(kInvalidEntry), def_count_(0), @@ -109,7 +108,9 @@ MIRGraph::MIRGraph(CompilationUnit* cu, ArenaAllocator* arena) attributes_(METHOD_IS_LEAF), // Start with leaf assumption, change on encountering invoke. checkstats_(NULL), special_case_(kNoHandler), - arena_(arena) { + arena_(arena), + backward_branches_(0), + forward_branches_(0) { try_block_addr_ = new (arena_) ArenaBitVector(arena_, 0, true /* expandable */); } @@ -151,7 +152,7 @@ BasicBlock* MIRGraph::SplitBlock(unsigned int code_offset, orig_block->terminated_by_return = false; /* Add it to the quick lookup cache */ - block_map_.Put(bottom_block->start_offset, bottom_block); + dex_pc_to_block_map_.Put(bottom_block->start_offset, bottom_block->id); /* Handle the taken path */ bottom_block->taken = orig_block->taken; @@ -196,6 +197,23 @@ BasicBlock* MIRGraph::SplitBlock(unsigned int code_offset, DCHECK_EQ(*immed_pred_block_p, orig_block); *immed_pred_block_p = bottom_block; } + + // Associate dex instructions in the bottom block with the new container. + MIR* p = bottom_block->first_mir_insn; + while (p != NULL) { + int opcode = p->dalvikInsn.opcode; + /* + * Some messiness here to ensure that we only enter real opcodes and only the + * first half of a potentially throwing instruction that has been split into + * CHECK and work portions. The 2nd half of a split operation will have a non-null + * throw_insn pointer that refers to the 1st half. + */ + if ((opcode == kMirOpCheck) || (!IsPseudoMirOp(opcode) && (p->meta.throw_insn == NULL))) { + dex_pc_to_block_map_.Put(p->offset, bottom_block->id); + } + p = (p == bottom_block->last_mir_insn) ? NULL : p->next; + } + return bottom_block; } @@ -209,39 +227,37 @@ BasicBlock* MIRGraph::SplitBlock(unsigned int code_offset, */ BasicBlock* MIRGraph::FindBlock(unsigned int code_offset, bool split, bool create, BasicBlock** immed_pred_block_p) { - BasicBlock* bb; - unsigned int i; - if (code_offset >= cu_->code_item->insns_size_in_code_units_) { return NULL; } - bb = block_map_.Get(code_offset); - if ((bb != NULL) || !create) { + + int block_id = dex_pc_to_block_map_.Get(code_offset); + BasicBlock* bb = (block_id == 0) ? NULL : block_list_.Get(block_id); + + if ((bb != NULL) && (bb->start_offset == code_offset)) { + // Does this containing block start with the desired instruction? return bb; } - if (split) { - for (i = block_list_.Size(); i > 0; i--) { - bb = block_list_.Get(i - 1); - if (bb->block_type != kDalvikByteCode) continue; - /* Check if a branch jumps into the middle of an existing block */ - if ((code_offset > bb->start_offset) && (bb->last_mir_insn != NULL) && - (code_offset <= bb->last_mir_insn->offset)) { - BasicBlock *new_bb = SplitBlock(code_offset, bb, bb == *immed_pred_block_p ? - immed_pred_block_p : NULL); - return new_bb; - } - } + // No direct hit. + if (!create) { + return NULL; + } + + if (bb != NULL) { + // The target exists somewhere in an existing block. + return SplitBlock(code_offset, bb, bb == *immed_pred_block_p ? immed_pred_block_p : NULL); } - /* Create a new one */ + // Create a new block. bb = NewMemBB(kDalvikByteCode, num_blocks_++); block_list_.Insert(bb); bb->start_offset = code_offset; - block_map_.Put(bb->start_offset, bb); + dex_pc_to_block_map_.Put(bb->start_offset, bb->id); return bb; } + /* Identify code range in try blocks and set up the empty catch blocks */ void MIRGraph::ProcessTryCatchBlocks() { int tries_size = current_code_item_->tries_size_; @@ -307,6 +323,7 @@ BasicBlock* MIRGraph::ProcessCanBranch(BasicBlock* cur_block, MIR* insn, int cur default: LOG(FATAL) << "Unexpected opcode(" << insn->dalvikInsn.opcode << ") with kBranch set"; } + CountBranch(target); BasicBlock *taken_block = FindBlock(target, /* split */ true, /* create */ true, /* immed_pred_block_p */ &cur_block); cur_block->taken = taken_block; @@ -485,6 +502,9 @@ BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, int cur_ * pseudo exception edge MIR. Note also that this new block is * not automatically terminated after the work portion, and may * contain following instructions. + * + * Note also that the dex_pc_to_block_map_ entry for the potentially + * throwing instruction will refer to the original basic block. */ BasicBlock *new_block = NewMemBB(kDalvikByteCode, num_blocks_++); block_list_.Insert(new_block); @@ -518,8 +538,9 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ current_code_item_->insns_ + current_code_item_->insns_size_in_code_units_; // TODO: need to rework expansion of block list & try_block_addr when inlining activated. + // TUNING: use better estimate of basic blocks for following resize. block_list_.Resize(block_list_.Size() + current_code_item_->insns_size_in_code_units_); - block_map_.SetSize(block_map_.Size() + current_code_item_->insns_size_in_code_units_); + dex_pc_to_block_map_.SetSize(dex_pc_to_block_map_.Size() + current_code_item_->insns_size_in_code_units_); // TODO: replace with explicit resize routine. Using automatic extension side effect for now. try_block_addr_->SetBit(current_code_item_->insns_size_in_code_units_); @@ -560,10 +581,7 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ DCHECK_EQ(current_offset_, 0); cur_block->start_offset = current_offset_; block_list_.Insert(cur_block); - /* Add first block to the fast lookup cache */ -// FIXME: block map needs association with offset/method pair rather than just offset - block_map_.Put(cur_block->start_offset, cur_block); -// FIXME: this needs to insert at the insert point rather than entry block. + // FIXME: this needs to insert at the insert point rather than entry block. entry_block_->fall_through = cur_block; cur_block->predecessors->Insert(entry_block_); @@ -589,7 +607,6 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ opcode_count_[static_cast(opcode)]++; } - /* Possible simple method? */ if (live_pattern) { live_pattern = false; @@ -640,6 +657,9 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ AppendMIR(cur_block, insn); } + // Associate the starting dex_pc for this opcode with its containing basic block. + dex_pc_to_block_map_.Put(insn->offset, cur_block->id); + code_ptr += width; if (flags & Instruction::kBranch) { diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 9d4ab98f67..5d014894c1 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -569,6 +569,26 @@ class MIRGraph { return IsBackedge(branch_bb, branch_bb->taken) || IsBackedge(branch_bb, branch_bb->fall_through); } + void CountBranch(int target_offset) { + if (target_offset <= current_offset_) { + backward_branches_++; + } else { + forward_branches_++; + } + } + + int GetBranchCount() { + return backward_branches_ + forward_branches_; + } + + bool IsPseudoMirOp(Instruction::Code opcode) { + return static_cast(opcode) >= static_cast(kMirOpFirst); + } + + bool IsPseudoMirOp(int opcode) { + return opcode >= static_cast(kMirOpFirst); + } + void BasicBlockCombine(); void CodeLayout(); void DumpCheckStats(); @@ -725,15 +745,14 @@ class MIRGraph { ArenaBitVector* try_block_addr_; BasicBlock* entry_block_; BasicBlock* exit_block_; - BasicBlock* cur_block_; int num_blocks_; const DexFile::CodeItem* current_code_item_; - GrowableArray block_map_; // FindBlock lookup cache. + GrowableArray dex_pc_to_block_map_; // FindBlock lookup cache. std::vector m_units_; // List of methods included in this graph typedef std::pair MIRLocation; // Insert point, (m_unit_ index, offset) std::vector method_stack_; // Include stack int current_method_; - int current_offset_; + int current_offset_; // Dex offset in code units int def_count_; // Used to estimate size of ssa name storage. int* opcode_count_; // Dex opcode coverage stats. int num_ssa_regs_; // Number of names following SSA transformation. @@ -743,6 +762,8 @@ class MIRGraph { Checkstats* checkstats_; SpecialCaseHandler special_case_; ArenaAllocator* arena_; + int backward_branches_; + int forward_branches_; }; } // namespace art diff --git a/compiler/dex/quick/arm/arm_lir.h b/compiler/dex/quick/arm/arm_lir.h index 2f54190ae7..d18467304f 100644 --- a/compiler/dex/quick/arm/arm_lir.h +++ b/compiler/dex/quick/arm/arm_lir.h @@ -462,7 +462,7 @@ enum ArmOpDmbOptions { // Instruction assembly field_loc kind. enum ArmEncodingKind { - kFmtUnused, + kFmtUnused, // Unused field and marks end of formats. kFmtBitBlt, // Bit string using end/start. kFmtDfp, // Double FP reg. kFmtSfp, // Single FP reg. @@ -477,6 +477,7 @@ enum ArmEncodingKind { kFmtBrOffset, // Signed extended [26,11,13,21-16,10-0]:0. kFmtFPImm, // Encoded floating point immediate. kFmtOff24, // 24-bit Thumb2 unconditional branch encoding. + kFmtSkip, // Unused field, but continue to next. }; // Struct used to define the snippet positions for each Thumb opcode. @@ -492,6 +493,7 @@ struct ArmEncodingMap { const char* name; const char* fmt; int size; // Note: size is in bytes. + FixupKind fixup; }; } // namespace art diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc index 2d69d935ca..dac3a2159c 100644 --- a/compiler/dex/quick/arm/assemble_arm.cc +++ b/compiler/dex/quick/arm/assemble_arm.cc @@ -37,9 +37,9 @@ namespace art { * fmt: for pretty-printing */ #define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \ - k3, k3s, k3e, flags, name, fmt, size) \ + k3, k3s, k3e, flags, name, fmt, size, fixup) \ {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \ - {k3, k3s, k3e}}, opcode, flags, name, fmt, size} + {k3, k3s, k3e}}, opcode, flags, name, fmt, size, fixup} /* Instruction dump string format keys: !pf, where "!" is the start * of the key, "p" is which numeric operand to use and "f" is the @@ -79,916 +79,938 @@ namespace art { const ArmEncodingMap ArmMir2Lir::EncodingMap[kArmLast] = { ENCODING_MAP(kArm16BitData, 0x0000, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, - kFmtUnused, -1, -1, IS_UNARY_OP, "data", "0x!0h(!0d)", 2), + kFmtUnused, -1, -1, IS_UNARY_OP, "data", "0x!0h(!0d)", 2, kFixupNone), ENCODING_MAP(kThumbAdcRR, 0x4140, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES | USES_CCODES, - "adcs", "!0C, !1C", 2), + "adcs", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbAddRRI3, 0x1c00, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "adds", "!0C, !1C, #!2d", 2), + "adds", "!0C, !1C, #!2d", 2, kFixupNone), ENCODING_MAP(kThumbAddRI8, 0x3000, kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES, - "adds", "!0C, !0C, #!1d", 2), + "adds", "!0C, !0C, #!1d", 2, kFixupNone), ENCODING_MAP(kThumbAddRRR, 0x1800, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | SETS_CCODES, - "adds", "!0C, !1C, !2C", 2), + "adds", "!0C, !1C, !2C", 2, kFixupNone), ENCODING_MAP(kThumbAddRRLH, 0x4440, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01, - "add", "!0C, !1C", 2), + "add", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbAddRRHL, 0x4480, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01, - "add", "!0C, !1C", 2), + "add", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbAddRRHH, 0x44c0, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01, - "add", "!0C, !1C", 2), + "add", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbAddPcRel, 0xa000, kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | IS_BRANCH | NEEDS_FIXUP, - "add", "!0C, pc, #!1E", 2), + "add", "!0C, pc, #!1E", 2, kFixupLoad), ENCODING_MAP(kThumbAddSpRel, 0xa800, - kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0, + kFmtBitBlt, 10, 8, kFmtSkip, -1, -1, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF_SP | REG_USE_SP, - "add", "!0C, sp, #!2E", 2), + "add", "!0C, sp, #!2E", 2, kFixupNone), ENCODING_MAP(kThumbAddSpI7, 0xb000, kFmtBitBlt, 6, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP, - "add", "sp, #!0d*4", 2), + "add", "sp, #!0d*4", 2, kFixupNone), ENCODING_MAP(kThumbAndRR, 0x4000, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, - "ands", "!0C, !1C", 2), + "ands", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbAsrRRI5, 0x1000, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "asrs", "!0C, !1C, #!2d", 2), + "asrs", "!0C, !1C, #!2d", 2, kFixupNone), ENCODING_MAP(kThumbAsrRR, 0x4100, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, - "asrs", "!0C, !1C", 2), + "asrs", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbBCond, 0xd000, kFmtBitBlt, 7, 0, kFmtBitBlt, 11, 8, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | USES_CCODES | - NEEDS_FIXUP, "b!1c", "!0t", 2), + NEEDS_FIXUP, "b!1c", "!0t", 2, kFixupCondBranch), ENCODING_MAP(kThumbBUncond, 0xe000, kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | NEEDS_FIXUP, - "b", "!0t", 2), + "b", "!0t", 2, kFixupT1Branch), ENCODING_MAP(kThumbBicRR, 0x4380, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, - "bics", "!0C, !1C", 2), + "bics", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbBkpt, 0xbe00, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH, - "bkpt", "!0d", 2), + "bkpt", "!0d", 2, kFixupNone), ENCODING_MAP(kThumbBlx1, 0xf000, kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF_LR | - NEEDS_FIXUP, "blx_1", "!0u", 2), + NEEDS_FIXUP, "blx_1", "!0u", 2, kFixupBlx1), ENCODING_MAP(kThumbBlx2, 0xe800, kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF_LR | - NEEDS_FIXUP, "blx_2", "!0v", 2), + NEEDS_FIXUP, "blx_2", "!0v", 2, kFixupLabel), ENCODING_MAP(kThumbBl1, 0xf000, kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, - kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR, - "bl_1", "!0u", 2), + kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR | NEEDS_FIXUP, + "bl_1", "!0u", 2, kFixupBl1), ENCODING_MAP(kThumbBl2, 0xf800, kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, - kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR, - "bl_2", "!0v", 2), + kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR | NEEDS_FIXUP, + "bl_2", "!0v", 2, kFixupLabel), ENCODING_MAP(kThumbBlxR, 0x4780, kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | REG_USE0 | IS_BRANCH | REG_DEF_LR, - "blx", "!0C", 2), + "blx", "!0C", 2, kFixupNone), ENCODING_MAP(kThumbBx, 0x4700, kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH, - "bx", "!0C", 2), + "bx", "!0C", 2, kFixupNone), ENCODING_MAP(kThumbCmnRR, 0x42c0, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES, - "cmn", "!0C, !1C", 2), + "cmn", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbCmpRI8, 0x2800, kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | SETS_CCODES, - "cmp", "!0C, #!1d", 2), + "cmp", "!0C, #!1d", 2, kFixupNone), ENCODING_MAP(kThumbCmpRR, 0x4280, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES, - "cmp", "!0C, !1C", 2), + "cmp", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbCmpLH, 0x4540, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES, - "cmp", "!0C, !1C", 2), + "cmp", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbCmpHL, 0x4580, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES, - "cmp", "!0C, !1C", 2), + "cmp", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbCmpHH, 0x45c0, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES, - "cmp", "!0C, !1C", 2), + "cmp", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbEorRR, 0x4040, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, - "eors", "!0C, !1C", 2), + "eors", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbLdmia, 0xc800, kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD, - "ldmia", "!0C!!, ", 2), + "ldmia", "!0C!!, ", 2, kFixupNone), ENCODING_MAP(kThumbLdrRRI5, 0x6800, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, - "ldr", "!0C, [!1C, #!2E]", 2), + "ldr", "!0C, [!1C, #!2E]", 2, kFixupNone), ENCODING_MAP(kThumbLdrRRR, 0x5800, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD, - "ldr", "!0C, [!1C, !2C]", 2), + "ldr", "!0C, [!1C, !2C]", 2, kFixupNone), ENCODING_MAP(kThumbLdrPcRel, 0x4800, kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC - | IS_LOAD | NEEDS_FIXUP, "ldr", "!0C, [pc, #!1E]", 2), + | IS_LOAD | NEEDS_FIXUP, "ldr", "!0C, [pc, #!1E]", 2, kFixupLoad), ENCODING_MAP(kThumbLdrSpRel, 0x9800, - kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0, + kFmtBitBlt, 10, 8, kFmtSkip, -1, -1, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_SP - | IS_LOAD, "ldr", "!0C, [sp, #!2E]", 2), + | IS_LOAD, "ldr", "!0C, [sp, #!2E]", 2, kFixupNone), ENCODING_MAP(kThumbLdrbRRI5, 0x7800, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, - "ldrb", "!0C, [!1C, #2d]", 2), + "ldrb", "!0C, [!1C, #2d]", 2, kFixupNone), ENCODING_MAP(kThumbLdrbRRR, 0x5c00, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD, - "ldrb", "!0C, [!1C, !2C]", 2), + "ldrb", "!0C, [!1C, !2C]", 2, kFixupNone), ENCODING_MAP(kThumbLdrhRRI5, 0x8800, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, - "ldrh", "!0C, [!1C, #!2F]", 2), + "ldrh", "!0C, [!1C, #!2F]", 2, kFixupNone), ENCODING_MAP(kThumbLdrhRRR, 0x5a00, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD, - "ldrh", "!0C, [!1C, !2C]", 2), + "ldrh", "!0C, [!1C, !2C]", 2, kFixupNone), ENCODING_MAP(kThumbLdrsbRRR, 0x5600, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD, - "ldrsb", "!0C, [!1C, !2C]", 2), + "ldrsb", "!0C, [!1C, !2C]", 2, kFixupNone), ENCODING_MAP(kThumbLdrshRRR, 0x5e00, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD, - "ldrsh", "!0C, [!1C, !2C]", 2), + "ldrsh", "!0C, [!1C, !2C]", 2, kFixupNone), ENCODING_MAP(kThumbLslRRI5, 0x0000, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "lsls", "!0C, !1C, #!2d", 2), + "lsls", "!0C, !1C, #!2d", 2, kFixupNone), ENCODING_MAP(kThumbLslRR, 0x4080, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, - "lsls", "!0C, !1C", 2), + "lsls", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbLsrRRI5, 0x0800, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "lsrs", "!0C, !1C, #!2d", 2), + "lsrs", "!0C, !1C, #!2d", 2, kFixupNone), ENCODING_MAP(kThumbLsrRR, 0x40c0, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, - "lsrs", "!0C, !1C", 2), + "lsrs", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbMovImm, 0x2000, kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0 | SETS_CCODES, - "movs", "!0C, #!1d", 2), + "movs", "!0C, #!1d", 2, kFixupNone), ENCODING_MAP(kThumbMovRR, 0x1c00, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "movs", "!0C, !1C", 2), + "movs", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbMovRR_H2H, 0x46c0, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "mov", "!0C, !1C", 2), + "mov", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbMovRR_H2L, 0x4640, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "mov", "!0C, !1C", 2), + "mov", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbMovRR_L2H, 0x4680, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "mov", "!0C, !1C", 2), + "mov", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbMul, 0x4340, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, - "muls", "!0C, !1C", 2), + "muls", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbMvn, 0x43c0, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "mvns", "!0C, !1C", 2), + "mvns", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbNeg, 0x4240, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "negs", "!0C, !1C", 2), + "negs", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbOrr, 0x4300, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, - "orrs", "!0C, !1C", 2), + "orrs", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbPop, 0xbc00, kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 - | IS_LOAD, "pop", "", 2), + | IS_LOAD, "pop", "", 2, kFixupNone), ENCODING_MAP(kThumbPush, 0xb400, kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0 - | IS_STORE, "push", "", 2), + | IS_STORE, "push", "", 2, kFixupNone), ENCODING_MAP(kThumbRorRR, 0x41c0, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, - "rors", "!0C, !1C", 2), + "rors", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbSbc, 0x4180, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01 | USES_CCODES | SETS_CCODES, - "sbcs", "!0C, !1C", 2), + "sbcs", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumbStmia, 0xc000, kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0 | REG_USE0 | REG_USE_LIST1 | IS_STORE, - "stmia", "!0C!!, ", 2), + "stmia", "!0C!!, ", 2, kFixupNone), ENCODING_MAP(kThumbStrRRI5, 0x6000, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, - "str", "!0C, [!1C, #!2E]", 2), + "str", "!0C, [!1C, #!2E]", 2, kFixupNone), ENCODING_MAP(kThumbStrRRR, 0x5000, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE, - "str", "!0C, [!1C, !2C]", 2), + "str", "!0C, [!1C, !2C]", 2, kFixupNone), ENCODING_MAP(kThumbStrSpRel, 0x9000, - kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0, + kFmtBitBlt, 10, 8, kFmtSkip, -1, -1, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE0 | REG_USE_SP - | IS_STORE, "str", "!0C, [sp, #!2E]", 2), + | IS_STORE, "str", "!0C, [sp, #!2E]", 2, kFixupNone), ENCODING_MAP(kThumbStrbRRI5, 0x7000, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, - "strb", "!0C, [!1C, #!2d]", 2), + "strb", "!0C, [!1C, #!2d]", 2, kFixupNone), ENCODING_MAP(kThumbStrbRRR, 0x5400, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE, - "strb", "!0C, [!1C, !2C]", 2), + "strb", "!0C, [!1C, !2C]", 2, kFixupNone), ENCODING_MAP(kThumbStrhRRI5, 0x8000, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, - "strh", "!0C, [!1C, #!2F]", 2), + "strh", "!0C, [!1C, #!2F]", 2, kFixupNone), ENCODING_MAP(kThumbStrhRRR, 0x5200, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE, - "strh", "!0C, [!1C, !2C]", 2), + "strh", "!0C, [!1C, !2C]", 2, kFixupNone), ENCODING_MAP(kThumbSubRRI3, 0x1e00, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "subs", "!0C, !1C, #!2d", 2), + "subs", "!0C, !1C, #!2d", 2, kFixupNone), ENCODING_MAP(kThumbSubRI8, 0x3800, kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES, - "subs", "!0C, #!1d", 2), + "subs", "!0C, #!1d", 2, kFixupNone), ENCODING_MAP(kThumbSubRRR, 0x1a00, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | SETS_CCODES, - "subs", "!0C, !1C, !2C", 2), + "subs", "!0C, !1C, !2C", 2, kFixupNone), ENCODING_MAP(kThumbSubSpI7, 0xb080, kFmtBitBlt, 6, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP, - "sub", "sp, #!0d*4", 2), + "sub", "sp, #!0d*4", 2, kFixupNone), ENCODING_MAP(kThumbSwi, 0xdf00, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH, - "swi", "!0d", 2), + "swi", "!0d", 2, kFixupNone), ENCODING_MAP(kThumbTst, 0x4200, kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | REG_USE01 | SETS_CCODES, - "tst", "!0C, !1C", 2), + "tst", "!0C, !1C", 2, kFixupNone), ENCODING_MAP(kThumb2Vldrs, 0xed900a00, kFmtSfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD | - REG_DEF_LR | NEEDS_FIXUP, "vldr", "!0s, [!1C, #!2E]", 4), + REG_DEF_LR | NEEDS_FIXUP, "vldr", "!0s, [!1C, #!2E]", 4, kFixupVLoad), ENCODING_MAP(kThumb2Vldrd, 0xed900b00, kFmtDfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD | - REG_DEF_LR | NEEDS_FIXUP, "vldr", "!0S, [!1C, #!2E]", 4), + REG_DEF_LR | NEEDS_FIXUP, "vldr", "!0S, [!1C, #!2E]", 4, kFixupVLoad), ENCODING_MAP(kThumb2Vmuls, 0xee200a00, kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "vmuls", "!0s, !1s, !2s", 4), + "vmuls", "!0s, !1s, !2s", 4, kFixupNone), ENCODING_MAP(kThumb2Vmuld, 0xee200b00, kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "vmuld", "!0S, !1S, !2S", 4), + "vmuld", "!0S, !1S, !2S", 4, kFixupNone), ENCODING_MAP(kThumb2Vstrs, 0xed800a00, kFmtSfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, - "vstr", "!0s, [!1C, #!2E]", 4), + "vstr", "!0s, [!1C, #!2E]", 4, kFixupNone), ENCODING_MAP(kThumb2Vstrd, 0xed800b00, kFmtDfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, - "vstr", "!0S, [!1C, #!2E]", 4), + "vstr", "!0S, [!1C, #!2E]", 4, kFixupNone), ENCODING_MAP(kThumb2Vsubs, 0xee300a40, kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "vsub", "!0s, !1s, !2s", 4), + "vsub", "!0s, !1s, !2s", 4, kFixupNone), ENCODING_MAP(kThumb2Vsubd, 0xee300b40, kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "vsub", "!0S, !1S, !2S", 4), + "vsub", "!0S, !1S, !2S", 4, kFixupNone), ENCODING_MAP(kThumb2Vadds, 0xee300a00, kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "vadd", "!0s, !1s, !2s", 4), + "vadd", "!0s, !1s, !2s", 4, kFixupNone), ENCODING_MAP(kThumb2Vaddd, 0xee300b00, kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "vadd", "!0S, !1S, !2S", 4), + "vadd", "!0S, !1S, !2S", 4, kFixupNone), ENCODING_MAP(kThumb2Vdivs, 0xee800a00, kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "vdivs", "!0s, !1s, !2s", 4), + "vdivs", "!0s, !1s, !2s", 4, kFixupNone), ENCODING_MAP(kThumb2Vdivd, 0xee800b00, kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "vdivd", "!0S, !1S, !2S", 4), + "vdivd", "!0S, !1S, !2S", 4, kFixupNone), ENCODING_MAP(kThumb2VcvtIF, 0xeeb80ac0, kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vcvt.f32", "!0s, !1s", 4), + "vcvt.f32", "!0s, !1s", 4, kFixupNone), ENCODING_MAP(kThumb2VcvtID, 0xeeb80bc0, kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vcvt.f64", "!0S, !1s", 4), + "vcvt.f64", "!0S, !1s", 4, kFixupNone), ENCODING_MAP(kThumb2VcvtFI, 0xeebd0ac0, kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vcvt.s32.f32 ", "!0s, !1s", 4), + "vcvt.s32.f32 ", "!0s, !1s", 4, kFixupNone), ENCODING_MAP(kThumb2VcvtDI, 0xeebd0bc0, kFmtSfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vcvt.s32.f64 ", "!0s, !1S", 4), + "vcvt.s32.f64 ", "!0s, !1S", 4, kFixupNone), ENCODING_MAP(kThumb2VcvtFd, 0xeeb70ac0, kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vcvt.f64.f32 ", "!0S, !1s", 4), + "vcvt.f64.f32 ", "!0S, !1s", 4, kFixupNone), ENCODING_MAP(kThumb2VcvtDF, 0xeeb70bc0, kFmtSfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vcvt.f32.f64 ", "!0s, !1S", 4), + "vcvt.f32.f64 ", "!0s, !1S", 4, kFixupNone), ENCODING_MAP(kThumb2Vsqrts, 0xeeb10ac0, kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vsqrt.f32 ", "!0s, !1s", 4), + "vsqrt.f32 ", "!0s, !1s", 4, kFixupNone), ENCODING_MAP(kThumb2Vsqrtd, 0xeeb10bc0, kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vsqrt.f64 ", "!0S, !1S", 4), + "vsqrt.f64 ", "!0S, !1S", 4, kFixupNone), ENCODING_MAP(kThumb2MovImmShift, 0xf04f0000, /* no setflags encoding */ kFmtBitBlt, 11, 8, kFmtModImm, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0, - "mov", "!0C, #!1m", 4), + "mov", "!0C, #!1m", 4, kFixupNone), ENCODING_MAP(kThumb2MovImm16, 0xf2400000, kFmtBitBlt, 11, 8, kFmtImm16, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0, - "mov", "!0C, #!1M", 4), + "mov", "!0C, #!1M", 4, kFixupNone), ENCODING_MAP(kThumb2StrRRI12, 0xf8c00000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, - "str", "!0C, [!1C, #!2d]", 4), + "str", "!0C, [!1C, #!2d]", 4, kFixupNone), ENCODING_MAP(kThumb2LdrRRI12, 0xf8d00000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, - "ldr", "!0C, [!1C, #!2d]", 4), + "ldr", "!0C, [!1C, #!2d]", 4, kFixupNone), ENCODING_MAP(kThumb2StrRRI8Predec, 0xf8400c00, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, - "str", "!0C, [!1C, #-!2d]", 4), + "str", "!0C, [!1C, #-!2d]", 4, kFixupNone), ENCODING_MAP(kThumb2LdrRRI8Predec, 0xf8500c00, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, - "ldr", "!0C, [!1C, #-!2d]", 4), + "ldr", "!0C, [!1C, #-!2d]", 4, kFixupNone), ENCODING_MAP(kThumb2Cbnz, 0xb900, /* Note: does not affect flags */ kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH | - NEEDS_FIXUP, "cbnz", "!0C,!1t", 2), + NEEDS_FIXUP, "cbnz", "!0C,!1t", 2, kFixupCBxZ), ENCODING_MAP(kThumb2Cbz, 0xb100, /* Note: does not affect flags */ kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH | - NEEDS_FIXUP, "cbz", "!0C,!1t", 2), + NEEDS_FIXUP, "cbz", "!0C,!1t", 2, kFixupCBxZ), ENCODING_MAP(kThumb2AddRRI12, 0xf2000000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */ - "add", "!0C,!1C,#!2d", 4), + "add", "!0C,!1C,#!2d", 4, kFixupNone), ENCODING_MAP(kThumb2MovRR, 0xea4f0000, /* no setflags encoding */ kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "mov", "!0C, !1C", 4), + "mov", "!0C, !1C", 4, kFixupNone), ENCODING_MAP(kThumb2Vmovs, 0xeeb00a40, kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vmov.f32 ", " !0s, !1s", 4), + "vmov.f32 ", " !0s, !1s", 4, kFixupNone), ENCODING_MAP(kThumb2Vmovd, 0xeeb00b40, kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vmov.f64 ", " !0S, !1S", 4), + "vmov.f64 ", " !0S, !1S", 4, kFixupNone), ENCODING_MAP(kThumb2Ldmia, 0xe8900000, kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD, - "ldmia", "!0C!!, ", 4), + "ldmia", "!0C!!, ", 4, kFixupNone), ENCODING_MAP(kThumb2Stmia, 0xe8800000, kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE0 | REG_USE_LIST1 | IS_STORE, - "stmia", "!0C!!, ", 4), + "stmia", "!0C!!, ", 4, kFixupNone), ENCODING_MAP(kThumb2AddRRR, 0xeb100000, /* setflags encoding */ kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES, - "adds", "!0C, !1C, !2C!3H", 4), + "adds", "!0C, !1C, !2C!3H", 4, kFixupNone), ENCODING_MAP(kThumb2SubRRR, 0xebb00000, /* setflags enconding */ kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES, - "subs", "!0C, !1C, !2C!3H", 4), + "subs", "!0C, !1C, !2C!3H", 4, kFixupNone), ENCODING_MAP(kThumb2SbcRRR, 0xeb700000, /* setflags encoding */ kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12 | USES_CCODES | SETS_CCODES, - "sbcs", "!0C, !1C, !2C!3H", 4), + "sbcs", "!0C, !1C, !2C!3H", 4, kFixupNone), ENCODING_MAP(kThumb2CmpRR, 0xebb00f00, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | SETS_CCODES, - "cmp", "!0C, !1C", 4), + "cmp", "!0C, !1C", 4, kFixupNone), ENCODING_MAP(kThumb2SubRRI12, 0xf2a00000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */ - "sub", "!0C,!1C,#!2d", 4), + "sub", "!0C,!1C,#!2d", 4, kFixupNone), ENCODING_MAP(kThumb2MvnImm12, 0xf06f0000, /* no setflags encoding */ kFmtBitBlt, 11, 8, kFmtImm12, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0, - "mvn", "!0C, #!1n", 4), + "mvn", "!0C, #!1n", 4, kFixupNone), ENCODING_MAP(kThumb2Sel, 0xfaa0f080, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | USES_CCODES, - "sel", "!0C, !1C, !2C", 4), + "sel", "!0C, !1C, !2C", 4, kFixupNone), ENCODING_MAP(kThumb2Ubfx, 0xf3c00000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtLsb, -1, -1, kFmtBWidth, 4, 0, IS_QUAD_OP | REG_DEF0_USE1, - "ubfx", "!0C, !1C, #!2d, #!3d", 4), + "ubfx", "!0C, !1C, #!2d, #!3d", 4, kFixupNone), ENCODING_MAP(kThumb2Sbfx, 0xf3400000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtLsb, -1, -1, kFmtBWidth, 4, 0, IS_QUAD_OP | REG_DEF0_USE1, - "sbfx", "!0C, !1C, #!2d, #!3d", 4), + "sbfx", "!0C, !1C, #!2d, #!3d", 4, kFixupNone), ENCODING_MAP(kThumb2LdrRRR, 0xf8500000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD, - "ldr", "!0C, [!1C, !2C, LSL #!3d]", 4), + "ldr", "!0C, [!1C, !2C, LSL #!3d]", 4, kFixupNone), ENCODING_MAP(kThumb2LdrhRRR, 0xf8300000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD, - "ldrh", "!0C, [!1C, !2C, LSL #!3d]", 4), + "ldrh", "!0C, [!1C, !2C, LSL #!3d]", 4, kFixupNone), ENCODING_MAP(kThumb2LdrshRRR, 0xf9300000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD, - "ldrsh", "!0C, [!1C, !2C, LSL #!3d]", 4), + "ldrsh", "!0C, [!1C, !2C, LSL #!3d]", 4, kFixupNone), ENCODING_MAP(kThumb2LdrbRRR, 0xf8100000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD, - "ldrb", "!0C, [!1C, !2C, LSL #!3d]", 4), + "ldrb", "!0C, [!1C, !2C, LSL #!3d]", 4, kFixupNone), ENCODING_MAP(kThumb2LdrsbRRR, 0xf9100000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD, - "ldrsb", "!0C, [!1C, !2C, LSL #!3d]", 4), + "ldrsb", "!0C, [!1C, !2C, LSL #!3d]", 4, kFixupNone), ENCODING_MAP(kThumb2StrRRR, 0xf8400000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE, - "str", "!0C, [!1C, !2C, LSL #!3d]", 4), + "str", "!0C, [!1C, !2C, LSL #!3d]", 4, kFixupNone), ENCODING_MAP(kThumb2StrhRRR, 0xf8200000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE, - "strh", "!0C, [!1C, !2C, LSL #!3d]", 4), + "strh", "!0C, [!1C, !2C, LSL #!3d]", 4, kFixupNone), ENCODING_MAP(kThumb2StrbRRR, 0xf8000000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE, - "strb", "!0C, [!1C, !2C, LSL #!3d]", 4), + "strb", "!0C, [!1C, !2C, LSL #!3d]", 4, kFixupNone), ENCODING_MAP(kThumb2LdrhRRI12, 0xf8b00000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, - "ldrh", "!0C, [!1C, #!2d]", 4), + "ldrh", "!0C, [!1C, #!2d]", 4, kFixupNone), ENCODING_MAP(kThumb2LdrshRRI12, 0xf9b00000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, - "ldrsh", "!0C, [!1C, #!2d]", 4), + "ldrsh", "!0C, [!1C, #!2d]", 4, kFixupNone), ENCODING_MAP(kThumb2LdrbRRI12, 0xf8900000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, - "ldrb", "!0C, [!1C, #!2d]", 4), + "ldrb", "!0C, [!1C, #!2d]", 4, kFixupNone), ENCODING_MAP(kThumb2LdrsbRRI12, 0xf9900000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, - "ldrsb", "!0C, [!1C, #!2d]", 4), + "ldrsb", "!0C, [!1C, #!2d]", 4, kFixupNone), ENCODING_MAP(kThumb2StrhRRI12, 0xf8a00000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, - "strh", "!0C, [!1C, #!2d]", 4), + "strh", "!0C, [!1C, #!2d]", 4, kFixupNone), ENCODING_MAP(kThumb2StrbRRI12, 0xf8800000, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, - "strb", "!0C, [!1C, #!2d]", 4), + "strb", "!0C, [!1C, #!2d]", 4, kFixupNone), ENCODING_MAP(kThumb2Pop, 0xe8bd0000, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 - | IS_LOAD | NEEDS_FIXUP, "pop", "", 4), + | IS_LOAD | NEEDS_FIXUP, "pop", "", 4, kFixupPushPop), ENCODING_MAP(kThumb2Push, 0xe92d0000, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0 - | IS_STORE | NEEDS_FIXUP, "push", "", 4), + | IS_STORE | NEEDS_FIXUP, "push", "", 4, kFixupPushPop), ENCODING_MAP(kThumb2CmpRI12, 0xf1b00f00, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | SETS_CCODES, - "cmp", "!0C, #!1m", 4), + "cmp", "!0C, #!1m", 4, kFixupNone), ENCODING_MAP(kThumb2AdcRRR, 0xeb500000, /* setflags encoding */ kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES, - "adcs", "!0C, !1C, !2C!3H", 4), + "adcs", "!0C, !1C, !2C!3H", 4, kFixupNone), ENCODING_MAP(kThumb2AndRRR, 0xea000000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12, - "and", "!0C, !1C, !2C!3H", 4), + "and", "!0C, !1C, !2C!3H", 4, kFixupNone), ENCODING_MAP(kThumb2BicRRR, 0xea200000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12, - "bic", "!0C, !1C, !2C!3H", 4), + "bic", "!0C, !1C, !2C!3H", 4, kFixupNone), ENCODING_MAP(kThumb2CmnRR, 0xeb000000, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "cmn", "!0C, !1C, shift !2d", 4), + "cmn", "!0C, !1C, shift !2d", 4, kFixupNone), ENCODING_MAP(kThumb2EorRRR, 0xea800000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12, - "eor", "!0C, !1C, !2C!3H", 4), + "eor", "!0C, !1C, !2C!3H", 4, kFixupNone), ENCODING_MAP(kThumb2MulRRR, 0xfb00f000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "mul", "!0C, !1C, !2C", 4), + "mul", "!0C, !1C, !2C", 4, kFixupNone), ENCODING_MAP(kThumb2MnvRR, 0xea6f0000, kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, - "mvn", "!0C, !1C, shift !2d", 4), + "mvn", "!0C, !1C, shift !2d", 4, kFixupNone), ENCODING_MAP(kThumb2RsubRRI8, 0xf1d00000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "rsb", "!0C,!1C,#!2m", 4), + "rsb", "!0C,!1C,#!2m", 4, kFixupNone), ENCODING_MAP(kThumb2NegRR, 0xf1d00000, /* instance of rsub */ kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "neg", "!0C,!1C", 4), + "neg", "!0C,!1C", 4, kFixupNone), ENCODING_MAP(kThumb2OrrRRR, 0xea400000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12, - "orr", "!0C, !1C, !2C!3H", 4), + "orr", "!0C, !1C, !2C!3H", 4, kFixupNone), ENCODING_MAP(kThumb2TstRR, 0xea100f00, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | SETS_CCODES, - "tst", "!0C, !1C, shift !2d", 4), + "tst", "!0C, !1C, shift !2d", 4, kFixupNone), ENCODING_MAP(kThumb2LslRRR, 0xfa00f000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "lsl", "!0C, !1C, !2C", 4), + "lsl", "!0C, !1C, !2C", 4, kFixupNone), ENCODING_MAP(kThumb2LsrRRR, 0xfa20f000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "lsr", "!0C, !1C, !2C", 4), + "lsr", "!0C, !1C, !2C", 4, kFixupNone), ENCODING_MAP(kThumb2AsrRRR, 0xfa40f000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "asr", "!0C, !1C, !2C", 4), + "asr", "!0C, !1C, !2C", 4, kFixupNone), ENCODING_MAP(kThumb2RorRRR, 0xfa60f000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "ror", "!0C, !1C, !2C", 4), + "ror", "!0C, !1C, !2C", 4, kFixupNone), ENCODING_MAP(kThumb2LslRRI5, 0xea4f0000, kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, - "lsl", "!0C, !1C, #!2d", 4), + "lsl", "!0C, !1C, #!2d", 4, kFixupNone), ENCODING_MAP(kThumb2LsrRRI5, 0xea4f0010, kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, - "lsr", "!0C, !1C, #!2d", 4), + "lsr", "!0C, !1C, #!2d", 4, kFixupNone), ENCODING_MAP(kThumb2AsrRRI5, 0xea4f0020, kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, - "asr", "!0C, !1C, #!2d", 4), + "asr", "!0C, !1C, #!2d", 4, kFixupNone), ENCODING_MAP(kThumb2RorRRI5, 0xea4f0030, kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, - "ror", "!0C, !1C, #!2d", 4), + "ror", "!0C, !1C, #!2d", 4, kFixupNone), ENCODING_MAP(kThumb2BicRRI8, 0xf0200000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, - "bic", "!0C, !1C, #!2m", 4), + "bic", "!0C, !1C, #!2m", 4, kFixupNone), ENCODING_MAP(kThumb2AndRRI8, 0xf0000000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, - "and", "!0C, !1C, #!2m", 4), + "and", "!0C, !1C, #!2m", 4, kFixupNone), ENCODING_MAP(kThumb2OrrRRI8, 0xf0400000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, - "orr", "!0C, !1C, #!2m", 4), + "orr", "!0C, !1C, #!2m", 4, kFixupNone), ENCODING_MAP(kThumb2EorRRI8, 0xf0800000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, - "eor", "!0C, !1C, #!2m", 4), + "eor", "!0C, !1C, #!2m", 4, kFixupNone), ENCODING_MAP(kThumb2AddRRI8, 0xf1100000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "adds", "!0C, !1C, #!2m", 4), + "adds", "!0C, !1C, #!2m", 4, kFixupNone), ENCODING_MAP(kThumb2AdcRRI8, 0xf1500000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES | USES_CCODES, - "adcs", "!0C, !1C, #!2m", 4), + "adcs", "!0C, !1C, #!2m", 4, kFixupNone), ENCODING_MAP(kThumb2SubRRI8, 0xf1b00000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "subs", "!0C, !1C, #!2m", 4), + "subs", "!0C, !1C, #!2m", 4, kFixupNone), ENCODING_MAP(kThumb2SbcRRI8, 0xf1700000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES | USES_CCODES, - "sbcs", "!0C, !1C, #!2m", 4), + "sbcs", "!0C, !1C, #!2m", 4, kFixupNone), ENCODING_MAP(kThumb2It, 0xbf00, kFmtBitBlt, 7, 4, kFmtBitBlt, 3, 0, kFmtModImm, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | IS_IT | USES_CCODES, - "it:!1b", "!0c", 2), + "it:!1b", "!0c", 2, kFixupNone), ENCODING_MAP(kThumb2Fmstat, 0xeef1fa10, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, NO_OPERAND | SETS_CCODES, - "fmstat", "", 4), + "fmstat", "", 4, kFixupNone), ENCODING_MAP(kThumb2Vcmpd, 0xeeb40b40, kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01, - "vcmp.f64", "!0S, !1S", 4), + "vcmp.f64", "!0S, !1S", 4, kFixupNone), ENCODING_MAP(kThumb2Vcmps, 0xeeb40a40, kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01, - "vcmp.f32", "!0s, !1s", 4), + "vcmp.f32", "!0s, !1s", 4, kFixupNone), ENCODING_MAP(kThumb2LdrPcRel12, 0xf8df0000, kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC | IS_LOAD | NEEDS_FIXUP, - "ldr", "!0C, [r15pc, #!1d]", 4), + "ldr", "!0C, [r15pc, #!1d]", 4, kFixupLoad), ENCODING_MAP(kThumb2BCond, 0xf0008000, kFmtBrOffset, -1, -1, kFmtBitBlt, 25, 22, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | USES_CCODES | NEEDS_FIXUP, - "b!1c", "!0t", 4), + "b!1c", "!0t", 4, kFixupCondBranch), ENCODING_MAP(kThumb2Vmovd_RR, 0xeeb00b40, kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vmov.f64", "!0S, !1S", 4), + "vmov.f64", "!0S, !1S", 4, kFixupNone), ENCODING_MAP(kThumb2Vmovs_RR, 0xeeb00a40, kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vmov.f32", "!0s, !1s", 4), + "vmov.f32", "!0s, !1s", 4, kFixupNone), ENCODING_MAP(kThumb2Fmrs, 0xee100a10, kFmtBitBlt, 15, 12, kFmtSfp, 7, 16, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "fmrs", "!0C, !1s", 4), + "fmrs", "!0C, !1s", 4, kFixupNone), ENCODING_MAP(kThumb2Fmsr, 0xee000a10, kFmtSfp, 7, 16, kFmtBitBlt, 15, 12, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "fmsr", "!0s, !1C", 4), + "fmsr", "!0s, !1C", 4, kFixupNone), ENCODING_MAP(kThumb2Fmrrd, 0xec500b10, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtDfp, 5, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF01_USE2, - "fmrrd", "!0C, !1C, !2S", 4), + "fmrrd", "!0C, !1C, !2S", 4, kFixupNone), ENCODING_MAP(kThumb2Fmdrr, 0xec400b10, kFmtDfp, 5, 0, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, - "fmdrr", "!0S, !1C, !2C", 4), + "fmdrr", "!0S, !1C, !2C", 4, kFixupNone), ENCODING_MAP(kThumb2Vabsd, 0xeeb00bc0, kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vabs.f64", "!0S, !1S", 4), + "vabs.f64", "!0S, !1S", 4, kFixupNone), ENCODING_MAP(kThumb2Vabss, 0xeeb00ac0, kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vabs.f32", "!0s, !1s", 4), + "vabs.f32", "!0s, !1s", 4, kFixupNone), ENCODING_MAP(kThumb2Vnegd, 0xeeb10b40, kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vneg.f64", "!0S, !1S", 4), + "vneg.f64", "!0S, !1S", 4, kFixupNone), ENCODING_MAP(kThumb2Vnegs, 0xeeb10a40, kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, - "vneg.f32", "!0s, !1s", 4), + "vneg.f32", "!0s, !1s", 4, kFixupNone), ENCODING_MAP(kThumb2Vmovs_IMM8, 0xeeb00a00, kFmtSfp, 22, 12, kFmtFPImm, 16, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0, - "vmov.f32", "!0s, #0x!1h", 4), + "vmov.f32", "!0s, #0x!1h", 4, kFixupNone), ENCODING_MAP(kThumb2Vmovd_IMM8, 0xeeb00b00, kFmtDfp, 22, 12, kFmtFPImm, 16, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0, - "vmov.f64", "!0S, #0x!1h", 4), + "vmov.f64", "!0S, #0x!1h", 4, kFixupNone), ENCODING_MAP(kThumb2Mla, 0xfb000000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtBitBlt, 15, 12, IS_QUAD_OP | REG_DEF0 | REG_USE1 | REG_USE2 | REG_USE3, - "mla", "!0C, !1C, !2C, !3C", 4), + "mla", "!0C, !1C, !2C, !3C", 4, kFixupNone), ENCODING_MAP(kThumb2Umull, 0xfba00000, kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, IS_QUAD_OP | REG_DEF0 | REG_DEF1 | REG_USE2 | REG_USE3, - "umull", "!0C, !1C, !2C, !3C", 4), + "umull", "!0C, !1C, !2C, !3C", 4, kFixupNone), ENCODING_MAP(kThumb2Ldrex, 0xe8500f00, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, - "ldrex", "!0C, [!1C, #!2E]", 4), + "ldrex", "!0C, [!1C, #!2E]", 4, kFixupNone), ENCODING_MAP(kThumb2Strex, 0xe8400000, kFmtBitBlt, 11, 8, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, IS_QUAD_OP | REG_DEF0_USE12 | IS_STORE, - "strex", "!0C,!1C, [!2C, #!2E]", 4), + "strex", "!0C,!1C, [!2C, #!2E]", 4, kFixupNone), ENCODING_MAP(kThumb2Clrex, 0xf3bf8f2f, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, NO_OPERAND, - "clrex", "", 4), + "clrex", "", 4, kFixupNone), ENCODING_MAP(kThumb2Bfi, 0xf3600000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtShift5, -1, -1, kFmtBitBlt, 4, 0, IS_QUAD_OP | REG_DEF0_USE1, - "bfi", "!0C,!1C,#!2d,#!3d", 4), + "bfi", "!0C,!1C,#!2d,#!3d", 4, kFixupNone), ENCODING_MAP(kThumb2Bfc, 0xf36f0000, kFmtBitBlt, 11, 8, kFmtShift5, -1, -1, kFmtBitBlt, 4, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0, - "bfc", "!0C,#!1d,#!2d", 4), + "bfc", "!0C,#!1d,#!2d", 4, kFixupNone), ENCODING_MAP(kThumb2Dmb, 0xf3bf8f50, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP, - "dmb", "#!0B", 4), + "dmb", "#!0B", 4, kFixupNone), ENCODING_MAP(kThumb2LdrPcReln12, 0xf85f0000, kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0 | REG_USE_PC | IS_LOAD, - "ldr", "!0C, [r15pc, -#!1d]", 4), + "ldr", "!0C, [r15pc, -#!1d]", 4, kFixupNone), ENCODING_MAP(kThumb2Stm, 0xe9000000, kFmtBitBlt, 19, 16, kFmtBitBlt, 12, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_USE_LIST1 | IS_STORE, - "stm", "!0C, ", 4), + "stm", "!0C, ", 4, kFixupNone), ENCODING_MAP(kThumbUndefined, 0xde00, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, NO_OPERAND, - "undefined", "", 2), + "undefined", "", 2, kFixupNone), // NOTE: vpop, vpush hard-encoded for s16+ reg list ENCODING_MAP(kThumb2VPopCS, 0xecbd8a00, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_FPCS_LIST0 - | IS_LOAD, "vpop", "", 4), + | IS_LOAD, "vpop", "", 4, kFixupNone), ENCODING_MAP(kThumb2VPushCS, 0xed2d8a00, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_FPCS_LIST0 - | IS_STORE, "vpush", "", 4), + | IS_STORE, "vpush", "", 4, kFixupNone), ENCODING_MAP(kThumb2Vldms, 0xec900a00, kFmtBitBlt, 19, 16, kFmtSfp, 22, 12, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE0 | REG_DEF_FPCS_LIST2 - | IS_LOAD, "vldms", "!0C, ", 4), + | IS_LOAD, "vldms", "!0C, ", 4, kFixupNone), ENCODING_MAP(kThumb2Vstms, 0xec800a00, kFmtBitBlt, 19, 16, kFmtSfp, 22, 12, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE0 | REG_USE_FPCS_LIST2 - | IS_STORE, "vstms", "!0C, ", 4), + | IS_STORE, "vstms", "!0C, ", 4, kFixupNone), ENCODING_MAP(kThumb2BUncond, 0xf0009000, kFmtOff24, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH, - "b", "!0t", 4), + "b", "!0t", 4, kFixupT2Branch), ENCODING_MAP(kThumb2MovImm16H, 0xf2c00000, kFmtBitBlt, 11, 8, kFmtImm16, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0 | REG_USE0, - "movt", "!0C, #!1M", 4), + "movt", "!0C, #!1M", 4, kFixupNone), ENCODING_MAP(kThumb2AddPCR, 0x4487, kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, - IS_UNARY_OP | REG_USE0 | IS_BRANCH, - "add", "rPC, !0C", 2), + IS_UNARY_OP | REG_USE0 | IS_BRANCH | NEEDS_FIXUP, + "add", "rPC, !0C", 2, kFixupLabel), ENCODING_MAP(kThumb2Adr, 0xf20f0000, kFmtBitBlt, 11, 8, kFmtImm12, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, /* Note: doesn't affect flags */ IS_TERTIARY_OP | REG_DEF0 | NEEDS_FIXUP, - "adr", "!0C,#!1d", 4), + "adr", "!0C,#!1d", 4, kFixupAdr), ENCODING_MAP(kThumb2MovImm16LST, 0xf2400000, kFmtBitBlt, 11, 8, kFmtImm16, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0 | NEEDS_FIXUP, - "mov", "!0C, #!1M", 4), + "mov", "!0C, #!1M", 4, kFixupMovImmLST), ENCODING_MAP(kThumb2MovImm16HST, 0xf2c00000, kFmtBitBlt, 11, 8, kFmtImm16, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0 | REG_USE0 | NEEDS_FIXUP, - "movt", "!0C, #!1M", 4), + "movt", "!0C, #!1M", 4, kFixupMovImmHST), ENCODING_MAP(kThumb2LdmiaWB, 0xe8b00000, kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD, - "ldmia", "!0C!!, ", 4), + "ldmia", "!0C!!, ", 4, kFixupNone), ENCODING_MAP(kThumb2SubsRRI12, 0xf1b00000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, - "subs", "!0C,!1C,#!2d", 4), + "subs", "!0C,!1C,#!2d", 4, kFixupNone), ENCODING_MAP(kThumb2OrrRRRs, 0xea500000, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES, - "orrs", "!0C, !1C, !2C!3H", 4), + "orrs", "!0C, !1C, !2C!3H", 4, kFixupNone), ENCODING_MAP(kThumb2Push1, 0xf84d0d04, kFmtBitBlt, 15, 12, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE0 - | IS_STORE, "push1", "!0C", 4), + | IS_STORE, "push1", "!0C", 4, kFixupNone), ENCODING_MAP(kThumb2Pop1, 0xf85d0b04, kFmtBitBlt, 15, 12, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF0 - | IS_LOAD, "pop1", "!0C", 4), + | IS_LOAD, "pop1", "!0C", 4, kFixupNone), ENCODING_MAP(kThumb2RsubRRR, 0xebd00000, /* setflags encoding */ kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES, - "rsbs", "!0C, !1C, !2C!3H", 4), + "rsbs", "!0C, !1C, !2C!3H", 4, kFixupNone), ENCODING_MAP(kThumb2Smull, 0xfb800000, kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, IS_QUAD_OP | REG_DEF0 | REG_DEF1 | REG_USE2 | REG_USE3, - "smull", "!0C, !1C, !2C, !3C", 4), + "smull", "!0C, !1C, !2C, !3C", 4, kFixupNone), ENCODING_MAP(kThumb2LdrdPcRel8, 0xe9df0000, kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_DEF1 | REG_USE_PC | IS_LOAD | NEEDS_FIXUP, - "ldrd", "!0C, !1C, [pc, #!2E]", 4), + "ldrd", "!0C, !1C, [pc, #!2E]", 4, kFixupLoad), ENCODING_MAP(kThumb2LdrdI8, 0xe9d00000, kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, IS_QUAD_OP | REG_DEF0 | REG_DEF1 | REG_USE2 | IS_LOAD, - "ldrd", "!0C, !1C, [!2C, #!3E]", 4), + "ldrd", "!0C, !1C, [!2C, #!3E]", 4, kFixupNone), ENCODING_MAP(kThumb2StrdI8, 0xe9c00000, kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, IS_QUAD_OP | REG_USE0 | REG_USE1 | REG_USE2 | IS_STORE, - "strd", "!0C, !1C, [!2C, #!3E]", 4), + "strd", "!0C, !1C, [!2C, #!3E]", 4, kFixupNone), }; +// new_lir replaces orig_lir in the pcrel_fixup list. +void ArmMir2Lir::ReplaceFixup(LIR* prev_lir, LIR* orig_lir, LIR* new_lir) { + new_lir->u.a.pcrel_next = orig_lir->u.a.pcrel_next; + if (UNLIKELY(prev_lir == NULL)) { + first_fixup_ = new_lir; + } else { + prev_lir->u.a.pcrel_next = new_lir; + } + orig_lir->flags.fixup = kFixupNone; +} + +// new_lir is inserted before orig_lir in the pcrel_fixup list. +void ArmMir2Lir::InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir) { + new_lir->u.a.pcrel_next = orig_lir; + if (UNLIKELY(prev_lir == NULL)) { + first_fixup_ = new_lir; + } else { + DCHECK(prev_lir->u.a.pcrel_next == orig_lir); + prev_lir->u.a.pcrel_next = new_lir; + } +} + /* * The fake NOP of moving r0 to r0 actually will incur data stalls if r0 is * not ready. Since r5FP is not updated often, it is less likely to @@ -997,404 +1019,640 @@ const ArmEncodingMap ArmMir2Lir::EncodingMap[kArmLast] = { */ #define PADDING_MOV_R5_R5 0x1C2D -/* - * Assemble the LIR into binary instruction format. Note that we may - * discover that pc-relative displacements may not fit the selected - * instruction. - */ -AssemblerStatus ArmMir2Lir::AssembleInstructions(uintptr_t start_addr) { - LIR* lir; - AssemblerStatus res = kSuccess; // Assume success - - for (lir = first_lir_insn_; lir != NULL; lir = NEXT_LIR(lir)) { - if (lir->opcode < 0) { - /* 1 means padding is needed */ - if ((lir->opcode == kPseudoPseudoAlign4) && (lir->operands[0] == 1)) { - code_buffer_.push_back(PADDING_MOV_R5_R5 & 0xFF); - code_buffer_.push_back((PADDING_MOV_R5_R5 >> 8) & 0xFF); +void ArmMir2Lir::EncodeLIR(LIR* lir) { + int opcode = lir->opcode; + if (opcode < 0) { + if (UNLIKELY(opcode == kPseudoPseudoAlign4)) { + // Note: size for this opcode will be either 0 or 2 depending on final alignment. + lir->u.a.bytes[0] = (PADDING_MOV_R5_R5 & 0xff); + lir->u.a.bytes[1] = ((PADDING_MOV_R5_R5 >> 8) & 0xff); + lir->flags.size = (lir->offset & 0x2); + } + } else if (LIKELY(!lir->flags.is_nop)) { + const ArmEncodingMap *encoder = &EncodingMap[lir->opcode]; + uint32_t bits = encoder->skeleton; + int i; + for (i = 0; i < 4; i++) { + uint32_t operand; + uint32_t value; + operand = lir->operands[i]; + ArmEncodingKind kind = encoder->field_loc[i].kind; + if (LIKELY(kind == kFmtBitBlt)) { + value = (operand << encoder->field_loc[i].start) & + ((1 << (encoder->field_loc[i].end + 1)) - 1); + bits |= value; + } else { + switch (encoder->field_loc[i].kind) { + case kFmtSkip: + break; // Nothing to do, but continue to next. + case kFmtUnused: + i = 4; // Done, break out of the enclosing loop. + break; + case kFmtFPImm: + value = ((operand & 0xF0) >> 4) << encoder->field_loc[i].end; + value |= (operand & 0x0F) << encoder->field_loc[i].start; + bits |= value; + break; + case kFmtBrOffset: + value = ((operand & 0x80000) >> 19) << 26; + value |= ((operand & 0x40000) >> 18) << 11; + value |= ((operand & 0x20000) >> 17) << 13; + value |= ((operand & 0x1f800) >> 11) << 16; + value |= (operand & 0x007ff); + bits |= value; + break; + case kFmtShift5: + value = ((operand & 0x1c) >> 2) << 12; + value |= (operand & 0x03) << 6; + bits |= value; + break; + case kFmtShift: + value = ((operand & 0x70) >> 4) << 12; + value |= (operand & 0x0f) << 4; + bits |= value; + break; + case kFmtBWidth: + value = operand - 1; + bits |= value; + break; + case kFmtLsb: + value = ((operand & 0x1c) >> 2) << 12; + value |= (operand & 0x03) << 6; + bits |= value; + break; + case kFmtImm6: + value = ((operand & 0x20) >> 5) << 9; + value |= (operand & 0x1f) << 3; + bits |= value; + break; + case kFmtDfp: { + DCHECK(ARM_DOUBLEREG(operand)); + DCHECK_EQ((operand & 0x1), 0U); + int reg_name = (operand & ARM_FP_REG_MASK) >> 1; + /* Snag the 1-bit slice and position it */ + value = ((reg_name & 0x10) >> 4) << encoder->field_loc[i].end; + /* Extract and position the 4-bit slice */ + value |= (reg_name & 0x0f) << encoder->field_loc[i].start; + bits |= value; + break; + } + case kFmtSfp: + DCHECK(ARM_SINGLEREG(operand)); + /* Snag the 1-bit slice and position it */ + value = (operand & 0x1) << encoder->field_loc[i].end; + /* Extract and position the 4-bit slice */ + value |= ((operand & 0x1e) >> 1) << encoder->field_loc[i].start; + bits |= value; + break; + case kFmtImm12: + case kFmtModImm: + value = ((operand & 0x800) >> 11) << 26; + value |= ((operand & 0x700) >> 8) << 12; + value |= operand & 0x0ff; + bits |= value; + break; + case kFmtImm16: + value = ((operand & 0x0800) >> 11) << 26; + value |= ((operand & 0xf000) >> 12) << 16; + value |= ((operand & 0x0700) >> 8) << 12; + value |= operand & 0x0ff; + bits |= value; + break; + case kFmtOff24: { + uint32_t signbit = (operand >> 31) & 0x1; + uint32_t i1 = (operand >> 22) & 0x1; + uint32_t i2 = (operand >> 21) & 0x1; + uint32_t imm10 = (operand >> 11) & 0x03ff; + uint32_t imm11 = operand & 0x07ff; + uint32_t j1 = (i1 ^ signbit) ? 0 : 1; + uint32_t j2 = (i2 ^ signbit) ? 0 : 1; + value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) | + imm11; + bits |= value; + } + break; + default: + LOG(FATAL) << "Bad fmt:" << encoder->field_loc[i].kind; + } } - continue; } - - if (lir->flags.is_nop) { - continue; + if (encoder->size == 4) { + lir->u.a.bytes[0] = ((bits >> 16) & 0xff); + lir->u.a.bytes[1] = ((bits >> 24) & 0xff); + lir->u.a.bytes[2] = (bits & 0xff); + lir->u.a.bytes[3] = ((bits >> 8) & 0xff); + } else { + DCHECK_EQ(encoder->size, 2); + lir->u.a.bytes[0] = (bits & 0xff); + lir->u.a.bytes[1] = ((bits >> 8) & 0xff); } + lir->flags.size = encoder->size; + } +} - /* - * For PC-relative displacements we won't know if the - * selected instruction will work until late (i.e. - now). - * If something doesn't fit, we must replace the short-form - * operation with a longer-form one. Note, though, that this - * can change code we've already processed, so we'll need to - * re-calculate offsets and restart. To limit the number of - * restarts, the entire list will be scanned and patched. - * Of course, the patching itself may cause new overflows so this - * is an iterative process. - */ - if (lir->flags.pcRelFixup) { - if (lir->opcode == kThumbLdrPcRel || - lir->opcode == kThumb2LdrPcRel12 || - lir->opcode == kThumbAddPcRel || - lir->opcode == kThumb2LdrdPcRel8 || - ((lir->opcode == kThumb2Vldrd) && (lir->operands[1] == r15pc)) || - ((lir->opcode == kThumb2Vldrs) && (lir->operands[1] == r15pc))) { - /* - * PC-relative loads are mostly used to load immediates - * that are too large to materialize directly in one shot. - * However, if the load displacement exceeds the limit, - * we revert to a multiple-instruction materialization sequence. - */ - LIR *lir_target = lir->target; - uintptr_t pc = (lir->offset + 4) & ~3; - uintptr_t target = lir_target->offset; - int delta = target - pc; - if (delta & 0x3) { - LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta; - } - // First, a sanity check for cases we shouldn't see now - if (((lir->opcode == kThumbAddPcRel) && (delta > 1020)) || - ((lir->opcode == kThumbLdrPcRel) && (delta > 1020))) { - // Shouldn't happen in current codegen. - LOG(FATAL) << "Unexpected pc-rel offset " << delta; - } - // Now, check for the difficult cases - if (((lir->opcode == kThumb2LdrPcRel12) && (delta > 4091)) || - ((lir->opcode == kThumb2LdrdPcRel8) && (delta > 1020)) || - ((lir->opcode == kThumb2Vldrs) && (delta > 1020)) || - ((lir->opcode == kThumb2Vldrd) && (delta > 1020))) { +// Assemble the LIR into binary instruction format. +void ArmMir2Lir::AssembleLIR() { + LIR* lir; + LIR* prev_lir; + int assembler_retries = 0; + int starting_offset = EncodeRange(first_lir_insn_, last_lir_insn_, 0); + data_offset_ = (starting_offset + 0x3) & ~0x3; + int offset_adjustment; + AssignDataOffsets(); + + /* + * Note: generation must be 1 on first pass (to distinguish from initialized state of 0 for non-visited nodes). + * Start at zero here, and bit will be flipped to 1 on entry to the loop. + */ + int generation = 0; + while (true) { + offset_adjustment = 0; + AssemblerStatus res = kSuccess; // Assume success + generation ^= 1; + // Note: nodes requring possible fixup linked in ascending order. + lir = first_fixup_; + prev_lir = NULL; + while (lir != NULL) { + /* + * NOTE: the lir being considered here will be encoded following the switch (so long as + * we're not in a retry situation). However, any new non-pc_rel instructions inserted + * due to retry must be explicitly encoded at the time of insertion. Note that + * inserted instructions don't need use/def flags, but do need size and pc-rel status + * properly updated. + */ + lir->offset += offset_adjustment; + // During pass, allows us to tell whether a node has been updated with offset_adjustment yet. + lir->flags.generation = generation; + switch (static_cast(lir->flags.fixup)) { + case kFixupLabel: + case kFixupNone: + break; + case kFixupVLoad: + if (lir->operands[1] != r15pc) { + break; + } + // NOTE: intentional fallthrough. + case kFixupLoad: { /* - * Note: because rARM_LR may be used to fix up out-of-range - * vldrs/vldrd we include REG_DEF_LR in the resource - * masks for these instructions. + * PC-relative loads are mostly used to load immediates + * that are too large to materialize directly in one shot. + * However, if the load displacement exceeds the limit, + * we revert to a multiple-instruction materialization sequence. */ - int base_reg = ((lir->opcode == kThumb2LdrdPcRel8) || (lir->opcode == kThumb2LdrPcRel12)) - ? lir->operands[0] : rARM_LR; + LIR *lir_target = lir->target; + uintptr_t pc = (lir->offset + 4) & ~3; + uintptr_t target = lir_target->offset + + ((lir_target->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); + int delta = target - pc; + if (res != kSuccess) { + /* + * In this case, we're just estimating and will do it again for real. Ensure offset + * is legal. + */ + delta &= ~0x3; + } + DCHECK_EQ((delta & 0x3), 0); + // First, a sanity check for cases we shouldn't see now + if (kIsDebugBuild && (((lir->opcode == kThumbAddPcRel) && (delta > 1020)) || + ((lir->opcode == kThumbLdrPcRel) && (delta > 1020)))) { + // Shouldn't happen in current codegen. + LOG(FATAL) << "Unexpected pc-rel offset " << delta; + } + // Now, check for the difficult cases + if (((lir->opcode == kThumb2LdrPcRel12) && (delta > 4091)) || + ((lir->opcode == kThumb2LdrdPcRel8) && (delta > 1020)) || + ((lir->opcode == kThumb2Vldrs) && (delta > 1020)) || + ((lir->opcode == kThumb2Vldrd) && (delta > 1020))) { + /* + * Note: The reason vldrs/vldrd include rARM_LR in their use/def masks is that we + * sometimes have to use it to fix up out-of-range accesses. This is where that + * happens. + */ + int base_reg = ((lir->opcode == kThumb2LdrdPcRel8) || + (lir->opcode == kThumb2LdrPcRel12)) ? lir->operands[0] : rARM_LR; - // Add new Adr to generate the address. - LIR* new_adr = RawLIR(lir->dalvik_offset, kThumb2Adr, - base_reg, 0, 0, 0, 0, lir->target); - InsertLIRBefore(lir, new_adr); + // Add new Adr to generate the address. + LIR* new_adr = RawLIR(lir->dalvik_offset, kThumb2Adr, + base_reg, 0, 0, 0, 0, lir->target); + new_adr->offset = lir->offset; + new_adr->flags.fixup = kFixupAdr; + new_adr->flags.size = EncodingMap[kThumb2Adr].size; + InsertLIRBefore(lir, new_adr); + lir->offset += new_adr->flags.size; + offset_adjustment += new_adr->flags.size; - // Convert to normal load. - if (lir->opcode == kThumb2LdrPcRel12) { - lir->opcode = kThumb2LdrRRI12; - } else if (lir->opcode == kThumb2LdrdPcRel8) { - lir->opcode = kThumb2LdrdI8; - } - // Change the load to be relative to the new Adr base. - if (lir->opcode == kThumb2LdrdI8) { - lir->operands[3] = 0; - lir->operands[2] = base_reg; + // lir no longer pcrel, unlink and link in new_adr. + ReplaceFixup(prev_lir, lir, new_adr); + + // Convert to normal load. + offset_adjustment -= lir->flags.size; + if (lir->opcode == kThumb2LdrPcRel12) { + lir->opcode = kThumb2LdrRRI12; + } else if (lir->opcode == kThumb2LdrdPcRel8) { + lir->opcode = kThumb2LdrdI8; + } + lir->flags.size = EncodingMap[lir->opcode].size; + offset_adjustment += lir->flags.size; + // Change the load to be relative to the new Adr base. + if (lir->opcode == kThumb2LdrdI8) { + lir->operands[3] = 0; + lir->operands[2] = base_reg; + } else { + lir->operands[2] = 0; + lir->operands[1] = base_reg; + } + // Must redo encoding here - won't ever revisit this node. + EncodeLIR(lir); + prev_lir = new_adr; // Continue scan with new_adr; + lir = new_adr->u.a.pcrel_next; + res = kRetryAll; + continue; } else { - lir->operands[2] = 0; - lir->operands[1] = base_reg; + if ((lir->opcode == kThumb2Vldrs) || + (lir->opcode == kThumb2Vldrd) || + (lir->opcode == kThumb2LdrdPcRel8)) { + lir->operands[2] = delta >> 2; + } else { + lir->operands[1] = (lir->opcode == kThumb2LdrPcRel12) ? delta : + delta >> 2; + } } - SetupResourceMasks(lir); - res = kRetryAll; - } else { - if ((lir->opcode == kThumb2Vldrs) || - (lir->opcode == kThumb2Vldrd) || - (lir->opcode == kThumb2LdrdPcRel8)) { - lir->operands[2] = delta >> 2; + break; + } + case kFixupCBxZ: { + LIR *target_lir = lir->target; + uintptr_t pc = lir->offset + 4; + uintptr_t target = target_lir->offset + + ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); + int delta = target - pc; + if (delta > 126 || delta < 0) { + /* + * Convert to cmp rx,#0 / b[eq/ne] tgt pair + * Make new branch instruction and insert after + */ + LIR* new_inst = + RawLIR(lir->dalvik_offset, kThumbBCond, 0, + (lir->opcode == kThumb2Cbz) ? kArmCondEq : kArmCondNe, + 0, 0, 0, lir->target); + InsertLIRAfter(lir, new_inst); + + /* Convert the cb[n]z to a cmp rx, #0 ] */ + // Subtract the old size. + offset_adjustment -= lir->flags.size; + lir->opcode = kThumbCmpRI8; + /* operand[0] is src1 in both cb[n]z & CmpRI8 */ + lir->operands[1] = 0; + lir->target = 0; + EncodeLIR(lir); // NOTE: sets flags.size. + // Add back the new size. + DCHECK_EQ(lir->flags.size, static_cast(EncodingMap[lir->opcode].size)); + offset_adjustment += lir->flags.size; + // Set up the new following inst. + new_inst->offset = lir->offset + lir->flags.size; + new_inst->flags.fixup = kFixupCondBranch; + new_inst->flags.size = EncodingMap[new_inst->opcode].size; + offset_adjustment += new_inst->flags.size; + + // lir no longer pcrel, unlink and link in new_inst. + ReplaceFixup(prev_lir, lir, new_inst); + prev_lir = new_inst; // Continue with the new instruction. + lir = new_inst->u.a.pcrel_next; + res = kRetryAll; + continue; } else { - lir->operands[1] = (lir->opcode == kThumb2LdrPcRel12) ? delta : - delta >> 2; + lir->operands[1] = delta >> 1; } + break; } - } else if (lir->opcode == kThumb2Cbnz || lir->opcode == kThumb2Cbz) { - LIR *target_lir = lir->target; - uintptr_t pc = lir->offset + 4; - uintptr_t target = target_lir->offset; - int delta = target - pc; - if (delta > 126 || delta < 0) { - /* - * Convert to cmp rx,#0 / b[eq/ne] tgt pair - * Make new branch instruction and insert after - */ - LIR* new_inst = - RawLIR(lir->dalvik_offset, kThumbBCond, 0, - (lir->opcode == kThumb2Cbz) ? kArmCondEq : kArmCondNe, - 0, 0, 0, lir->target); - InsertLIRAfter(lir, new_inst); - /* Convert the cb[n]z to a cmp rx, #0 ] */ - lir->opcode = kThumbCmpRI8; - /* operand[0] is src1 in both cb[n]z & CmpRI8 */ - lir->operands[1] = 0; - lir->target = 0; - SetupResourceMasks(lir); - /* - * Because we just added this new instruction after the current one, - * advance lir so that this new instruction won't be checked for displacement - * overflow until the next pass (when its base offset will be properly established). - */ - lir = new_inst; - res = kRetryAll; - } else { - lir->operands[1] = delta >> 1; - } - } else if (lir->opcode == kThumb2Push || lir->opcode == kThumb2Pop) { - if (__builtin_popcount(lir->operands[0]) == 1) { - /* - * The standard push/pop multiple instruction - * requires at least two registers in the list. - * If we've got just one, switch to the single-reg - * encoding. - */ - lir->opcode = (lir->opcode == kThumb2Push) ? kThumb2Push1 : - kThumb2Pop1; - int reg = 0; - while (lir->operands[0]) { - if (lir->operands[0] & 0x1) { - break; - } else { - reg++; - lir->operands[0] >>= 1; + case kFixupPushPop: { + if (__builtin_popcount(lir->operands[0]) == 1) { + /* + * The standard push/pop multiple instruction + * requires at least two registers in the list. + * If we've got just one, switch to the single-reg + * encoding. + */ + lir->opcode = (lir->opcode == kThumb2Push) ? kThumb2Push1 : + kThumb2Pop1; + int reg = 0; + while (lir->operands[0]) { + if (lir->operands[0] & 0x1) { + break; + } else { + reg++; + lir->operands[0] >>= 1; + } } + lir->operands[0] = reg; + // This won't change again, don't bother unlinking, just reset fixup kind + lir->flags.fixup = kFixupNone; } - lir->operands[0] = reg; - SetupResourceMasks(lir); - res = kRetryAll; - } - } else if (lir->opcode == kThumbBCond || lir->opcode == kThumb2BCond) { - LIR *target_lir = lir->target; - int delta = 0; - DCHECK(target_lir); - uintptr_t pc = lir->offset + 4; - uintptr_t target = target_lir->offset; - delta = target - pc; - if ((lir->opcode == kThumbBCond) && (delta > 254 || delta < -256)) { - lir->opcode = kThumb2BCond; - SetupResourceMasks(lir); - res = kRetryAll; + break; } - lir->operands[0] = delta >> 1; - } else if (lir->opcode == kThumb2BUncond) { - LIR *target_lir = lir->target; - uintptr_t pc = lir->offset + 4; - uintptr_t target = target_lir->offset; - int delta = target - pc; - lir->operands[0] = delta >> 1; - if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && - lir->operands[0] == 0) { // Useless branch - NopLIR(lir); - res = kRetryAll; + case kFixupCondBranch: { + LIR *target_lir = lir->target; + int delta = 0; + DCHECK(target_lir); + uintptr_t pc = lir->offset + 4; + uintptr_t target = target_lir->offset + + ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); + delta = target - pc; + if ((lir->opcode == kThumbBCond) && (delta > 254 || delta < -256)) { + offset_adjustment -= lir->flags.size; + lir->opcode = kThumb2BCond; + lir->flags.size = EncodingMap[lir->opcode].size; + // Fixup kind remains the same. + offset_adjustment += lir->flags.size; + res = kRetryAll; + } + lir->operands[0] = delta >> 1; + break; } - } else if (lir->opcode == kThumbBUncond) { - LIR *target_lir = lir->target; - uintptr_t pc = lir->offset + 4; - uintptr_t target = target_lir->offset; - int delta = target - pc; - if (delta > 2046 || delta < -2048) { - // Convert to Thumb2BCond w/ kArmCondAl - lir->opcode = kThumb2BUncond; - lir->operands[0] = 0; - SetupResourceMasks(lir); - res = kRetryAll; - } else { + case kFixupT2Branch: { + LIR *target_lir = lir->target; + uintptr_t pc = lir->offset + 4; + uintptr_t target = target_lir->offset + + ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); + int delta = target - pc; lir->operands[0] = delta >> 1; - if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && - lir->operands[0] == -1) { // Useless branch - NopLIR(lir); + if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && lir->operands[0] == 0) { + // Useless branch + offset_adjustment -= lir->flags.size; + lir->flags.is_nop = true; + // Don't unlink - just set to do-nothing. + lir->flags.fixup = kFixupNone; res = kRetryAll; } + break; } - } else if (lir->opcode == kThumbBlx1) { - DCHECK(NEXT_LIR(lir)->opcode == kThumbBlx2); - /* cur_pc is Thumb */ - uintptr_t cur_pc = (start_addr + lir->offset + 4) & ~3; - uintptr_t target = lir->operands[1]; - - /* Match bit[1] in target with base */ - if (cur_pc & 0x2) { - target |= 0x2; + case kFixupT1Branch: { + LIR *target_lir = lir->target; + uintptr_t pc = lir->offset + 4; + uintptr_t target = target_lir->offset + + ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); + int delta = target - pc; + if (delta > 2046 || delta < -2048) { + // Convert to Thumb2BCond w/ kArmCondAl + offset_adjustment -= lir->flags.size; + lir->opcode = kThumb2BUncond; + lir->operands[0] = 0; + lir->flags.size = EncodingMap[lir->opcode].size; + lir->flags.fixup = kFixupT2Branch; + offset_adjustment += lir->flags.size; + res = kRetryAll; + } else { + lir->operands[0] = delta >> 1; + if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && lir->operands[0] == -1) { + // Useless branch + offset_adjustment -= lir->flags.size; + lir->flags.is_nop = true; + // Don't unlink - just set to do-nothing. + lir->flags.fixup = kFixupNone; + res = kRetryAll; + } + } + break; } - int delta = target - cur_pc; - DCHECK((delta >= -(1<<22)) && (delta <= ((1<<22)-2))); + case kFixupBlx1: { + DCHECK(NEXT_LIR(lir)->opcode == kThumbBlx2); + /* cur_pc is Thumb */ + uintptr_t cur_pc = (lir->offset + 4) & ~3; + uintptr_t target = lir->operands[1]; - lir->operands[0] = (delta >> 12) & 0x7ff; - NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff; - } else if (lir->opcode == kThumbBl1) { - DCHECK(NEXT_LIR(lir)->opcode == kThumbBl2); - /* Both cur_pc and target are Thumb */ - uintptr_t cur_pc = start_addr + lir->offset + 4; - uintptr_t target = lir->operands[1]; + /* Match bit[1] in target with base */ + if (cur_pc & 0x2) { + target |= 0x2; + } + int delta = target - cur_pc; + DCHECK((delta >= -(1<<22)) && (delta <= ((1<<22)-2))); - int delta = target - cur_pc; - DCHECK((delta >= -(1<<22)) && (delta <= ((1<<22)-2))); + lir->operands[0] = (delta >> 12) & 0x7ff; + NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff; + break; + } + case kFixupBl1: { + DCHECK(NEXT_LIR(lir)->opcode == kThumbBl2); + /* Both cur_pc and target are Thumb */ + uintptr_t cur_pc = lir->offset + 4; + uintptr_t target = lir->operands[1]; - lir->operands[0] = (delta >> 12) & 0x7ff; - NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff; - } else if (lir->opcode == kThumb2Adr) { - SwitchTable *tab_rec = reinterpret_cast(lir->operands[2]); - LIR* target = lir->target; - int target_disp = tab_rec ? tab_rec->offset - : target->offset; - int disp = target_disp - ((lir->offset + 4) & ~3); - if (disp < 4096) { - lir->operands[1] = disp; - } else { - // convert to ldimm16l, ldimm16h, add tgt, pc, operands[0] - // TUNING: if this case fires often, it can be improved. Not expected to be common. - LIR *new_mov16L = - RawLIR(lir->dalvik_offset, kThumb2MovImm16LST, - lir->operands[0], 0, reinterpret_cast(lir), - reinterpret_cast(tab_rec), 0, lir->target); - InsertLIRBefore(lir, new_mov16L); - LIR *new_mov16H = - RawLIR(lir->dalvik_offset, kThumb2MovImm16HST, - lir->operands[0], 0, reinterpret_cast(lir), - reinterpret_cast(tab_rec), 0, lir->target); - InsertLIRBefore(lir, new_mov16H); - if (ARM_LOWREG(lir->operands[0])) { - lir->opcode = kThumbAddRRLH; + int delta = target - cur_pc; + DCHECK((delta >= -(1<<22)) && (delta <= ((1<<22)-2))); + + lir->operands[0] = (delta >> 12) & 0x7ff; + NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff; + break; + } + case kFixupAdr: { + SwitchTable *tab_rec = reinterpret_cast(lir->operands[2]); + LIR* target = lir->target; + int target_disp = (tab_rec != NULL) ? tab_rec->offset + offset_adjustment + : target->offset + ((target->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); + int disp = target_disp - ((lir->offset + 4) & ~3); + if (disp < 4096) { + lir->operands[1] = disp; } else { - lir->opcode = kThumbAddRRHH; + // convert to ldimm16l, ldimm16h, add tgt, pc, operands[0] + // TUNING: if this case fires often, it can be improved. Not expected to be common. + LIR *new_mov16L = + RawLIR(lir->dalvik_offset, kThumb2MovImm16LST, + lir->operands[0], 0, reinterpret_cast(lir), + reinterpret_cast(tab_rec), 0, lir->target); + new_mov16L->flags.size = EncodingMap[new_mov16L->opcode].size; + new_mov16L->flags.fixup = kFixupMovImmLST; + new_mov16L->offset = lir->offset; + // Link the new instruction, retaining lir. + InsertLIRBefore(lir, new_mov16L); + lir->offset += new_mov16L->flags.size; + offset_adjustment += new_mov16L->flags.size; + InsertFixupBefore(prev_lir, lir, new_mov16L); + prev_lir = new_mov16L; // Now we've got a new prev. + + LIR *new_mov16H = + RawLIR(lir->dalvik_offset, kThumb2MovImm16HST, + lir->operands[0], 0, reinterpret_cast(lir), + reinterpret_cast(tab_rec), 0, lir->target); + new_mov16H->flags.size = EncodingMap[new_mov16H->opcode].size; + new_mov16H->flags.fixup = kFixupMovImmHST; + new_mov16H->offset = lir->offset; + // Link the new instruction, retaining lir. + InsertLIRBefore(lir, new_mov16H); + lir->offset += new_mov16H->flags.size; + offset_adjustment += new_mov16H->flags.size; + InsertFixupBefore(prev_lir, lir, new_mov16H); + prev_lir = new_mov16H; // Now we've got a new prev. + + offset_adjustment -= lir->flags.size; + if (ARM_LOWREG(lir->operands[0])) { + lir->opcode = kThumbAddRRLH; + } else { + lir->opcode = kThumbAddRRHH; + } + lir->operands[1] = rARM_PC; + lir->flags.size = EncodingMap[lir->opcode].size; + offset_adjustment += lir->flags.size; + // Must stay in fixup list and have offset updated; will be used by LST/HSP pair. + lir->flags.fixup = kFixupNone; + res = kRetryAll; } - lir->operands[1] = rARM_PC; - SetupResourceMasks(lir); - res = kRetryAll; - } - } else if (lir->opcode == kThumb2MovImm16LST) { - // operands[1] should hold disp, [2] has add, [3] has tab_rec - LIR *addPCInst = reinterpret_cast(lir->operands[2]); - SwitchTable *tab_rec = reinterpret_cast(lir->operands[3]); - // If tab_rec is null, this is a literal load. Use target - LIR* target = lir->target; - int target_disp = tab_rec ? tab_rec->offset : target->offset; - lir->operands[1] = (target_disp - (addPCInst->offset + 4)) & 0xffff; - } else if (lir->opcode == kThumb2MovImm16HST) { - // operands[1] should hold disp, [2] has add, [3] has tab_rec - LIR *addPCInst = reinterpret_cast(lir->operands[2]); - SwitchTable *tab_rec = reinterpret_cast(lir->operands[3]); - // If tab_rec is null, this is a literal load. Use target - LIR* target = lir->target; - int target_disp = tab_rec ? tab_rec->offset : target->offset; - lir->operands[1] = - ((target_disp - (addPCInst->offset + 4)) >> 16) & 0xffff; - } - } - /* - * If one of the pc-relative instructions expanded we'll have - * to make another pass. Don't bother to fully assemble the - * instruction. - */ - if (res != kSuccess) { - continue; - } - const ArmEncodingMap *encoder = &EncodingMap[lir->opcode]; - uint32_t bits = encoder->skeleton; - int i; - for (i = 0; i < 4; i++) { - uint32_t operand; - uint32_t value; - operand = lir->operands[i]; - switch (encoder->field_loc[i].kind) { - case kFmtUnused: - break; - case kFmtFPImm: - value = ((operand & 0xF0) >> 4) << encoder->field_loc[i].end; - value |= (operand & 0x0F) << encoder->field_loc[i].start; - bits |= value; - break; - case kFmtBrOffset: - value = ((operand & 0x80000) >> 19) << 26; - value |= ((operand & 0x40000) >> 18) << 11; - value |= ((operand & 0x20000) >> 17) << 13; - value |= ((operand & 0x1f800) >> 11) << 16; - value |= (operand & 0x007ff); - bits |= value; - break; - case kFmtShift5: - value = ((operand & 0x1c) >> 2) << 12; - value |= (operand & 0x03) << 6; - bits |= value; - break; - case kFmtShift: - value = ((operand & 0x70) >> 4) << 12; - value |= (operand & 0x0f) << 4; - bits |= value; - break; - case kFmtBWidth: - value = operand - 1; - bits |= value; - break; - case kFmtLsb: - value = ((operand & 0x1c) >> 2) << 12; - value |= (operand & 0x03) << 6; - bits |= value; - break; - case kFmtImm6: - value = ((operand & 0x20) >> 5) << 9; - value |= (operand & 0x1f) << 3; - bits |= value; - break; - case kFmtBitBlt: - value = (operand << encoder->field_loc[i].start) & - ((1 << (encoder->field_loc[i].end + 1)) - 1); - bits |= value; - break; - case kFmtDfp: { - DCHECK(ARM_DOUBLEREG(operand)); - DCHECK_EQ((operand & 0x1), 0U); - int reg_name = (operand & ARM_FP_REG_MASK) >> 1; - /* Snag the 1-bit slice and position it */ - value = ((reg_name & 0x10) >> 4) << encoder->field_loc[i].end; - /* Extract and position the 4-bit slice */ - value |= (reg_name & 0x0f) << encoder->field_loc[i].start; - bits |= value; break; } - case kFmtSfp: - DCHECK(ARM_SINGLEREG(operand)); - /* Snag the 1-bit slice and position it */ - value = (operand & 0x1) << encoder->field_loc[i].end; - /* Extract and position the 4-bit slice */ - value |= ((operand & 0x1e) >> 1) << encoder->field_loc[i].start; - bits |= value; - break; - case kFmtImm12: - case kFmtModImm: - value = ((operand & 0x800) >> 11) << 26; - value |= ((operand & 0x700) >> 8) << 12; - value |= operand & 0x0ff; - bits |= value; + case kFixupMovImmLST: { + // operands[1] should hold disp, [2] has add, [3] has tab_rec + LIR *addPCInst = reinterpret_cast(lir->operands[2]); + SwitchTable *tab_rec = reinterpret_cast(lir->operands[3]); + // If tab_rec is null, this is a literal load. Use target + LIR* target = lir->target; + int target_disp = tab_rec ? tab_rec->offset : target->offset; + lir->operands[1] = (target_disp - (addPCInst->offset + 4)) & 0xffff; break; - case kFmtImm16: - value = ((operand & 0x0800) >> 11) << 26; - value |= ((operand & 0xf000) >> 12) << 16; - value |= ((operand & 0x0700) >> 8) << 12; - value |= operand & 0x0ff; - bits |= value; + } + case kFixupMovImmHST: { + // operands[1] should hold disp, [2] has add, [3] has tab_rec + LIR *addPCInst = reinterpret_cast(lir->operands[2]); + SwitchTable *tab_rec = reinterpret_cast(lir->operands[3]); + // If tab_rec is null, this is a literal load. Use target + LIR* target = lir->target; + int target_disp = tab_rec ? tab_rec->offset : target->offset; + lir->operands[1] = + ((target_disp - (addPCInst->offset + 4)) >> 16) & 0xffff; break; - case kFmtOff24: { - uint32_t signbit = (operand >> 31) & 0x1; - uint32_t i1 = (operand >> 22) & 0x1; - uint32_t i2 = (operand >> 21) & 0x1; - uint32_t imm10 = (operand >> 11) & 0x03ff; - uint32_t imm11 = operand & 0x07ff; - uint32_t j1 = (i1 ^ signbit) ? 0 : 1; - uint32_t j2 = (i2 ^ signbit) ? 0 : 1; - value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) | - imm11; - bits |= value; + } + case kFixupAlign4: { + int required_size = lir->offset & 0x2; + if (lir->flags.size != required_size) { + offset_adjustment += required_size - lir->flags.size; + lir->flags.size = required_size; + res = kRetryAll; } break; + } default: - LOG(FATAL) << "Bad fmt:" << encoder->field_loc[i].kind; + LOG(FATAL) << "Unexpected case " << lir->flags.fixup; + } + /* + * If one of the pc-relative instructions expanded we'll have + * to make another pass. Don't bother to fully assemble the + * instruction. + */ + if (res == kSuccess) { + EncodeLIR(lir); + if (assembler_retries == 0) { + // Go ahead and fix up the code buffer image. + for (int i = 0; i < lir->flags.size; i++) { + code_buffer_[lir->offset + i] = lir->u.a.bytes[i]; + } + } } + prev_lir = lir; + lir = lir->u.a.pcrel_next; } - if (encoder->size == 4) { - code_buffer_.push_back((bits >> 16) & 0xff); - code_buffer_.push_back((bits >> 24) & 0xff); + + if (res == kSuccess) { + break; + } else { + assembler_retries++; + if (assembler_retries > MAX_ASSEMBLER_RETRIES) { + CodegenDump(); + LOG(FATAL) << "Assembler error - too many retries"; + } + starting_offset += offset_adjustment; + data_offset_ = (starting_offset + 0x3) & ~0x3; + AssignDataOffsets(); + } + } + + // Rebuild the CodeBuffer if we had to retry; otherwise it should be good as-is. + if (assembler_retries != 0) { + code_buffer_.clear(); + for (LIR* lir = first_lir_insn_; lir != NULL; lir = NEXT_LIR(lir)) { + if (lir->flags.is_nop) { + continue; + } else { + for (int i = 0; i < lir->flags.size; i++) { + code_buffer_.push_back(lir->u.a.bytes[i]); + } + } } - code_buffer_.push_back(bits & 0xff); - code_buffer_.push_back((bits >> 8) & 0xff); } - return res; + + data_offset_ = (code_buffer_.size() + 0x3) & ~0x3; + + // Install literals + InstallLiteralPools(); + + // Install switch tables + InstallSwitchTables(); + + // Install fill array data + InstallFillArrayData(); + + // Create the mapping table and native offset to reference map. + CreateMappingTables(); + + CreateNativeGcMap(); } int ArmMir2Lir::GetInsnSize(LIR* lir) { return EncodingMap[lir->opcode].size; } +// Encode instruction bit pattern and assign offsets. +uint32_t ArmMir2Lir::EncodeRange(LIR* head_lir, LIR* tail_lir, uint32_t offset) { + LIR* end_lir = tail_lir->next; + + /* + * A significant percentage of methods can be assembled in a single pass. We'll + * go ahead and build the code image here, leaving holes for pc-relative fixup + * codes. If the code size changes during that pass, we'll have to throw away + * this work - but if not, we're ready to go. + */ + code_buffer_.reserve(estimated_native_code_size_ + 256); // Add a little slop. + LIR* last_fixup = NULL; + for (LIR* lir = head_lir; lir != end_lir; lir = NEXT_LIR(lir)) { + lir->offset = offset; + if (!lir->flags.is_nop) { + if (lir->flags.fixup != kFixupNone) { + if (lir->opcode >= 0) { + lir->flags.size = EncodingMap[lir->opcode].size; + lir->flags.fixup = EncodingMap[lir->opcode].fixup; + } else if (UNLIKELY(lir->opcode == kPseudoPseudoAlign4)) { + lir->flags.size = (offset & 0x2); + lir->flags.fixup = kFixupAlign4; + } else { + lir->flags.size = 0; + lir->flags.fixup = kFixupLabel; + } + // Link into the fixup chain. + lir->flags.use_def_invalid = true; + lir->u.a.pcrel_next = NULL; + if (first_fixup_ == NULL) { + first_fixup_ = lir; + } else { + last_fixup->u.a.pcrel_next = lir; + } + last_fixup = lir; + } else { + EncodeLIR(lir); + } + for (int i = 0; i < lir->flags.size; i++) { + code_buffer_.push_back(lir->u.a.bytes[i]); + } + offset += lir->flags.size; + } + } + return offset; +} + +void ArmMir2Lir::AssignDataOffsets() { + /* Set up offsets for literals */ + int offset = data_offset_; + + offset = AssignLiteralOffset(offset); + + offset = AssignSwitchTablesOffset(offset); + + total_size_ = AssignFillArrayDataOffset(offset); +} + } // namespace art diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h index 1954fbac51..b75661cdfd 100644 --- a/compiler/dex/quick/arm/codegen_arm.h +++ b/compiler/dex/quick/arm/codegen_arm.h @@ -70,9 +70,14 @@ class ArmMir2Lir : public Mir2Lir { void CompilerInitializeRegAlloc(); // Required for target - miscellaneous. + void AssembleLIR(); + uint32_t EncodeRange(LIR* head_lir, LIR* tail_lir, uint32_t starting_offset); + int AssignInsnOffsets(); + void AssignOffsets(); AssemblerStatus AssembleInstructions(uintptr_t start_addr); + void EncodeLIR(LIR* lir); void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix); - void SetupTargetResourceMasks(LIR* lir); + void SetupTargetResourceMasks(LIR* lir, uint64_t flags); const char* GetTargetInstFmt(int opcode); const char* GetTargetInstName(int opcode); std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr); @@ -187,6 +192,9 @@ class ArmMir2Lir : public Mir2Lir { MIR* SpecialIdentity(MIR* mir); LIR* LoadFPConstantValue(int r_dest, int value); bool BadOverlap(RegLocation rl_src, RegLocation rl_dest); + void ReplaceFixup(LIR* prev_lir, LIR* orig_lir, LIR* new_lir); + void InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir); + void AssignDataOffsets(); }; } // namespace art diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index 07782d957f..9b0fa62b32 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -319,7 +319,18 @@ LIR* ArmMir2Lir::OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* branch; int mod_imm; ArmConditionCode arm_cond = ArmConditionEncoding(cond); - if ((ARM_LOWREG(reg)) && (check_value == 0) && + /* + * A common use of OpCmpImmBranch is for null checks, and using the Thumb 16-bit + * compare-and-branch if zero is ideal if it will reach. However, because null checks + * branch forward to a launch pad, they will frequently not reach - and thus have to + * be converted to a long form during assembly (which will trigger another assembly + * pass). Here we estimate the branch distance for checks, and if large directly + * generate the long form in an attempt to avoid an extra assembly pass. + * TODO: consider interspersing launchpads in code following unconditional branches. + */ + bool skip = ((target != NULL) && (target->opcode == kPseudoThrowTarget)); + skip &= ((cu_->code_item->insns_size_in_code_units_ - current_dalvik_offset_) > 64); + if (!skip && (ARM_LOWREG(reg)) && (check_value == 0) && ((arm_cond == kArmCondEq) || (arm_cond == kArmCondNe))) { branch = NewLIR2((arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz, reg, 0); @@ -624,7 +635,7 @@ void ArmMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) { break; } LIR* dmb = NewLIR1(kThumb2Dmb, dmb_flavor); - dmb->def_mask = ENCODE_ALL; + dmb->u.m.def_mask = ENCODE_ALL; #endif } diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc index 203a8cc55d..a4ea10b799 100644 --- a/compiler/dex/quick/arm/target_arm.cc +++ b/compiler/dex/quick/arm/target_arm.cc @@ -118,78 +118,83 @@ uint64_t ArmMir2Lir::GetPCUseDefEncoding() { return ENCODE_ARM_REG_PC; } -void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir) { +// Thumb2 specific setup. TODO: inline?: +void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) { DCHECK_EQ(cu_->instruction_set, kThumb2); + DCHECK(!lir->flags.use_def_invalid); - // Thumb2 specific setup - uint64_t flags = ArmMir2Lir::EncodingMap[lir->opcode].flags; int opcode = lir->opcode; - if (flags & REG_DEF_SP) { - lir->def_mask |= ENCODE_ARM_REG_SP; - } + // These flags are somewhat uncommon - bypass if we can. + if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 | + REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 | + REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) { + if (flags & REG_DEF_SP) { + lir->u.m.def_mask |= ENCODE_ARM_REG_SP; + } - if (flags & REG_USE_SP) { - lir->use_mask |= ENCODE_ARM_REG_SP; - } + if (flags & REG_USE_SP) { + lir->u.m.use_mask |= ENCODE_ARM_REG_SP; + } - if (flags & REG_DEF_LIST0) { - lir->def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]); - } + if (flags & REG_DEF_LIST0) { + lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]); + } - if (flags & REG_DEF_LIST1) { - lir->def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]); - } + if (flags & REG_DEF_LIST1) { + lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]); + } - if (flags & REG_DEF_FPCS_LIST0) { - lir->def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]); - } + if (flags & REG_DEF_FPCS_LIST0) { + lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]); + } - if (flags & REG_DEF_FPCS_LIST2) { - for (int i = 0; i < lir->operands[2]; i++) { - SetupRegMask(&lir->def_mask, lir->operands[1] + i); + if (flags & REG_DEF_FPCS_LIST2) { + for (int i = 0; i < lir->operands[2]; i++) { + SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i); + } } - } - if (flags & REG_USE_PC) { - lir->use_mask |= ENCODE_ARM_REG_PC; - } + if (flags & REG_USE_PC) { + lir->u.m.use_mask |= ENCODE_ARM_REG_PC; + } - /* Conservatively treat the IT block */ - if (flags & IS_IT) { - lir->def_mask = ENCODE_ALL; - } + /* Conservatively treat the IT block */ + if (flags & IS_IT) { + lir->u.m.def_mask = ENCODE_ALL; + } - if (flags & REG_USE_LIST0) { - lir->use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]); - } + if (flags & REG_USE_LIST0) { + lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]); + } - if (flags & REG_USE_LIST1) { - lir->use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]); - } + if (flags & REG_USE_LIST1) { + lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]); + } - if (flags & REG_USE_FPCS_LIST0) { - lir->use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]); - } + if (flags & REG_USE_FPCS_LIST0) { + lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]); + } - if (flags & REG_USE_FPCS_LIST2) { - for (int i = 0; i < lir->operands[2]; i++) { - SetupRegMask(&lir->use_mask, lir->operands[1] + i); + if (flags & REG_USE_FPCS_LIST2) { + for (int i = 0; i < lir->operands[2]; i++) { + SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i); + } } - } - /* Fixup for kThumbPush/lr and kThumbPop/pc */ - if (opcode == kThumbPush || opcode == kThumbPop) { - uint64_t r8Mask = GetRegMaskCommon(r8); - if ((opcode == kThumbPush) && (lir->use_mask & r8Mask)) { - lir->use_mask &= ~r8Mask; - lir->use_mask |= ENCODE_ARM_REG_LR; - } else if ((opcode == kThumbPop) && (lir->def_mask & r8Mask)) { - lir->def_mask &= ~r8Mask; - lir->def_mask |= ENCODE_ARM_REG_PC; + /* Fixup for kThumbPush/lr and kThumbPop/pc */ + if (opcode == kThumbPush || opcode == kThumbPop) { + uint64_t r8Mask = GetRegMaskCommon(r8); + if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) { + lir->u.m.use_mask &= ~r8Mask; + lir->u.m.use_mask |= ENCODE_ARM_REG_LR; + } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) { + lir->u.m.def_mask &= ~r8Mask; + lir->u.m.def_mask |= ENCODE_ARM_REG_PC; + } + } + if (flags & REG_DEF_LR) { + lir->u.m.def_mask |= ENCODE_ARM_REG_LR; } - } - if (flags & REG_DEF_LR) { - lir->def_mask |= ENCODE_ARM_REG_LR; } } @@ -466,8 +471,8 @@ void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefi /* Memory bits */ if (arm_lir && (mask & ENCODE_DALVIK_REG)) { - sprintf(buf + strlen(buf), "dr%d%s", arm_lir->alias_info & 0xffff, - (arm_lir->alias_info & 0x80000000) ? "(+1)" : ""); + sprintf(buf + strlen(buf), "dr%d%s", DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info), + DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : ""); } if (mask & ENCODE_LITERAL) { strcat(buf, "lit "); diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc index c63de69284..a7b8dfecf0 100644 --- a/compiler/dex/quick/arm/utility_arm.cc +++ b/compiler/dex/quick/arm/utility_arm.cc @@ -90,7 +90,6 @@ LIR* ArmMir2Lir::LoadFPConstantValue(int r_dest, int value) { LIR* load_pc_rel = RawLIR(current_dalvik_offset_, kThumb2Vldrs, r_dest, r15pc, 0, 0, 0, data_target); SetMemRefType(load_pc_rel, true, kLiteral); - load_pc_rel->alias_info = reinterpret_cast(data_target); AppendLIR(load_pc_rel); return load_pc_rel; } @@ -626,7 +625,6 @@ LIR* ArmMir2Lir::LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value) { r_dest_lo, r_dest_hi, r15pc, 0, 0, data_target); } SetMemRefType(res, true, kLiteral); - res->alias_info = reinterpret_cast(data_target); AppendLIR(res); } return res; diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 6e49f0bc54..617f35707c 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -45,9 +45,10 @@ bool Mir2Lir::IsInexpensiveConstant(RegLocation rl_src) { } void Mir2Lir::MarkSafepointPC(LIR* inst) { - inst->def_mask = ENCODE_ALL; + DCHECK(!inst->flags.use_def_invalid); + inst->u.m.def_mask = ENCODE_ALL; LIR* safepoint_pc = NewLIR0(kPseudoSafepointPC); - DCHECK_EQ(safepoint_pc->def_mask, ENCODE_ALL); + DCHECK_EQ(safepoint_pc->u.m.def_mask, ENCODE_ALL); } bool Mir2Lir::FastInstance(uint32_t field_idx, bool is_put, int* field_offset, bool* is_volatile) { @@ -87,10 +88,11 @@ void Mir2Lir::SetMemRefType(LIR* lir, bool is_load, int mem_type) { uint64_t *mask_ptr; uint64_t mask = ENCODE_MEM; DCHECK(GetTargetInstFlags(lir->opcode) & (IS_LOAD | IS_STORE)); + DCHECK(!lir->flags.use_def_invalid); if (is_load) { - mask_ptr = &lir->use_mask; + mask_ptr = &lir->u.m.use_mask; } else { - mask_ptr = &lir->def_mask; + mask_ptr = &lir->u.m.def_mask; } /* Clear out the memref flags */ *mask_ptr &= ~mask; @@ -127,7 +129,7 @@ void Mir2Lir::AnnotateDalvikRegAccess(LIR* lir, int reg_id, bool is_load, * Store the Dalvik register id in alias_info. Mark the MSB if it is a 64-bit * access. */ - lir->alias_info = ENCODE_ALIAS_INFO(reg_id, is64bit); + lir->flags.alias_info = ENCODE_ALIAS_INFO(reg_id, is64bit); } /* @@ -213,11 +215,11 @@ void Mir2Lir::DumpLIRInsn(LIR* lir, unsigned char* base_addr) { break; } - if (lir->use_mask && (!lir->flags.is_nop || dump_nop)) { - DUMP_RESOURCE_MASK(DumpResourceMask(lir, lir->use_mask, "use")); + if (lir->u.m.use_mask && (!lir->flags.is_nop || dump_nop)) { + DUMP_RESOURCE_MASK(DumpResourceMask(lir, lir->u.m.use_mask, "use")); } - if (lir->def_mask && (!lir->flags.is_nop || dump_nop)) { - DUMP_RESOURCE_MASK(DumpResourceMask(lir, lir->def_mask, "def")); + if (lir->u.m.def_mask && (!lir->flags.is_nop || dump_nop)) { + DUMP_RESOURCE_MASK(DumpResourceMask(lir, lir->u.m.def_mask, "def")); } } @@ -348,6 +350,7 @@ LIR* Mir2Lir::AddWordData(LIR* *constant_list_p, int value) { new_value->operands[0] = value; new_value->next = *constant_list_p; *constant_list_p = new_value; + estimated_native_code_size_ += sizeof(value); return new_value; } return NULL; @@ -431,6 +434,7 @@ void Mir2Lir::InstallSwitchTables() { int bx_offset = INVALID_OFFSET; switch (cu_->instruction_set) { case kThumb2: + DCHECK(tab_rec->anchor->flags.fixup != kFixupNone); bx_offset = tab_rec->anchor->offset + 4; break; case kX86: @@ -714,111 +718,29 @@ int Mir2Lir::AssignFillArrayDataOffset(int offset) { return offset; } -// LIR offset assignment. -int Mir2Lir::AssignInsnOffsets() { - LIR* lir; - int offset = 0; - - for (lir = first_lir_insn_; lir != NULL; lir = NEXT_LIR(lir)) { - lir->offset = offset; - if (LIKELY(lir->opcode >= 0)) { - if (!lir->flags.is_nop) { - offset += lir->flags.size; - } - } else if (UNLIKELY(lir->opcode == kPseudoPseudoAlign4)) { - if (offset & 0x2) { - offset += 2; - lir->operands[0] = 1; - } else { - lir->operands[0] = 0; - } - } - /* Pseudo opcodes don't consume space */ - } - return offset; -} - -/* - * Walk the compilation unit and assign offsets to instructions - * and literals and compute the total size of the compiled unit. - */ -void Mir2Lir::AssignOffsets() { - int offset = AssignInsnOffsets(); - - /* Const values have to be word aligned */ - offset = (offset + 3) & ~3; - - /* Set up offsets for literals */ - data_offset_ = offset; - - offset = AssignLiteralOffset(offset); - - offset = AssignSwitchTablesOffset(offset); - - offset = AssignFillArrayDataOffset(offset); - - total_size_ = offset; -} - -/* - * Go over each instruction in the list and calculate the offset from the top - * before sending them off to the assembler. If out-of-range branch distance is - * seen rearrange the instructions a bit to correct it. - */ -void Mir2Lir::AssembleLIR() { - AssignOffsets(); - int assembler_retries = 0; - /* - * Assemble here. Note that we generate code with optimistic assumptions - * and if found now to work, we'll have to redo the sequence and retry. - */ - - while (true) { - AssemblerStatus res = AssembleInstructions(0); - if (res == kSuccess) { - break; - } else { - assembler_retries++; - if (assembler_retries > MAX_ASSEMBLER_RETRIES) { - CodegenDump(); - LOG(FATAL) << "Assembler error - too many retries"; - } - // Redo offsets and try again - AssignOffsets(); - code_buffer_.clear(); - } - } - - // Install literals - InstallLiteralPools(); - - // Install switch tables - InstallSwitchTables(); - - // Install fill array data - InstallFillArrayData(); - - // Create the mapping table and native offset to reference map. - CreateMappingTables(); - - CreateNativeGcMap(); -} - /* * Insert a kPseudoCaseLabel at the beginning of the Dalvik - * offset vaddr. This label will be used to fix up the case + * offset vaddr if pretty-printing, otherise use the standard block + * label. The selected label will be used to fix up the case * branch table during the assembly phase. All resource flags * are set to prevent code motion. KeyVal is just there for debugging. */ LIR* Mir2Lir::InsertCaseLabel(int vaddr, int keyVal) { LIR* boundary_lir = &block_label_list_[mir_graph_->FindBlock(vaddr)->id]; - LIR* new_label = static_cast(arena_->Alloc(sizeof(LIR), ArenaAllocator::kAllocLIR)); - new_label->dalvik_offset = vaddr; - new_label->opcode = kPseudoCaseLabel; - new_label->operands[0] = keyVal; - new_label->def_mask = ENCODE_ALL; - InsertLIRAfter(boundary_lir, new_label); - return new_label; + LIR* res = boundary_lir; + if (cu_->verbose) { + // Only pay the expense if we're pretty-printing. + LIR* new_label = static_cast(arena_->Alloc(sizeof(LIR), ArenaAllocator::kAllocLIR)); + new_label->dalvik_offset = vaddr; + new_label->opcode = kPseudoCaseLabel; + new_label->operands[0] = keyVal; + new_label->flags.fixup = kFixupLabel; + DCHECK(!new_label->flags.use_def_invalid); + new_label->u.m.def_mask = ENCODE_ALL; + InsertLIRAfter(boundary_lir, new_label); + res = new_label; + } + return res; } void Mir2Lir::MarkPackedCaseLabels(Mir2Lir::SwitchTable *tab_rec) { @@ -951,6 +873,7 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena literal_list_(NULL), method_literal_list_(NULL), code_literal_list_(NULL), + first_fixup_(NULL), cu_(cu), mir_graph_(mir_graph), switch_tables_(arena, 4, kGrowableArraySwitchTables), @@ -964,6 +887,7 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena total_size_(0), block_label_list_(NULL), current_dalvik_offset_(0), + estimated_native_code_size_(0), reg_pool_(NULL), live_sreg_(0), num_core_spills_(0), diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 4dd55d763a..9b9fc070a0 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -30,13 +30,14 @@ namespace art { */ /* - * Generate an kPseudoBarrier marker to indicate the boundary of special + * Generate a kPseudoBarrier marker to indicate the boundary of special * blocks. */ void Mir2Lir::GenBarrier() { LIR* barrier = NewLIR0(kPseudoBarrier); /* Mark all resources as being clobbered */ - barrier->def_mask = -1; + DCHECK(!barrier->flags.use_def_invalid); + barrier->u.m.def_mask = ENCODE_ALL; } // FIXME: need to do some work to split out targets with diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index ed83863733..8270e017ad 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -810,7 +810,7 @@ int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state, OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset); LIR* ld = OpVldm(TargetReg(kArg3), regs_left); // TUNING: loosen barrier - ld->def_mask = ENCODE_ALL; + ld->u.m.def_mask = ENCODE_ALL; SetMemRefType(ld, true /* is_load */, kDalvikReg); call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx, direct_code, direct_method, type); @@ -819,7 +819,7 @@ int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state, direct_code, direct_method, type); LIR* st = OpVstm(TargetReg(kArg3), regs_left); SetMemRefType(st, false /* is_load */, kDalvikReg); - st->def_mask = ENCODE_ALL; + st->u.m.def_mask = ENCODE_ALL; call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx, direct_code, direct_method, type); } diff --git a/compiler/dex/quick/local_optimizations.cc b/compiler/dex/quick/local_optimizations.cc index cb7694de68..f915779e75 100644 --- a/compiler/dex/quick/local_optimizations.cc +++ b/compiler/dex/quick/local_optimizations.cc @@ -21,8 +21,8 @@ namespace art { #define DEBUG_OPT(X) /* Check RAW, WAR, and RAW dependency on the register operands */ -#define CHECK_REG_DEP(use, def, check) ((def & check->use_mask) || \ - ((use | def) & check->def_mask)) +#define CHECK_REG_DEP(use, def, check) ((def & check->u.m.use_mask) || \ + ((use | def) & check->u.m.def_mask)) /* Scheduler heuristics */ #define MAX_HOIST_DISTANCE 20 @@ -30,10 +30,10 @@ namespace art { #define LD_LATENCY 2 static bool IsDalvikRegisterClobbered(LIR* lir1, LIR* lir2) { - int reg1Lo = DECODE_ALIAS_INFO_REG(lir1->alias_info); - int reg1Hi = reg1Lo + DECODE_ALIAS_INFO_WIDE(lir1->alias_info); - int reg2Lo = DECODE_ALIAS_INFO_REG(lir2->alias_info); - int reg2Hi = reg2Lo + DECODE_ALIAS_INFO_WIDE(lir2->alias_info); + int reg1Lo = DECODE_ALIAS_INFO_REG(lir1->flags.alias_info); + int reg1Hi = reg1Lo + DECODE_ALIAS_INFO_WIDE(lir1->flags.alias_info); + int reg2Lo = DECODE_ALIAS_INFO_REG(lir2->flags.alias_info); + int reg2Hi = reg2Lo + DECODE_ALIAS_INFO_WIDE(lir2->flags.alias_info); return (reg1Lo == reg2Lo) || (reg1Lo == reg2Hi) || (reg1Hi == reg2Lo); } @@ -106,7 +106,7 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { bool is_this_lir_load = target_flags & IS_LOAD; LIR* check_lir; /* Use the mem mask to determine the rough memory location */ - uint64_t this_mem_mask = (this_lir->use_mask | this_lir->def_mask) & ENCODE_MEM; + uint64_t this_mem_mask = (this_lir->u.m.use_mask | this_lir->u.m.def_mask) & ENCODE_MEM; /* * Currently only eliminate redundant ld/st for constant and Dalvik @@ -116,10 +116,10 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { continue; } - uint64_t stop_def_reg_mask = this_lir->def_mask & ~ENCODE_MEM; + uint64_t stop_def_reg_mask = this_lir->u.m.def_mask & ~ENCODE_MEM; uint64_t stop_use_reg_mask; if (cu_->instruction_set == kX86) { - stop_use_reg_mask = (IS_BRANCH | this_lir->use_mask) & ~ENCODE_MEM; + stop_use_reg_mask = (IS_BRANCH | this_lir->u.m.use_mask) & ~ENCODE_MEM; } else { /* * Add pc to the resource mask to prevent this instruction @@ -127,7 +127,7 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { * region bits since stop_mask is used to check data/control * dependencies. */ - stop_use_reg_mask = (GetPCUseDefEncoding() | this_lir->use_mask) & ~ENCODE_MEM; + stop_use_reg_mask = (GetPCUseDefEncoding() | this_lir->u.m.use_mask) & ~ENCODE_MEM; } for (check_lir = NEXT_LIR(this_lir); check_lir != tail_lir; check_lir = NEXT_LIR(check_lir)) { @@ -139,7 +139,7 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { continue; } - uint64_t check_mem_mask = (check_lir->use_mask | check_lir->def_mask) & ENCODE_MEM; + uint64_t check_mem_mask = (check_lir->u.m.use_mask | check_lir->u.m.def_mask) & ENCODE_MEM; uint64_t alias_condition = this_mem_mask & check_mem_mask; bool stop_here = false; @@ -159,7 +159,7 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { */ DCHECK(!(check_flags & IS_STORE)); /* Same value && same register type */ - if (check_lir->alias_info == this_lir->alias_info && + if (check_lir->flags.alias_info == this_lir->flags.alias_info && SameRegType(check_lir->operands[0], native_reg_id)) { /* * Different destination register - insert @@ -172,7 +172,7 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { } } else if (alias_condition == ENCODE_DALVIK_REG) { /* Must alias */ - if (check_lir->alias_info == this_lir->alias_info) { + if (check_lir->flags.alias_info == this_lir->flags.alias_info) { /* Only optimize compatible registers */ bool reg_compatible = SameRegType(check_lir->operands[0], native_reg_id); if ((is_this_lir_load && is_check_lir_load) || @@ -297,7 +297,7 @@ void Mir2Lir::ApplyLoadHoisting(LIR* head_lir, LIR* tail_lir) { continue; } - uint64_t stop_use_all_mask = this_lir->use_mask; + uint64_t stop_use_all_mask = this_lir->u.m.use_mask; if (cu_->instruction_set != kX86) { /* @@ -313,7 +313,7 @@ void Mir2Lir::ApplyLoadHoisting(LIR* head_lir, LIR* tail_lir) { /* Similar as above, but just check for pure register dependency */ uint64_t stop_use_reg_mask = stop_use_all_mask & ~ENCODE_MEM; - uint64_t stop_def_reg_mask = this_lir->def_mask & ~ENCODE_MEM; + uint64_t stop_def_reg_mask = this_lir->u.m.def_mask & ~ENCODE_MEM; int next_slot = 0; bool stop_here = false; @@ -328,7 +328,7 @@ void Mir2Lir::ApplyLoadHoisting(LIR* head_lir, LIR* tail_lir) { continue; } - uint64_t check_mem_mask = check_lir->def_mask & ENCODE_MEM; + uint64_t check_mem_mask = check_lir->u.m.def_mask & ENCODE_MEM; uint64_t alias_condition = stop_use_all_mask & check_mem_mask; stop_here = false; @@ -337,7 +337,7 @@ void Mir2Lir::ApplyLoadHoisting(LIR* head_lir, LIR* tail_lir) { /* We can fully disambiguate Dalvik references */ if (alias_condition == ENCODE_DALVIK_REG) { /* Must alias or partually overlap */ - if ((check_lir->alias_info == this_lir->alias_info) || + if ((check_lir->flags.alias_info == this_lir->flags.alias_info) || IsDalvikRegisterClobbered(this_lir, check_lir)) { stop_here = true; } @@ -406,7 +406,7 @@ void Mir2Lir::ApplyLoadHoisting(LIR* head_lir, LIR* tail_lir) { LIR* prev_lir = prev_inst_list[slot+1]; /* Check the highest instruction */ - if (prev_lir->def_mask == ENCODE_ALL) { + if (prev_lir->u.m.def_mask == ENCODE_ALL) { /* * If the first instruction is a load, don't hoist anything * above it since it is unlikely to be beneficial. @@ -436,7 +436,7 @@ void Mir2Lir::ApplyLoadHoisting(LIR* head_lir, LIR* tail_lir) { */ bool prev_is_load = is_pseudo_opcode(prev_lir->opcode) ? false : (GetTargetInstFlags(prev_lir->opcode) & IS_LOAD); - if (((cur_lir->use_mask & prev_lir->def_mask) && prev_is_load) || (slot < LD_LATENCY)) { + if (((cur_lir->u.m.use_mask & prev_lir->u.m.def_mask) && prev_is_load) || (slot < LD_LATENCY)) { break; } } diff --git a/compiler/dex/quick/mips/assemble_mips.cc b/compiler/dex/quick/mips/assemble_mips.cc index dbd668b330..3a6207cfb5 100644 --- a/compiler/dex/quick/mips/assemble_mips.cc +++ b/compiler/dex/quick/mips/assemble_mips.cc @@ -526,7 +526,7 @@ AssemblerStatus MipsMir2Lir::AssembleInstructions(uintptr_t start_addr) { continue; } - if (lir->flags.pcRelFixup) { + if (lir->flags.fixup != kFixupNone) { if (lir->opcode == kMipsDelta) { /* * The "Delta" pseudo-ops load the difference between @@ -710,4 +710,97 @@ int MipsMir2Lir::GetInsnSize(LIR* lir) { return EncodingMap[lir->opcode].size; } +// LIR offset assignment. +// TODO: consolidate w/ Arm assembly mechanism. +int MipsMir2Lir::AssignInsnOffsets() { + LIR* lir; + int offset = 0; + + for (lir = first_lir_insn_; lir != NULL; lir = NEXT_LIR(lir)) { + lir->offset = offset; + if (LIKELY(lir->opcode >= 0)) { + if (!lir->flags.is_nop) { + offset += lir->flags.size; + } + } else if (UNLIKELY(lir->opcode == kPseudoPseudoAlign4)) { + if (offset & 0x2) { + offset += 2; + lir->operands[0] = 1; + } else { + lir->operands[0] = 0; + } + } + /* Pseudo opcodes don't consume space */ + } + return offset; +} + +/* + * Walk the compilation unit and assign offsets to instructions + * and literals and compute the total size of the compiled unit. + * TODO: consolidate w/ Arm assembly mechanism. + */ +void MipsMir2Lir::AssignOffsets() { + int offset = AssignInsnOffsets(); + + /* Const values have to be word aligned */ + offset = (offset + 3) & ~3; + + /* Set up offsets for literals */ + data_offset_ = offset; + + offset = AssignLiteralOffset(offset); + + offset = AssignSwitchTablesOffset(offset); + + offset = AssignFillArrayDataOffset(offset); + + total_size_ = offset; +} + +/* + * Go over each instruction in the list and calculate the offset from the top + * before sending them off to the assembler. If out-of-range branch distance is + * seen rearrange the instructions a bit to correct it. + * TODO: consolidate w/ Arm assembly mechanism. + */ +void MipsMir2Lir::AssembleLIR() { + AssignOffsets(); + int assembler_retries = 0; + /* + * Assemble here. Note that we generate code with optimistic assumptions + * and if found now to work, we'll have to redo the sequence and retry. + */ + + while (true) { + AssemblerStatus res = AssembleInstructions(0); + if (res == kSuccess) { + break; + } else { + assembler_retries++; + if (assembler_retries > MAX_ASSEMBLER_RETRIES) { + CodegenDump(); + LOG(FATAL) << "Assembler error - too many retries"; + } + // Redo offsets and try again + AssignOffsets(); + code_buffer_.clear(); + } + } + + // Install literals + InstallLiteralPools(); + + // Install switch tables + InstallSwitchTables(); + + // Install fill array data + InstallFillArrayData(); + + // Create the mapping table and native offset to reference map. + CreateMappingTables(); + + CreateNativeGcMap(); +} + } // namespace art diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h index 8d0b347a34..9671a78497 100644 --- a/compiler/dex/quick/mips/codegen_mips.h +++ b/compiler/dex/quick/mips/codegen_mips.h @@ -71,9 +71,12 @@ class MipsMir2Lir : public Mir2Lir { void CompilerInitializeRegAlloc(); // Required for target - miscellaneous. + void AssembleLIR(); + int AssignInsnOffsets(); + void AssignOffsets(); AssemblerStatus AssembleInstructions(uintptr_t start_addr); void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix); - void SetupTargetResourceMasks(LIR* lir); + void SetupTargetResourceMasks(LIR* lir, uint64_t flags); const char* GetTargetInstFmt(int opcode); const char* GetTargetInstName(int opcode); std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr); diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc index 8e768dcf18..f9d432ec75 100644 --- a/compiler/dex/quick/mips/target_mips.cc +++ b/compiler/dex/quick/mips/target_mips.cc @@ -120,22 +120,21 @@ uint64_t MipsMir2Lir::GetPCUseDefEncoding() { } -void MipsMir2Lir::SetupTargetResourceMasks(LIR* lir) { +void MipsMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) { DCHECK_EQ(cu_->instruction_set, kMips); + DCHECK(!lir->flags.use_def_invalid); // Mips-specific resource map setup here. - uint64_t flags = MipsMir2Lir::EncodingMap[lir->opcode].flags; - if (flags & REG_DEF_SP) { - lir->def_mask |= ENCODE_MIPS_REG_SP; + lir->u.m.def_mask |= ENCODE_MIPS_REG_SP; } if (flags & REG_USE_SP) { - lir->use_mask |= ENCODE_MIPS_REG_SP; + lir->u.m.use_mask |= ENCODE_MIPS_REG_SP; } if (flags & REG_DEF_LR) { - lir->def_mask |= ENCODE_MIPS_REG_LR; + lir->u.m.def_mask |= ENCODE_MIPS_REG_LR; } } @@ -269,8 +268,8 @@ void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, uint64_t mask, const char *pre } /* Memory bits */ if (mips_lir && (mask & ENCODE_DALVIK_REG)) { - sprintf(buf + strlen(buf), "dr%d%s", mips_lir->alias_info & 0xffff, - (mips_lir->alias_info & 0x80000000) ? "(+1)" : ""); + sprintf(buf + strlen(buf), "dr%d%s", DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info), + DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : ""); } if (mask & ENCODE_LITERAL) { strcat(buf, "lit "); diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h index 0ca8d8de11..314c57e02c 100644 --- a/compiler/dex/quick/mir_to_lir-inl.h +++ b/compiler/dex/quick/mir_to_lir-inl.h @@ -58,7 +58,8 @@ inline LIR* Mir2Lir::RawLIR(int dalvik_offset, int opcode, int op0, if ((opcode == kPseudoTargetLabel) || (opcode == kPseudoSafepointPC) || (opcode == kPseudoExportedPC)) { // Always make labels scheduling barriers - insn->use_mask = insn->def_mask = ENCODE_ALL; + DCHECK(!insn->flags.use_def_invalid); + insn->u.m.use_mask = insn->u.m.def_mask = ENCODE_ALL; } return insn; } @@ -141,20 +142,21 @@ inline void Mir2Lir::SetupRegMask(uint64_t* mask, int reg) { inline void Mir2Lir::SetupResourceMasks(LIR* lir) { int opcode = lir->opcode; - if (opcode <= 0) { - lir->use_mask = lir->def_mask = 0; + if ((opcode < 0) && (opcode != kPseudoBarrier)) { + lir->flags.fixup = kFixupLabel; return; } uint64_t flags = GetTargetInstFlags(opcode); if (flags & NEEDS_FIXUP) { - lir->flags.pcRelFixup = true; + // Note: target-specific setup may specialize the fixup kind. + lir->flags.fixup = kFixupLabel; } /* Get the starting size of the instruction's template */ lir->flags.size = GetInsnSize(lir); - + estimated_native_code_size_ += lir->flags.size; /* Set up the mask for resources that are updated */ if (flags & (IS_LOAD | IS_STORE)) { /* Default to heap - will catch specialized classes later */ @@ -166,39 +168,44 @@ inline void Mir2Lir::SetupResourceMasks(LIR* lir) { * turn will trash everything. */ if (flags & IS_BRANCH) { - lir->def_mask = lir->use_mask = ENCODE_ALL; + lir->u.m.def_mask = lir->u.m.use_mask = ENCODE_ALL; return; } if (flags & REG_DEF0) { - SetupRegMask(&lir->def_mask, lir->operands[0]); + SetupRegMask(&lir->u.m.def_mask, lir->operands[0]); } if (flags & REG_DEF1) { - SetupRegMask(&lir->def_mask, lir->operands[1]); + SetupRegMask(&lir->u.m.def_mask, lir->operands[1]); } + if (flags & REG_USE0) { + SetupRegMask(&lir->u.m.use_mask, lir->operands[0]); + } - if (flags & SETS_CCODES) { - lir->def_mask |= ENCODE_CCODE; + if (flags & REG_USE1) { + SetupRegMask(&lir->u.m.use_mask, lir->operands[1]); + } + + if (flags & REG_USE2) { + SetupRegMask(&lir->u.m.use_mask, lir->operands[2]); } - if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) { - int i; + if (flags & REG_USE3) { + SetupRegMask(&lir->u.m.use_mask, lir->operands[3]); + } - for (i = 0; i < 4; i++) { - if (flags & (1 << (kRegUse0 + i))) { - SetupRegMask(&lir->use_mask, lir->operands[i]); - } - } + if (flags & SETS_CCODES) { + lir->u.m.def_mask |= ENCODE_CCODE; } if (flags & USES_CCODES) { - lir->use_mask |= ENCODE_CCODE; + lir->u.m.use_mask |= ENCODE_CCODE; } // Handle target-specific actions - SetupTargetResourceMasks(lir); + SetupTargetResourceMasks(lir, flags); } inline art::Mir2Lir::RegisterInfo* Mir2Lir::GetRegInfo(int reg) { diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc index 6f398696dd..66ece2c230 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -697,6 +697,7 @@ bool Mir2Lir::MethodBlockCodeGen(BasicBlock* bb) { // Insert the block label. block_label_list_[block_id].opcode = kPseudoNormalBlockLabel; + block_label_list_[block_id].flags.fixup = kFixupLabel; AppendLIR(&block_label_list_[block_id]); LIR* head_lir = NULL; @@ -746,7 +747,8 @@ bool Mir2Lir::MethodBlockCodeGen(BasicBlock* bb) { if (head_lir == NULL) { head_lir = &block_label_list_[bb->id]; // Set the first label as a scheduling barrier. - head_lir->def_mask = ENCODE_ALL; + DCHECK(!head_lir->flags.use_def_invalid); + head_lir->u.m.def_mask = ENCODE_ALL; } if (opcode == kMirOpCheck) { diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 7d6f968da5..e48cdbc7f8 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -95,6 +95,7 @@ struct BasicBlock; struct CallInfo; struct CompilationUnit; struct MIR; +struct LIR; struct RegLocation; struct RegisterInfo; class MIRGraph; @@ -107,24 +108,36 @@ typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int, typedef std::vector CodeBuffer; +struct UseDefMasks { + uint64_t use_mask; // Resource mask for use. + uint64_t def_mask; // Resource mask for def. +}; + +struct AssemblyInfo { + LIR* pcrel_next; // Chain of LIR nodes needing pc relative fixups. + uint8_t bytes[16]; // Encoded instruction bytes. +}; struct LIR { int offset; // Offset of this instruction. - int dalvik_offset; // Offset of Dalvik opcode. + uint16_t dalvik_offset; // Offset of Dalvik opcode in code units (16-bit words). + int16_t opcode; LIR* next; LIR* prev; LIR* target; - int opcode; - int operands[5]; // [0..4] = [dest, src1, src2, extra, extra2]. struct { - bool is_nop:1; // LIR is optimized away. - bool pcRelFixup:1; // May need pc-relative fixup. - unsigned int size:5; // Note: size is in bytes. - unsigned int unused:25; + unsigned int alias_info:17; // For Dalvik register disambiguation. + bool is_nop:1; // LIR is optimized away. + unsigned int size:4; // Note: size of encoded instruction is in bytes. + bool use_def_invalid:1; // If true, masks should not be used. + unsigned int generation:1; // Used to track visitation state during fixup pass. + unsigned int fixup:8; // Fixup kind. } flags; - int alias_info; // For Dalvik register & litpool disambiguation. - uint64_t use_mask; // Resource mask for use. - uint64_t def_mask; // Resource mask for def. + union { + UseDefMasks m; // Use & Def masks used during optimization. + AssemblyInfo a; // Instruction encoding used during assembly phase. + } u; + int operands[5]; // [0..4] = [dest, src1, src2, extra, extra2]. }; // Target-specific initialization. @@ -141,7 +154,7 @@ Mir2Lir* X86CodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, // Defines for alias_info (tracks Dalvik register references). #define DECODE_ALIAS_INFO_REG(X) (X & 0xffff) -#define DECODE_ALIAS_INFO_WIDE_FLAG (0x80000000) +#define DECODE_ALIAS_INFO_WIDE_FLAG (0x10000) #define DECODE_ALIAS_INFO_WIDE(X) ((X & DECODE_ALIAS_INFO_WIDE_FLAG) ? 1 : 0) #define ENCODE_ALIAS_INFO(REG, ISWIDE) (REG | (ISWIDE ? DECODE_ALIAS_INFO_WIDE_FLAG : 0)) @@ -255,7 +268,6 @@ class Mir2Lir : public Backend { void MarkSafepointPC(LIR* inst); bool FastInstance(uint32_t field_idx, bool is_put, int* field_offset, bool* is_volatile); void SetupResourceMasks(LIR* lir); - void AssembleLIR(); void SetMemRefType(LIR* lir, bool is_load, int mem_type); void AnnotateDalvikRegAccess(LIR* lir, int reg_id, bool is_load, bool is64bit); void SetupRegMask(uint64_t* mask, int reg); @@ -295,8 +307,6 @@ class Mir2Lir : public Backend { int AssignLiteralOffset(int offset); int AssignSwitchTablesOffset(int offset); int AssignFillArrayDataOffset(int offset); - int AssignInsnOffsets(); - void AssignOffsets(); LIR* InsertCaseLabel(int vaddr, int keyVal); void MarkPackedCaseLabels(Mir2Lir::SwitchTable *tab_rec); void MarkSparseCaseLabels(Mir2Lir::SwitchTable *tab_rec); @@ -571,9 +581,9 @@ class Mir2Lir : public Backend { virtual void CompilerInitializeRegAlloc() = 0; // Required for target - miscellaneous. - virtual AssemblerStatus AssembleInstructions(uintptr_t start_addr) = 0; + virtual void AssembleLIR() = 0; virtual void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix) = 0; - virtual void SetupTargetResourceMasks(LIR* lir) = 0; + virtual void SetupTargetResourceMasks(LIR* lir, uint64_t flags) = 0; virtual const char* GetTargetInstFmt(int opcode) = 0; virtual const char* GetTargetInstName(int opcode) = 0; virtual std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) = 0; @@ -719,6 +729,7 @@ class Mir2Lir : public Backend { LIR* literal_list_; // Constants. LIR* method_literal_list_; // Method literals requiring patching. LIR* code_literal_list_; // Code literals requiring patching. + LIR* first_fixup_; // Doubly-linked list of LIR nodes requiring fixups. protected: CompilationUnit* const cu_; @@ -741,6 +752,7 @@ class Mir2Lir : public Backend { * immediately preceed the instruction. */ std::vector dex2pc_mapping_table_; + int current_code_offset_; // Working byte offset of machine instructons. int data_offset_; // starting offset of literal pool. int total_size_; // header + code size. LIR* block_label_list_; @@ -755,6 +767,7 @@ class Mir2Lir : public Backend { * The low-level LIR creation utilites will pull it from here. Rework this. */ int current_dalvik_offset_; + int estimated_native_code_size_; // Just an estimate; used to reserve code_buffer_ size. RegisterPool* reg_pool_; /* * Sanity checking for the register temp tracking. The same ssa diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc index 3e768837ff..b1634da4d9 100644 --- a/compiler/dex/quick/x86/assemble_x86.cc +++ b/compiler/dex/quick/x86/assemble_x86.cc @@ -1174,7 +1174,7 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(uintptr_t start_addr) { continue; } - if (lir->flags.pcRelFixup) { + if (lir->flags.fixup != kFixupNone) { switch (lir->opcode) { case kX86Jcc8: { LIR *target_lir = lir->target; @@ -1385,4 +1385,97 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(uintptr_t start_addr) { return res; } +// LIR offset assignment. +// TODO: consolidate w/ Arm assembly mechanism. +int X86Mir2Lir::AssignInsnOffsets() { + LIR* lir; + int offset = 0; + + for (lir = first_lir_insn_; lir != NULL; lir = NEXT_LIR(lir)) { + lir->offset = offset; + if (LIKELY(lir->opcode >= 0)) { + if (!lir->flags.is_nop) { + offset += lir->flags.size; + } + } else if (UNLIKELY(lir->opcode == kPseudoPseudoAlign4)) { + if (offset & 0x2) { + offset += 2; + lir->operands[0] = 1; + } else { + lir->operands[0] = 0; + } + } + /* Pseudo opcodes don't consume space */ + } + return offset; +} + +/* + * Walk the compilation unit and assign offsets to instructions + * and literals and compute the total size of the compiled unit. + * TODO: consolidate w/ Arm assembly mechanism. + */ +void X86Mir2Lir::AssignOffsets() { + int offset = AssignInsnOffsets(); + + /* Const values have to be word aligned */ + offset = (offset + 3) & ~3; + + /* Set up offsets for literals */ + data_offset_ = offset; + + offset = AssignLiteralOffset(offset); + + offset = AssignSwitchTablesOffset(offset); + + offset = AssignFillArrayDataOffset(offset); + + total_size_ = offset; +} + +/* + * Go over each instruction in the list and calculate the offset from the top + * before sending them off to the assembler. If out-of-range branch distance is + * seen rearrange the instructions a bit to correct it. + * TODO: consolidate w/ Arm assembly mechanism. + */ +void X86Mir2Lir::AssembleLIR() { + AssignOffsets(); + int assembler_retries = 0; + /* + * Assemble here. Note that we generate code with optimistic assumptions + * and if found now to work, we'll have to redo the sequence and retry. + */ + + while (true) { + AssemblerStatus res = AssembleInstructions(0); + if (res == kSuccess) { + break; + } else { + assembler_retries++; + if (assembler_retries > MAX_ASSEMBLER_RETRIES) { + CodegenDump(); + LOG(FATAL) << "Assembler error - too many retries"; + } + // Redo offsets and try again + AssignOffsets(); + code_buffer_.clear(); + } + } + + // Install literals + InstallLiteralPools(); + + // Install switch tables + InstallSwitchTables(); + + // Install fill array data + InstallFillArrayData(); + + // Create the mapping table and native offset to reference map. + CreateMappingTables(); + + CreateNativeGcMap(); +} + } // namespace art diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index 0f281106b2..e9eafc66f0 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -71,9 +71,12 @@ class X86Mir2Lir : public Mir2Lir { void CompilerInitializeRegAlloc(); // Required for target - miscellaneous. + void AssembleLIR(); + int AssignInsnOffsets(); + void AssignOffsets(); AssemblerStatus AssembleInstructions(uintptr_t start_addr); void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix); - void SetupTargetResourceMasks(LIR* lir); + void SetupTargetResourceMasks(LIR* lir, uint64_t flags); const char* GetTargetInstFmt(int opcode); const char* GetTargetInstName(int opcode); std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr); diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index 94dd759e91..f0808301a3 100644 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -132,37 +132,36 @@ uint64_t X86Mir2Lir::GetPCUseDefEncoding() { return 0ULL; } -void X86Mir2Lir::SetupTargetResourceMasks(LIR* lir) { +void X86Mir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) { DCHECK_EQ(cu_->instruction_set, kX86); + DCHECK(!lir->flags.use_def_invalid); // X86-specific resource map setup here. - uint64_t flags = X86Mir2Lir::EncodingMap[lir->opcode].flags; - if (flags & REG_USE_SP) { - lir->use_mask |= ENCODE_X86_REG_SP; + lir->u.m.use_mask |= ENCODE_X86_REG_SP; } if (flags & REG_DEF_SP) { - lir->def_mask |= ENCODE_X86_REG_SP; + lir->u.m.def_mask |= ENCODE_X86_REG_SP; } if (flags & REG_DEFA) { - SetupRegMask(&lir->def_mask, rAX); + SetupRegMask(&lir->u.m.def_mask, rAX); } if (flags & REG_DEFD) { - SetupRegMask(&lir->def_mask, rDX); + SetupRegMask(&lir->u.m.def_mask, rDX); } if (flags & REG_USEA) { - SetupRegMask(&lir->use_mask, rAX); + SetupRegMask(&lir->u.m.use_mask, rAX); } if (flags & REG_USEC) { - SetupRegMask(&lir->use_mask, rCX); + SetupRegMask(&lir->u.m.use_mask, rCX); } if (flags & REG_USED) { - SetupRegMask(&lir->use_mask, rDX); + SetupRegMask(&lir->u.m.use_mask, rDX); } } @@ -275,8 +274,8 @@ void X86Mir2Lir::DumpResourceMask(LIR *x86LIR, uint64_t mask, const char *prefix } /* Memory bits */ if (x86LIR && (mask & ENCODE_DALVIK_REG)) { - sprintf(buf + strlen(buf), "dr%d%s", x86LIR->alias_info & 0xffff, - (x86LIR->alias_info & 0x80000000) ? "(+1)" : ""); + sprintf(buf + strlen(buf), "dr%d%s", DECODE_ALIAS_INFO_REG(x86LIR->flags.alias_info), + (DECODE_ALIAS_INFO_WIDE(x86LIR->flags.alias_info)) ? "(+1)" : ""); } if (mask & ENCODE_LITERAL) { strcat(buf, "lit "); -- cgit v1.2.3-59-g8ed1b From 0d82948094d9a198e01aa95f64012bdedd5b6fc9 Mon Sep 17 00:00:00 2001 From: buzbee Date: Fri, 11 Oct 2013 15:24:55 -0700 Subject: 64-bit prep Preparation for 64-bit roll. o Eliminated storing pointers in 32-bit int slots in LIR. o General size reductions of common structures to reduce impact of doubled pointer sizes: - BasicBlock struct was 72 bytes, now is 48. - MIR struct was 72 bytes, now is 64. - RegLocation was 12 bytes, now is 8. o Generally replaced uses of BasicBlock* pointers with 16-bit Ids. o Replaced several doubly-linked lists with singly-linked to save one stored pointer per node. o We had quite a few uses of uintptr_t's that were a holdover from the JIT (which used pointers to mapped dex & actual code cache addresses rather than trace-relative offsets). Replaced those with uint32_t's. o Clean up handling of embedded data for switch tables and array data. o Miscellaneous cleanup. I anticipate one or two additional CLs to reduce the size of MIR and LIR structs. Change-Id: I58e426d3f8e5efe64c1146b2823453da99451230 --- compiler/dex/arena_bit_vector.h | 14 +- compiler/dex/compiler_enums.h | 1 + compiler/dex/compiler_ir.h | 10 +- compiler/dex/dataflow_iterator-inl.h | 8 +- compiler/dex/dataflow_iterator.h | 10 +- compiler/dex/mir_analysis.cc | 11 +- compiler/dex/mir_dataflow.cc | 16 +-- compiler/dex/mir_graph.cc | 220 ++++++++++++++++--------------- compiler/dex/mir_graph.h | 144 +++++++++++--------- compiler/dex/mir_optimization.cc | 84 ++++++------ compiler/dex/portable/mir_to_gbc.cc | 60 ++++----- compiler/dex/quick/arm/assemble_arm.cc | 84 ++++++------ compiler/dex/quick/arm/call_arm.cc | 20 +-- compiler/dex/quick/arm/codegen_arm.h | 7 +- compiler/dex/quick/arm/fp_arm.cc | 2 +- compiler/dex/quick/arm/int_arm.cc | 25 +--- compiler/dex/quick/arm/target_arm.cc | 4 +- compiler/dex/quick/arm/utility_arm.cc | 48 +++---- compiler/dex/quick/codegen_util.cc | 90 ++++++++----- compiler/dex/quick/gen_common.cc | 18 +-- compiler/dex/quick/gen_invoke.cc | 10 +- compiler/dex/quick/mips/assemble_mips.cc | 42 +++--- compiler/dex/quick/mips/call_mips.cc | 23 ++-- compiler/dex/quick/mips/codegen_mips.h | 2 +- compiler/dex/quick/mips/utility_mips.cc | 2 +- compiler/dex/quick/mir_to_lir-inl.h | 2 +- compiler/dex/quick/mir_to_lir.cc | 32 ++--- compiler/dex/quick/mir_to_lir.h | 123 ++++++++++------- compiler/dex/quick/ralloc_util.cc | 11 +- compiler/dex/quick/x86/assemble_x86.cc | 24 ++-- compiler/dex/quick/x86/call_x86.cc | 21 ++- compiler/dex/quick/x86/codegen_x86.h | 8 +- compiler/dex/quick/x86/fp_x86.cc | 4 +- compiler/dex/quick/x86/int_x86.cc | 2 +- compiler/dex/quick/x86/target_x86.cc | 4 +- compiler/dex/ssa_transformation.cc | 141 ++++++++++---------- 36 files changed, 695 insertions(+), 632 deletions(-) (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/arena_bit_vector.h b/compiler/dex/arena_bit_vector.h index 24a7ce9601..53e6eb6512 100644 --- a/compiler/dex/arena_bit_vector.h +++ b/compiler/dex/arena_bit_vector.h @@ -39,7 +39,7 @@ class ArenaBitVector { bit_size_(p_bits_->storage_size_ * sizeof(uint32_t) * 8) {} // Return the position of the next set bit. -1 means end-of-element reached. - int Next() { + int32_t Next() { // Did anything obviously change since we started? DCHECK_EQ(bit_size_, p_bits_->GetStorageSize() * sizeof(uint32_t) * 8); DCHECK_EQ(bit_storage_, p_bits_->GetRawStorage()); @@ -79,7 +79,7 @@ class ArenaBitVector { const uint32_t bit_size_; // Size of vector in bits. }; - ArenaBitVector(ArenaAllocator* arena, unsigned int start_bits, bool expandable, + ArenaBitVector(ArenaAllocator* arena, uint32_t start_bits, bool expandable, OatBitMapKind kind = kBitMapMisc); ~ArenaBitVector() {} @@ -88,13 +88,13 @@ class ArenaBitVector { } static void operator delete(void* p) {} // Nop. - void SetBit(unsigned int num); - void ClearBit(unsigned int num); + void SetBit(uint32_t num); + void ClearBit(uint32_t num); void MarkAllBits(bool set); void DebugBitVector(char* msg, int length); - bool IsBitSet(unsigned int num); + bool IsBitSet(uint32_t num); void ClearAllBits(); - void SetInitialBits(unsigned int num_bits); + void SetInitialBits(uint32_t num_bits); void Copy(ArenaBitVector* src) { memcpy(storage_, src->GetRawStorage(), sizeof(uint32_t) * storage_size_); } @@ -106,7 +106,7 @@ class ArenaBitVector { (expandable_ == src->IsExpandable()) && (memcmp(storage_, src->GetRawStorage(), storage_size_ * 4) == 0); } - int NumSetBits(); + int32_t NumSetBits(); uint32_t GetStorageSize() const { return storage_size_; } bool IsExpandable() const { return expandable_; } diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h index 17b5bb5b19..05ca1b565e 100644 --- a/compiler/dex/compiler_enums.h +++ b/compiler/dex/compiler_enums.h @@ -55,6 +55,7 @@ enum RegLocationType { }; enum BBType { + kNullBlock, kEntryBlock, kDalvikByteCode, kExitBlock, diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h index 6607562b13..bdc31547cb 100644 --- a/compiler/dex/compiler_ir.h +++ b/compiler/dex/compiler_ir.h @@ -90,14 +90,14 @@ struct CompilationUnit { InstructionSet instruction_set; // TODO: much of this info available elsewhere. Go to the original source? - int num_dalvik_registers; // method->registers_size. + uint16_t num_dalvik_registers; // method->registers_size. const uint16_t* insns; - int num_ins; - int num_outs; - int num_regs; // Unlike num_dalvik_registers, does not include ins. + uint16_t num_ins; + uint16_t num_outs; + uint16_t num_regs; // Unlike num_dalvik_registers, does not include ins. // TODO: may want to move this to MIRGraph. - int num_compiler_temps; + uint16_t num_compiler_temps; // If non-empty, apply optimizer/debug flags only to matching methods. std::string compiler_method_match; diff --git a/compiler/dex/dataflow_iterator-inl.h b/compiler/dex/dataflow_iterator-inl.h index 236c6f4940..74f36ddd81 100644 --- a/compiler/dex/dataflow_iterator-inl.h +++ b/compiler/dex/dataflow_iterator-inl.h @@ -25,7 +25,7 @@ namespace art { inline BasicBlock* DataflowIterator::ForwardSingleNext() { BasicBlock* res = NULL; if (idx_ < end_idx_) { - int bb_id = block_id_list_->Get(idx_++); + BasicBlockId bb_id = block_id_list_->Get(idx_++); res = mir_graph_->GetBasicBlock(bb_id); } return res; @@ -40,7 +40,7 @@ inline BasicBlock* DataflowIterator::ForwardRepeatNext(bool had_change) { changed_ = false; } if (idx_ < end_idx_) { - int bb_id = block_id_list_->Get(idx_++); + BasicBlockId bb_id = block_id_list_->Get(idx_++); res = mir_graph_->GetBasicBlock(bb_id); } return res; @@ -50,7 +50,7 @@ inline BasicBlock* DataflowIterator::ForwardRepeatNext(bool had_change) { inline BasicBlock* DataflowIterator::ReverseSingleNext() { BasicBlock* res = NULL; if (idx_ >= 0) { - int bb_id = block_id_list_->Get(idx_--); + BasicBlockId bb_id = block_id_list_->Get(idx_--); res = mir_graph_->GetBasicBlock(bb_id); } return res; @@ -65,7 +65,7 @@ inline BasicBlock* DataflowIterator::ReverseRepeatNext(bool had_change) { changed_ = false; } if (idx_ >= 0) { - int bb_id = block_id_list_->Get(idx_--); + BasicBlockId bb_id = block_id_list_->Get(idx_--); res = mir_graph_->GetBasicBlock(bb_id); } return res; diff --git a/compiler/dex/dataflow_iterator.h b/compiler/dex/dataflow_iterator.h index 1dab54ea72..26e36653be 100644 --- a/compiler/dex/dataflow_iterator.h +++ b/compiler/dex/dataflow_iterator.h @@ -39,7 +39,7 @@ namespace art { virtual ~DataflowIterator() {} protected: - DataflowIterator(MIRGraph* mir_graph, int start_idx, int end_idx) + DataflowIterator(MIRGraph* mir_graph, int32_t start_idx, int32_t end_idx) : mir_graph_(mir_graph), start_idx_(start_idx), end_idx_(end_idx), @@ -53,10 +53,10 @@ namespace art { virtual BasicBlock* ReverseRepeatNext(bool had_change) ALWAYS_INLINE; MIRGraph* const mir_graph_; - const int start_idx_; - const int end_idx_; - GrowableArray* block_id_list_; - int idx_; + const int32_t start_idx_; + const int32_t end_idx_; + GrowableArray* block_id_list_; + int32_t idx_; bool changed_; }; // DataflowIterator diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc index 8597172881..89af06e085 100644 --- a/compiler/dex/mir_analysis.cc +++ b/compiler/dex/mir_analysis.cc @@ -864,7 +864,7 @@ void MIRGraph::AnalyzeBlock(BasicBlock* bb, MethodStats* stats) { if (ending_bb->last_mir_insn != NULL) { uint32_t ending_flags = analysis_attributes_[ending_bb->last_mir_insn->dalvikInsn.opcode]; while ((ending_flags & AN_BRANCH) == 0) { - ending_bb = ending_bb->fall_through; + ending_bb = GetBasicBlock(ending_bb->fall_through); ending_flags = analysis_attributes_[ending_bb->last_mir_insn->dalvikInsn.opcode]; } } @@ -876,13 +876,14 @@ void MIRGraph::AnalyzeBlock(BasicBlock* bb, MethodStats* stats) { */ int loop_scale_factor = 1; // Simple for and while loops - if ((ending_bb->taken != NULL) && (ending_bb->fall_through == NULL)) { - if ((ending_bb->taken->taken == bb) || (ending_bb->taken->fall_through == bb)) { + if ((ending_bb->taken != NullBasicBlockId) && (ending_bb->fall_through == NullBasicBlockId)) { + if ((GetBasicBlock(ending_bb->taken)->taken == bb->id) || + (GetBasicBlock(ending_bb->taken)->fall_through == bb->id)) { loop_scale_factor = 25; } } // Simple do-while loop - if ((ending_bb->taken != NULL) && (ending_bb->taken == bb)) { + if ((ending_bb->taken != NullBasicBlockId) && (ending_bb->taken == bb->id)) { loop_scale_factor = 25; } @@ -922,7 +923,7 @@ void MIRGraph::AnalyzeBlock(BasicBlock* bb, MethodStats* stats) { if (tbb == ending_bb) { done = true; } else { - tbb = tbb->fall_through; + tbb = GetBasicBlock(tbb->fall_through); } } if (has_math && computational_block && (loop_scale_factor > 1)) { diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc index 3d29908e9f..9c8ce23ca5 100644 --- a/compiler/dex/mir_dataflow.cc +++ b/compiler/dex/mir_dataflow.cc @@ -1295,23 +1295,23 @@ void MIRGraph::MethodUseCount() { /* Verify if all the successor is connected with all the claimed predecessors */ bool MIRGraph::VerifyPredInfo(BasicBlock* bb) { - GrowableArray::Iterator iter(bb->predecessors); + GrowableArray::Iterator iter(bb->predecessors); while (true) { - BasicBlock *pred_bb = iter.Next(); + BasicBlock *pred_bb = GetBasicBlock(iter.Next()); if (!pred_bb) break; bool found = false; - if (pred_bb->taken == bb) { + if (pred_bb->taken == bb->id) { found = true; - } else if (pred_bb->fall_through == bb) { + } else if (pred_bb->fall_through == bb->id) { found = true; - } else if (pred_bb->successor_block_list.block_list_type != kNotUsed) { - GrowableArray::Iterator iterator(pred_bb->successor_block_list.blocks); + } else if (pred_bb->successor_block_list_type != kNotUsed) { + GrowableArray::Iterator iterator(pred_bb->successor_blocks); while (true) { SuccessorBlockInfo *successor_block_info = iterator.Next(); if (successor_block_info == NULL) break; - BasicBlock *succ_bb = successor_block_info->block; - if (succ_bb == bb) { + BasicBlockId succ_bb = successor_block_info->block; + if (succ_bb == bb->id) { found = true; break; } diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index fb306de0c1..cf758fc5da 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -130,11 +130,14 @@ int MIRGraph::ParseInsn(const uint16_t* code_ptr, DecodedInstruction* decoded_in /* Split an existing block from the specified code offset into two */ -BasicBlock* MIRGraph::SplitBlock(unsigned int code_offset, +BasicBlock* MIRGraph::SplitBlock(DexOffset code_offset, BasicBlock* orig_block, BasicBlock** immed_pred_block_p) { + DCHECK_GT(code_offset, orig_block->start_offset); MIR* insn = orig_block->first_mir_insn; + MIR* prev = NULL; while (insn) { if (insn->offset == code_offset) break; + prev = insn; insn = insn->next; } if (insn == NULL) { @@ -156,39 +159,42 @@ BasicBlock* MIRGraph::SplitBlock(unsigned int code_offset, /* Handle the taken path */ bottom_block->taken = orig_block->taken; - if (bottom_block->taken) { - orig_block->taken = NULL; - bottom_block->taken->predecessors->Delete(orig_block); - bottom_block->taken->predecessors->Insert(bottom_block); + if (bottom_block->taken != NullBasicBlockId) { + orig_block->taken = NullBasicBlockId; + BasicBlock* bb_taken = GetBasicBlock(bottom_block->taken); + bb_taken->predecessors->Delete(orig_block->id); + bb_taken->predecessors->Insert(bottom_block->id); } /* Handle the fallthrough path */ bottom_block->fall_through = orig_block->fall_through; - orig_block->fall_through = bottom_block; - bottom_block->predecessors->Insert(orig_block); - if (bottom_block->fall_through) { - bottom_block->fall_through->predecessors->Delete(orig_block); - bottom_block->fall_through->predecessors->Insert(bottom_block); + orig_block->fall_through = bottom_block->id; + bottom_block->predecessors->Insert(orig_block->id); + if (bottom_block->fall_through != NullBasicBlockId) { + BasicBlock* bb_fall_through = GetBasicBlock(bottom_block->fall_through); + bb_fall_through->predecessors->Delete(orig_block->id); + bb_fall_through->predecessors->Insert(bottom_block->id); } /* Handle the successor list */ - if (orig_block->successor_block_list.block_list_type != kNotUsed) { - bottom_block->successor_block_list = orig_block->successor_block_list; - orig_block->successor_block_list.block_list_type = kNotUsed; - GrowableArray::Iterator iterator(bottom_block->successor_block_list.blocks); + if (orig_block->successor_block_list_type != kNotUsed) { + bottom_block->successor_block_list_type = orig_block->successor_block_list_type; + bottom_block->successor_blocks = orig_block->successor_blocks; + orig_block->successor_block_list_type = kNotUsed; + orig_block->successor_blocks = NULL; + GrowableArray::Iterator iterator(bottom_block->successor_blocks); while (true) { SuccessorBlockInfo *successor_block_info = iterator.Next(); if (successor_block_info == NULL) break; - BasicBlock *bb = successor_block_info->block; - bb->predecessors->Delete(orig_block); - bb->predecessors->Insert(bottom_block); + BasicBlock *bb = GetBasicBlock(successor_block_info->block); + bb->predecessors->Delete(orig_block->id); + bb->predecessors->Insert(bottom_block->id); } } - orig_block->last_mir_insn = insn->prev; + orig_block->last_mir_insn = prev; + prev->next = NULL; - insn->prev->next = NULL; - insn->prev = NULL; /* * Update the immediate predecessor block pointer so that outgoing edges * can be applied to the proper block. @@ -225,7 +231,7 @@ BasicBlock* MIRGraph::SplitBlock(unsigned int code_offset, * (by the caller) * Utilizes a map for fast lookup of the typical cases. */ -BasicBlock* MIRGraph::FindBlock(unsigned int code_offset, bool split, bool create, +BasicBlock* MIRGraph::FindBlock(DexOffset code_offset, bool split, bool create, BasicBlock** immed_pred_block_p) { if (code_offset >= cu_->code_item->insns_size_in_code_units_) { return NULL; @@ -261,7 +267,7 @@ BasicBlock* MIRGraph::FindBlock(unsigned int code_offset, bool split, bool creat /* Identify code range in try blocks and set up the empty catch blocks */ void MIRGraph::ProcessTryCatchBlocks() { int tries_size = current_code_item_->tries_size_; - int offset; + DexOffset offset; if (tries_size == 0) { return; @@ -270,8 +276,8 @@ void MIRGraph::ProcessTryCatchBlocks() { for (int i = 0; i < tries_size; i++) { const DexFile::TryItem* pTry = DexFile::GetTryItems(*current_code_item_, i); - int start_offset = pTry->start_addr_; - int end_offset = start_offset + pTry->insn_count_; + DexOffset start_offset = pTry->start_addr_; + DexOffset end_offset = start_offset + pTry->insn_count_; for (offset = start_offset; offset < end_offset; offset++) { try_block_addr_->SetBit(offset); } @@ -292,10 +298,10 @@ void MIRGraph::ProcessTryCatchBlocks() { } /* Process instructions with the kBranch flag */ -BasicBlock* MIRGraph::ProcessCanBranch(BasicBlock* cur_block, MIR* insn, int cur_offset, int width, - int flags, const uint16_t* code_ptr, +BasicBlock* MIRGraph::ProcessCanBranch(BasicBlock* cur_block, MIR* insn, DexOffset cur_offset, + int width, int flags, const uint16_t* code_ptr, const uint16_t* code_end) { - int target = cur_offset; + DexOffset target = cur_offset; switch (insn->dalvikInsn.opcode) { case Instruction::GOTO: case Instruction::GOTO_16: @@ -326,8 +332,8 @@ BasicBlock* MIRGraph::ProcessCanBranch(BasicBlock* cur_block, MIR* insn, int cur CountBranch(target); BasicBlock *taken_block = FindBlock(target, /* split */ true, /* create */ true, /* immed_pred_block_p */ &cur_block); - cur_block->taken = taken_block; - taken_block->predecessors->Insert(cur_block); + cur_block->taken = taken_block->id; + taken_block->predecessors->Insert(cur_block->id); /* Always terminate the current block for conditional branches */ if (flags & Instruction::kContinue) { @@ -349,8 +355,8 @@ BasicBlock* MIRGraph::ProcessCanBranch(BasicBlock* cur_block, MIR* insn, int cur true, /* immed_pred_block_p */ &cur_block); - cur_block->fall_through = fallthrough_block; - fallthrough_block->predecessors->Insert(cur_block); + cur_block->fall_through = fallthrough_block->id; + fallthrough_block->predecessors->Insert(cur_block->id); } else if (code_ptr < code_end) { FindBlock(cur_offset + width, /* split */ false, /* create */ true, /* immed_pred_block_p */ NULL); @@ -359,7 +365,7 @@ BasicBlock* MIRGraph::ProcessCanBranch(BasicBlock* cur_block, MIR* insn, int cur } /* Process instructions with the kSwitch flag */ -void MIRGraph::ProcessCanSwitch(BasicBlock* cur_block, MIR* insn, int cur_offset, int width, +void MIRGraph::ProcessCanSwitch(BasicBlock* cur_block, MIR* insn, DexOffset cur_offset, int width, int flags) { const uint16_t* switch_data = reinterpret_cast(GetCurrentInsns() + cur_offset + insn->dalvikInsn.vB); @@ -403,14 +409,13 @@ void MIRGraph::ProcessCanSwitch(BasicBlock* cur_block, MIR* insn, int cur_offset first_key = 0; // To make the compiler happy } - if (cur_block->successor_block_list.block_list_type != kNotUsed) { + if (cur_block->successor_block_list_type != kNotUsed) { LOG(FATAL) << "Successor block list already in use: " - << static_cast(cur_block->successor_block_list.block_list_type); + << static_cast(cur_block->successor_block_list_type); } - cur_block->successor_block_list.block_list_type = - (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ? - kPackedSwitch : kSparseSwitch; - cur_block->successor_block_list.blocks = + cur_block->successor_block_list_type = + (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ? kPackedSwitch : kSparseSwitch; + cur_block->successor_blocks = new (arena_) GrowableArray(arena_, size, kGrowableArraySuccessorBlocks); for (i = 0; i < size; i++) { @@ -419,24 +424,24 @@ void MIRGraph::ProcessCanSwitch(BasicBlock* cur_block, MIR* insn, int cur_offset SuccessorBlockInfo *successor_block_info = static_cast(arena_->Alloc(sizeof(SuccessorBlockInfo), ArenaAllocator::kAllocSuccessor)); - successor_block_info->block = case_block; + successor_block_info->block = case_block->id; successor_block_info->key = (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ? first_key + i : keyTable[i]; - cur_block->successor_block_list.blocks->Insert(successor_block_info); - case_block->predecessors->Insert(cur_block); + cur_block->successor_blocks->Insert(successor_block_info); + case_block->predecessors->Insert(cur_block->id); } /* Fall-through case */ BasicBlock* fallthrough_block = FindBlock(cur_offset + width, /* split */ false, /* create */ true, /* immed_pred_block_p */ NULL); - cur_block->fall_through = fallthrough_block; - fallthrough_block->predecessors->Insert(cur_block); + cur_block->fall_through = fallthrough_block->id; + fallthrough_block->predecessors->Insert(cur_block->id); } /* Process instructions with the kThrow flag */ -BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, int cur_offset, int width, - int flags, ArenaBitVector* try_block_addr, +BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, DexOffset cur_offset, + int width, int flags, ArenaBitVector* try_block_addr, const uint16_t* code_ptr, const uint16_t* code_end) { bool in_try_block = try_block_addr->IsBitSet(cur_offset); @@ -444,14 +449,14 @@ BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, int cur_ if (in_try_block) { CatchHandlerIterator iterator(*current_code_item_, cur_offset); - if (cur_block->successor_block_list.block_list_type != kNotUsed) { + if (cur_block->successor_block_list_type != kNotUsed) { LOG(INFO) << PrettyMethod(cu_->method_idx, *cu_->dex_file); LOG(FATAL) << "Successor block list already in use: " - << static_cast(cur_block->successor_block_list.block_list_type); + << static_cast(cur_block->successor_block_list_type); } - cur_block->successor_block_list.block_list_type = kCatch; - cur_block->successor_block_list.blocks = + cur_block->successor_block_list_type = kCatch; + cur_block->successor_blocks = new (arena_) GrowableArray(arena_, 2, kGrowableArraySuccessorBlocks); for (; iterator.HasNext(); iterator.Next()) { @@ -463,17 +468,17 @@ BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, int cur_ } SuccessorBlockInfo *successor_block_info = reinterpret_cast (arena_->Alloc(sizeof(SuccessorBlockInfo), ArenaAllocator::kAllocSuccessor)); - successor_block_info->block = catch_block; + successor_block_info->block = catch_block->id; successor_block_info->key = iterator.GetHandlerTypeIndex(); - cur_block->successor_block_list.blocks->Insert(successor_block_info); - catch_block->predecessors->Insert(cur_block); + cur_block->successor_blocks->Insert(successor_block_info); + catch_block->predecessors->Insert(cur_block->id); } } else { BasicBlock *eh_block = NewMemBB(kExceptionHandling, num_blocks_++); - cur_block->taken = eh_block; + cur_block->taken = eh_block->id; block_list_.Insert(eh_block); eh_block->start_offset = cur_offset; - eh_block->predecessors->Insert(cur_block); + eh_block->predecessors->Insert(cur_block->id); } if (insn->dalvikInsn.opcode == Instruction::THROW) { @@ -509,8 +514,8 @@ BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, int cur_ BasicBlock *new_block = NewMemBB(kDalvikByteCode, num_blocks_++); block_list_.Insert(new_block); new_block->start_offset = insn->offset; - cur_block->fall_through = new_block; - new_block->predecessors->Insert(cur_block); + cur_block->fall_through = new_block->id; + new_block->predecessors->Insert(cur_block->id); MIR* new_insn = static_cast(arena_->Alloc(sizeof(MIR), ArenaAllocator::kAllocMIR)); *new_insn = *insn; insn->dalvikInsn.opcode = @@ -551,9 +556,14 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ DCHECK(entry_block_ == NULL); DCHECK(exit_block_ == NULL); DCHECK_EQ(num_blocks_, 0); + // Use id 0 to represent a null block. + BasicBlock* null_block = NewMemBB(kNullBlock, num_blocks_++); + DCHECK_EQ(null_block->id, NullBasicBlockId); + null_block->hidden = true; + block_list_.Insert(null_block); entry_block_ = NewMemBB(kEntryBlock, num_blocks_++); - exit_block_ = NewMemBB(kExitBlock, num_blocks_++); block_list_.Insert(entry_block_); + exit_block_ = NewMemBB(kExitBlock, num_blocks_++); block_list_.Insert(exit_block_); // TODO: deprecate all "cu->" fields; move what's left to wherever CompilationUnit is allocated. cu_->dex_file = &dex_file; @@ -578,12 +588,12 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ /* Current block to record parsed instructions */ BasicBlock *cur_block = NewMemBB(kDalvikByteCode, num_blocks_++); - DCHECK_EQ(current_offset_, 0); + DCHECK_EQ(current_offset_, 0U); cur_block->start_offset = current_offset_; block_list_.Insert(cur_block); - // FIXME: this needs to insert at the insert point rather than entry block. - entry_block_->fall_through = cur_block; - cur_block->predecessors->Insert(entry_block_); + // TODO: for inlining support, insert at the insert point rather than entry block. + entry_block_->fall_through = cur_block->id; + cur_block->predecessors->Insert(entry_block_->id); /* Identify code range in try blocks and set up the empty catch blocks */ ProcessTryCatchBlocks(); @@ -648,8 +658,8 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ // It is a simple nop - treat normally. AppendMIR(cur_block, insn); } else { - DCHECK(cur_block->fall_through == NULL); - DCHECK(cur_block->taken == NULL); + DCHECK(cur_block->fall_through == NullBasicBlockId); + DCHECK(cur_block->taken == NullBasicBlockId); // Unreachable instruction, mark for no continuation. flags &= ~Instruction::kContinue; } @@ -667,8 +677,8 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ width, flags, code_ptr, code_end); } else if (flags & Instruction::kReturn) { cur_block->terminated_by_return = true; - cur_block->fall_through = exit_block_; - exit_block_->predecessors->Insert(cur_block); + cur_block->fall_through = exit_block_->id; + exit_block_->predecessors->Insert(cur_block->id); /* * Terminate the current block if there are instructions * afterwards. @@ -697,13 +707,13 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ * instruction is not an unconditional branch, connect them through * the fall-through link. */ - DCHECK(cur_block->fall_through == NULL || - cur_block->fall_through == next_block || - cur_block->fall_through == exit_block_); + DCHECK(cur_block->fall_through == NullBasicBlockId || + GetBasicBlock(cur_block->fall_through) == next_block || + GetBasicBlock(cur_block->fall_through) == exit_block_); - if ((cur_block->fall_through == NULL) && (flags & Instruction::kContinue)) { - cur_block->fall_through = next_block; - next_block->predecessors->Insert(cur_block); + if ((cur_block->fall_through == NullBasicBlockId) && (flags & Instruction::kContinue)) { + cur_block->fall_through = next_block->id; + next_block->predecessors->Insert(cur_block->id); } cur_block = next_block; } @@ -735,7 +745,7 @@ void MIRGraph::DumpCFG(const char* dir_prefix, bool all_blocks) { std::string fname(PrettyMethod(cu_->method_idx, *cu_->dex_file)); ReplaceSpecialChars(fname); fname = StringPrintf("%s%s%x.dot", dir_prefix, fname.c_str(), - GetEntryBlock()->fall_through->start_offset); + GetBasicBlock(GetEntryBlock()->fall_through)->start_offset); file = fopen(fname.c_str(), "w"); if (file == NULL) { return; @@ -782,31 +792,30 @@ void MIRGraph::DumpCFG(const char* dir_prefix, bool all_blocks) { char block_name1[BLOCK_NAME_LEN], block_name2[BLOCK_NAME_LEN]; - if (bb->taken) { + if (bb->taken != NullBasicBlockId) { GetBlockName(bb, block_name1); - GetBlockName(bb->taken, block_name2); + GetBlockName(GetBasicBlock(bb->taken), block_name2); fprintf(file, " %s:s -> %s:n [style=dotted]\n", block_name1, block_name2); } - if (bb->fall_through) { + if (bb->fall_through != NullBasicBlockId) { GetBlockName(bb, block_name1); - GetBlockName(bb->fall_through, block_name2); + GetBlockName(GetBasicBlock(bb->fall_through), block_name2); fprintf(file, " %s:s -> %s:n\n", block_name1, block_name2); } - if (bb->successor_block_list.block_list_type != kNotUsed) { + if (bb->successor_block_list_type != kNotUsed) { fprintf(file, " succ%04x_%d [shape=%s,label = \"{ \\\n", bb->start_offset, bb->id, - (bb->successor_block_list.block_list_type == kCatch) ? - "Mrecord" : "record"); - GrowableArray::Iterator iterator(bb->successor_block_list.blocks); + (bb->successor_block_list_type == kCatch) ? "Mrecord" : "record"); + GrowableArray::Iterator iterator(bb->successor_blocks); SuccessorBlockInfo *successor_block_info = iterator.Next(); int succ_id = 0; while (true) { if (successor_block_info == NULL) break; - BasicBlock *dest_block = successor_block_info->block; + BasicBlock *dest_block = GetBasicBlock(successor_block_info->block); SuccessorBlockInfo *next_successor_block_info = iterator.Next(); fprintf(file, " { %04x: %04x\\l}%s\\\n", @@ -823,16 +832,16 @@ void MIRGraph::DumpCFG(const char* dir_prefix, bool all_blocks) { fprintf(file, " %s:s -> succ%04x_%d:n [style=dashed]\n", block_name1, bb->start_offset, bb->id); - if (bb->successor_block_list.block_list_type == kPackedSwitch || - bb->successor_block_list.block_list_type == kSparseSwitch) { - GrowableArray::Iterator iter(bb->successor_block_list.blocks); + if (bb->successor_block_list_type == kPackedSwitch || + bb->successor_block_list_type == kSparseSwitch) { + GrowableArray::Iterator iter(bb->successor_blocks); succ_id = 0; while (true) { SuccessorBlockInfo *successor_block_info = iter.Next(); if (successor_block_info == NULL) break; - BasicBlock *dest_block = successor_block_info->block; + BasicBlock* dest_block = GetBasicBlock(successor_block_info->block); GetBlockName(dest_block, block_name2); fprintf(file, " succ%04x_%d:f%d:e -> %s:n\n", bb->start_offset, @@ -848,7 +857,7 @@ void MIRGraph::DumpCFG(const char* dir_prefix, bool all_blocks) { fprintf(file, " cfg%s [label=\"%s\", shape=none];\n", block_name1, block_name1); if (bb->i_dom) { - GetBlockName(bb->i_dom, block_name2); + GetBlockName(GetBasicBlock(bb->i_dom), block_name2); fprintf(file, " cfg%s:s -> cfg%s:n\n\n", block_name2, block_name1); } } @@ -862,10 +871,9 @@ void MIRGraph::AppendMIR(BasicBlock* bb, MIR* mir) { if (bb->first_mir_insn == NULL) { DCHECK(bb->last_mir_insn == NULL); bb->last_mir_insn = bb->first_mir_insn = mir; - mir->prev = mir->next = NULL; + mir->next = NULL; } else { bb->last_mir_insn->next = mir; - mir->prev = bb->last_mir_insn; mir->next = NULL; bb->last_mir_insn = mir; } @@ -876,25 +884,19 @@ void MIRGraph::PrependMIR(BasicBlock* bb, MIR* mir) { if (bb->first_mir_insn == NULL) { DCHECK(bb->last_mir_insn == NULL); bb->last_mir_insn = bb->first_mir_insn = mir; - mir->prev = mir->next = NULL; + mir->next = NULL; } else { - bb->first_mir_insn->prev = mir; mir->next = bb->first_mir_insn; - mir->prev = NULL; bb->first_mir_insn = mir; } } /* Insert a MIR instruction after the specified MIR */ void MIRGraph::InsertMIRAfter(BasicBlock* bb, MIR* current_mir, MIR* new_mir) { - new_mir->prev = current_mir; new_mir->next = current_mir->next; current_mir->next = new_mir; - if (new_mir->next) { - /* Is not the last MIR in the block */ - new_mir->next->prev = new_mir; - } else { + if (bb->last_mir_insn == current_mir) { /* Is the last MIR in the block */ bb->last_mir_insn = new_mir; } @@ -924,8 +926,9 @@ char* MIRGraph::GetDalvikDisassembly(const MIR* mir) { opcode = insn.opcode; } else if (opcode == kMirOpNop) { str.append("["); - insn.opcode = mir->meta.original_opcode; - opcode = mir->meta.original_opcode; + // Recover original opcode. + insn.opcode = Instruction::At(current_code_item_->insns_ + mir->offset)->Opcode(); + opcode = insn.opcode; nop = true; } @@ -938,7 +941,7 @@ char* MIRGraph::GetDalvikDisassembly(const MIR* mir) { } if (opcode == kMirOpPhi) { - int* incoming = reinterpret_cast(insn.vB); + BasicBlockId* incoming = mir->meta.phi_incoming; str.append(StringPrintf(" %s = (%s", GetSSANameWithConst(ssa_rep->defs[0], true).c_str(), GetSSANameWithConst(ssa_rep->uses[0], true).c_str())); @@ -1088,7 +1091,7 @@ void MIRGraph::GetBlockName(BasicBlock* bb, char* name) { } const char* MIRGraph::GetShortyFromTargetIdx(int target_idx) { - // FIXME: use current code unit for inline support. + // TODO: for inlining support, use current code unit. const DexFile::MethodId& method_id = cu_->dex_file->GetMethodId(target_idx); return cu_->dex_file->GetShorty(method_id.proto_idx_); } @@ -1118,13 +1121,13 @@ void MIRGraph::DumpMIRGraph() { bb->start_offset, bb->last_mir_insn ? bb->last_mir_insn->offset : bb->start_offset, bb->last_mir_insn ? "" : " empty"); - if (bb->taken) { - LOG(INFO) << " Taken branch: block " << bb->taken->id - << "(0x" << std::hex << bb->taken->start_offset << ")"; + if (bb->taken != NullBasicBlockId) { + LOG(INFO) << " Taken branch: block " << bb->taken + << "(0x" << std::hex << GetBasicBlock(bb->taken)->start_offset << ")"; } - if (bb->fall_through) { - LOG(INFO) << " Fallthrough : block " << bb->fall_through->id - << " (0x" << std::hex << bb->fall_through->start_offset << ")"; + if (bb->fall_through != NullBasicBlockId) { + LOG(INFO) << " Fallthrough : block " << bb->fall_through + << " (0x" << std::hex << GetBasicBlock(bb->fall_through)->start_offset << ")"; } } } @@ -1144,7 +1147,6 @@ CallInfo* MIRGraph::NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, info->result.location = kLocInvalid; } else { info->result = GetRawDest(move_result_mir); - move_result_mir->meta.original_opcode = move_result_mir->dalvikInsn.opcode; move_result_mir->dalvikInsn.opcode = static_cast(kMirOpNop); } info->num_arg_words = mir->ssa_rep->num_uses; @@ -1168,10 +1170,10 @@ BasicBlock* MIRGraph::NewMemBB(BBType block_type, int block_id) { bb->block_type = block_type; bb->id = block_id; // TUNING: better estimate of the exit block predecessors? - bb->predecessors = new (arena_) GrowableArray(arena_, + bb->predecessors = new (arena_) GrowableArray(arena_, (block_type == kExitBlock) ? 2048 : 2, kGrowableArrayPredecessors); - bb->successor_block_list.block_list_type = kNotUsed; + bb->successor_block_list_type = kNotUsed; block_id_map_.Put(block_id, block_id); return bb; } diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 5d014894c1..8dda7c4c7e 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -183,6 +183,9 @@ enum OatMethodAttributes { #define BLOCK_NAME_LEN 80 +typedef uint16_t BasicBlockId; +static const BasicBlockId NullBasicBlockId = 0; + /* * In general, vreg/sreg describe Dalvik registers that originated with dx. However, * it is useful to have compiler-generated temporary registers and have them treated @@ -190,15 +193,15 @@ enum OatMethodAttributes { * name of compiler-introduced temporaries. */ struct CompilerTemp { - int s_reg; + int32_t s_reg; }; // When debug option enabled, records effectiveness of null and range check elimination. struct Checkstats { - int null_checks; - int null_checks_eliminated; - int range_checks; - int range_checks_eliminated; + int32_t null_checks; + int32_t null_checks_eliminated; + int32_t range_checks; + int32_t range_checks_eliminated; }; // Dataflow attributes of a basic block. @@ -207,7 +210,7 @@ struct BasicBlockDataFlow { ArenaBitVector* def_v; ArenaBitVector* live_in_v; ArenaBitVector* phi_v; - int* vreg_to_ssa_map; + int32_t* vreg_to_ssa_map; ArenaBitVector* ending_null_check_v; }; @@ -220,11 +223,11 @@ struct BasicBlockDataFlow { * we may want to revisit in the future. */ struct SSARepresentation { - int num_uses; - int* uses; + int16_t num_uses; + int16_t num_defs; + int32_t* uses; bool* fp_use; - int num_defs; - int* defs; + int32_t* defs; bool* fp_def; }; @@ -233,51 +236,53 @@ struct SSARepresentation { * wrapper around a Dalvik byte code. */ struct MIR { + /* + * TODO: remove embedded DecodedInstruction to save space, keeping only opcode. Recover + * additional fields on as-needed basis. Question: how to support MIR Pseudo-ops; probably + * need to carry aux data pointer. + */ DecodedInstruction dalvikInsn; - uint32_t width; // NOTE: only need 16 bits for width. - unsigned int offset; - int m_unit_index; // From which method was this MIR included - MIR* prev; + uint16_t width; // Note: width can include switch table or fill array data. + NarrowDexOffset offset; // Offset of the instruction in code units. + uint16_t optimization_flags; + int16_t m_unit_index; // From which method was this MIR included MIR* next; SSARepresentation* ssa_rep; - int optimization_flags; union { + // Incoming edges for phi node. + BasicBlockId* phi_incoming; // Establish link between two halves of throwing instructions. MIR* throw_insn; - // Saved opcode for NOP'd MIRs - Instruction::Code original_opcode; } meta; }; struct SuccessorBlockInfo; struct BasicBlock { - int id; - int dfs_id; - bool visited; - bool hidden; - bool catch_entry; - bool explicit_throw; - bool conditional_branch; - bool terminated_by_return; // Block ends with a Dalvik return opcode. - bool dominates_return; // Is a member of return extended basic block. - uint16_t start_offset; + BasicBlockId id; + BasicBlockId dfs_id; + NarrowDexOffset start_offset; // Offset in code units. + BasicBlockId fall_through; + BasicBlockId taken; + BasicBlockId i_dom; // Immediate dominator. uint16_t nesting_depth; - BBType block_type; + BBType block_type:4; + BlockListType successor_block_list_type:4; + bool visited:1; + bool hidden:1; + bool catch_entry:1; + bool explicit_throw:1; + bool conditional_branch:1; + bool terminated_by_return:1; // Block ends with a Dalvik return opcode. + bool dominates_return:1; // Is a member of return extended basic block. MIR* first_mir_insn; MIR* last_mir_insn; - BasicBlock* fall_through; - BasicBlock* taken; - BasicBlock* i_dom; // Immediate dominator. BasicBlockDataFlow* data_flow_info; - GrowableArray* predecessors; ArenaBitVector* dominators; ArenaBitVector* i_dominated; // Set nodes being immediately dominated. ArenaBitVector* dom_frontier; // Dominance frontier. - struct { // For one-to-many successors like. - BlockListType block_list_type; // switch and exception handling. - GrowableArray* blocks; - } successor_block_list; + GrowableArray* predecessors; + GrowableArray* successor_blocks; }; /* @@ -285,9 +290,8 @@ struct BasicBlock { * "SuccessorBlockInfo". For catch blocks, key is type index for the exception. For swtich * blocks, key is the case value. */ -// TODO: make class with placement new. struct SuccessorBlockInfo { - BasicBlock* block; + BasicBlockId block; int key; }; @@ -296,6 +300,15 @@ struct SuccessorBlockInfo { * the type of an SSA name (and, can also be used by code generators to record where the * value is located (i.e. - physical register, frame, spill, etc.). For each SSA name (SReg) * there is a RegLocation. + * A note on SSA names: + * o SSA names for Dalvik vRegs v0..vN will be assigned 0..N. These represent the "vN_0" + * names. Negative SSA names represent special values not present in the Dalvik byte code. + * For example, SSA name -1 represents an invalid SSA name, and SSA name -2 represents the + * the Method pointer. SSA names < -2 are reserved for future use. + * o The vN_0 names for non-argument Dalvik should in practice never be used (as they would + * represent the read of an undefined local variable). The first definition of the + * underlying Dalvik vReg will result in a vN_1 name. + * * FIXME: The orig_sreg field was added as a workaround for llvm bitcode generation. With * the latest restructuring, we should be able to remove it and rely on s_reg_low throughout. */ @@ -311,9 +324,9 @@ struct RegLocation { unsigned home:1; // Does this represent the home location? uint8_t low_reg; // First physical register. uint8_t high_reg; // 2nd physical register (if wide). - int32_t s_reg_low; // SSA name for low Dalvik word. - int32_t orig_sreg; // TODO: remove after Bitcode gen complete - // and consolodate usage w/ s_reg_low. + int16_t s_reg_low; // SSA name for low Dalvik word. + int16_t orig_sreg; // TODO: remove after Bitcode gen complete + // and consolidate usage w/ s_reg_low. }; /* @@ -334,7 +347,7 @@ struct CallInfo { RegLocation target; // Target of following move_result. bool skip_this; bool is_range; - int offset; // Dalvik offset. + DexOffset offset; // Offset in code units. }; @@ -361,7 +374,7 @@ class MIRGraph { uint32_t method_idx, jobject class_loader, const DexFile& dex_file); /* Find existing block */ - BasicBlock* FindBlock(unsigned int code_offset) { + BasicBlock* FindBlock(DexOffset code_offset) { return FindBlock(code_offset, false, false, NULL); } @@ -394,7 +407,7 @@ class MIRGraph { } BasicBlock* GetBasicBlock(int block_id) const { - return block_list_.Get(block_id); + return (block_id == NullBasicBlockId) ? NULL : block_list_.Get(block_id); } size_t GetBasicBlockListCount() const { @@ -405,15 +418,15 @@ class MIRGraph { return &block_list_; } - GrowableArray* GetDfsOrder() { + GrowableArray* GetDfsOrder() { return dfs_order_; } - GrowableArray* GetDfsPostOrder() { + GrowableArray* GetDfsPostOrder() { return dfs_post_order_; } - GrowableArray* GetDomPostOrder() { + GrowableArray* GetDomPostOrder() { return dom_post_order_traversal_; } @@ -477,6 +490,12 @@ class MIRGraph { } void SetNumSSARegs(int new_num) { + /* + * TODO: It's theoretically possible to exceed 32767, though any cases which did + * would be filtered out with current settings. When orig_sreg field is removed + * from RegLocation, expand s_reg_low to handle all possible cases and remove DCHECK(). + */ + DCHECK_EQ(new_num, static_cast(new_num)); num_ssa_regs_ = new_num; } @@ -561,15 +580,16 @@ class MIRGraph { return special_case_; } - bool IsBackedge(BasicBlock* branch_bb, BasicBlock* target_bb) { - return ((target_bb != NULL) && (target_bb->start_offset <= branch_bb->start_offset)); + bool IsBackedge(BasicBlock* branch_bb, BasicBlockId target_bb_id) { + return ((target_bb_id != NullBasicBlockId) && + (GetBasicBlock(target_bb_id)->start_offset <= branch_bb->start_offset)); } bool IsBackwardsBranch(BasicBlock* branch_bb) { return IsBackedge(branch_bb, branch_bb->taken) || IsBackedge(branch_bb, branch_bb->fall_through); } - void CountBranch(int target_offset) { + void CountBranch(DexOffset target_offset) { if (target_offset <= current_offset_) { backward_branches_++; } else { @@ -640,6 +660,9 @@ class MIRGraph { void DumpMIRGraph(); CallInfo* NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, bool is_range); BasicBlock* NewMemBB(BBType block_type, int block_id); + MIR* AdvanceMIR(BasicBlock** p_bb, MIR* mir); + BasicBlock* NextDominatedBlock(BasicBlock* bb); + bool LayoutBlocks(BasicBlock* bb); /* * IsDebugBuild sanity check: keep track of the Dex PCs for catch entries so that later on @@ -668,15 +691,16 @@ class MIRGraph { bool InvokeUsesMethodStar(MIR* mir); int ParseInsn(const uint16_t* code_ptr, DecodedInstruction* decoded_instruction); bool ContentIsInsn(const uint16_t* code_ptr); - BasicBlock* SplitBlock(unsigned int code_offset, BasicBlock* orig_block, + BasicBlock* SplitBlock(DexOffset code_offset, BasicBlock* orig_block, BasicBlock** immed_pred_block_p); - BasicBlock* FindBlock(unsigned int code_offset, bool split, bool create, + BasicBlock* FindBlock(DexOffset code_offset, bool split, bool create, BasicBlock** immed_pred_block_p); void ProcessTryCatchBlocks(); - BasicBlock* ProcessCanBranch(BasicBlock* cur_block, MIR* insn, int cur_offset, int width, + BasicBlock* ProcessCanBranch(BasicBlock* cur_block, MIR* insn, DexOffset cur_offset, int width, int flags, const uint16_t* code_ptr, const uint16_t* code_end); - void ProcessCanSwitch(BasicBlock* cur_block, MIR* insn, int cur_offset, int width, int flags); - BasicBlock* ProcessCanThrow(BasicBlock* cur_block, MIR* insn, int cur_offset, int width, + void ProcessCanSwitch(BasicBlock* cur_block, MIR* insn, DexOffset cur_offset, int width, + int flags); + BasicBlock* ProcessCanThrow(BasicBlock* cur_block, MIR* insn, DexOffset cur_offset, int width, int flags, ArenaBitVector* try_block_addr, const uint16_t* code_ptr, const uint16_t* code_end); int AddNewSReg(int v_reg); @@ -732,9 +756,9 @@ class MIRGraph { GrowableArray use_counts_; // Weighted by nesting depth GrowableArray raw_use_counts_; // Not weighted unsigned int num_reachable_blocks_; - GrowableArray* dfs_order_; - GrowableArray* dfs_post_order_; - GrowableArray* dom_post_order_traversal_; + GrowableArray* dfs_order_; + GrowableArray* dfs_post_order_; + GrowableArray* dom_post_order_traversal_; int* i_dom_list_; ArenaBitVector** def_block_matrix_; // num_dalvik_register x num_blocks. ArenaBitVector* temp_block_v_; @@ -752,11 +776,11 @@ class MIRGraph { typedef std::pair MIRLocation; // Insert point, (m_unit_ index, offset) std::vector method_stack_; // Include stack int current_method_; - int current_offset_; // Dex offset in code units + DexOffset current_offset_; // Offset in code units int def_count_; // Used to estimate size of ssa name storage. int* opcode_count_; // Dex opcode coverage stats. int num_ssa_regs_; // Number of names following SSA transformation. - std::vector extended_basic_blocks_; // Heads of block "traces". + std::vector extended_basic_blocks_; // Heads of block "traces". int method_sreg_; unsigned int attributes_; Checkstats* checkstats_; diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index 05e428e178..3cd158ffc0 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -103,12 +103,12 @@ void MIRGraph::PropagateConstants() { } /* Advance to next strictly dominated MIR node in an extended basic block */ -static MIR* AdvanceMIR(BasicBlock** p_bb, MIR* mir) { +MIR* MIRGraph::AdvanceMIR(BasicBlock** p_bb, MIR* mir) { BasicBlock* bb = *p_bb; if (mir != NULL) { mir = mir->next; if (mir == NULL) { - bb = bb->fall_through; + bb = GetBasicBlock(bb->fall_through); if ((bb == NULL) || Predecessors(bb) != 1) { mir = NULL; } else { @@ -147,19 +147,21 @@ MIR* MIRGraph::FindMoveResult(BasicBlock* bb, MIR* mir) { return mir; } -static BasicBlock* NextDominatedBlock(BasicBlock* bb) { +BasicBlock* MIRGraph::NextDominatedBlock(BasicBlock* bb) { if (bb->block_type == kDead) { return NULL; } DCHECK((bb->block_type == kEntryBlock) || (bb->block_type == kDalvikByteCode) || (bb->block_type == kExitBlock)); - if (((bb->taken != NULL) && (bb->fall_through == NULL)) && - ((bb->taken->block_type == kDalvikByteCode) || (bb->taken->block_type == kExitBlock))) { + BasicBlock* bb_taken = GetBasicBlock(bb->taken); + BasicBlock* bb_fall_through = GetBasicBlock(bb->fall_through); + if (((bb_taken != NULL) && (bb_fall_through == NULL)) && + ((bb_taken->block_type == kDalvikByteCode) || (bb_taken->block_type == kExitBlock))) { // Follow simple unconditional branches. - bb = bb->taken; + bb = bb_taken; } else { // Follow simple fallthrough - bb = (bb->taken != NULL) ? NULL : bb->fall_through; + bb = (bb_taken != NULL) ? NULL : bb_fall_through; } if (bb == NULL || (Predecessors(bb) != 1)) { return NULL; @@ -311,11 +313,13 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) { case Instruction::IF_GTZ: case Instruction::IF_LEZ: // If we've got a backwards branch to return, no need to suspend check. - if ((IsBackedge(bb, bb->taken) && bb->taken->dominates_return) || - (IsBackedge(bb, bb->fall_through) && bb->fall_through->dominates_return)) { + if ((IsBackedge(bb, bb->taken) && GetBasicBlock(bb->taken)->dominates_return) || + (IsBackedge(bb, bb->fall_through) && + GetBasicBlock(bb->fall_through)->dominates_return)) { mir->optimization_flags |= MIR_IGNORE_SUSPEND_CHECK; if (cu_->verbose) { - LOG(INFO) << "Suppressed suspend check on branch to return at 0x" << std::hex << mir->offset; + LOG(INFO) << "Suppressed suspend check on branch to return at 0x" << std::hex + << mir->offset; } } break; @@ -328,15 +332,15 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) { if (!(cu_->compiler_backend == kPortable) && (cu_->instruction_set == kThumb2) && ((mir->dalvikInsn.opcode == Instruction::IF_EQZ) || (mir->dalvikInsn.opcode == Instruction::IF_NEZ))) { - BasicBlock* ft = bb->fall_through; + BasicBlock* ft = GetBasicBlock(bb->fall_through); DCHECK(ft != NULL); - BasicBlock* ft_ft = ft->fall_through; - BasicBlock* ft_tk = ft->taken; + BasicBlock* ft_ft = GetBasicBlock(ft->fall_through); + BasicBlock* ft_tk = GetBasicBlock(ft->taken); - BasicBlock* tk = bb->taken; + BasicBlock* tk = GetBasicBlock(bb->taken); DCHECK(tk != NULL); - BasicBlock* tk_ft = tk->fall_through; - BasicBlock* tk_tk = tk->taken; + BasicBlock* tk_ft = GetBasicBlock(tk->fall_through); + BasicBlock* tk_tk = GetBasicBlock(tk->taken); /* * In the select pattern, the taken edge goes to a block that unconditionally @@ -434,7 +438,7 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) { int dead_def = if_false->ssa_rep->defs[0]; int live_def = if_true->ssa_rep->defs[0]; mir->ssa_rep->defs[0] = live_def; - int* incoming = reinterpret_cast(phi->dalvikInsn.vB); + BasicBlockId* incoming = phi->meta.phi_incoming; for (int i = 0; i < phi->ssa_rep->num_uses; i++) { if (phi->ssa_rep->uses[i] == live_def) { incoming[i] = bb->id; @@ -449,7 +453,7 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) { } } phi->ssa_rep->num_uses--; - bb->taken = NULL; + bb->taken = NullBasicBlockId; tk->block_type = kDead; for (MIR* tmir = ft->first_mir_insn; tmir != NULL; tmir = tmir->next) { tmir->dalvikInsn.opcode = static_cast(kMirOpNop); @@ -500,7 +504,7 @@ void MIRGraph::CountChecks(struct BasicBlock* bb) { } /* Try to make common case the fallthrough path */ -static bool LayoutBlocks(struct BasicBlock* bb) { +bool MIRGraph::LayoutBlocks(BasicBlock* bb) { // TODO: For now, just looking for direct throws. Consider generalizing for profile feedback if (!bb->explicit_throw) { return false; @@ -511,13 +515,13 @@ static bool LayoutBlocks(struct BasicBlock* bb) { if ((walker->block_type == kEntryBlock) || (Predecessors(walker) != 1)) { break; } - BasicBlock* prev = walker->predecessors->Get(0); + BasicBlock* prev = GetBasicBlock(walker->predecessors->Get(0)); if (prev->conditional_branch) { - if (prev->fall_through == walker) { + if (GetBasicBlock(prev->fall_through) == walker) { // Already done - return break; } - DCHECK_EQ(walker, prev->taken); + DCHECK_EQ(walker, GetBasicBlock(prev->taken)); // Got one. Flip it and exit Instruction::Code opcode = prev->last_mir_insn->dalvikInsn.opcode; switch (opcode) { @@ -536,7 +540,7 @@ static bool LayoutBlocks(struct BasicBlock* bb) { default: LOG(FATAL) << "Unexpected opcode " << opcode; } prev->last_mir_insn->dalvikInsn.opcode = opcode; - BasicBlock* t_bb = prev->taken; + BasicBlockId t_bb = prev->taken; prev->taken = prev->fall_through; prev->fall_through = t_bb; break; @@ -556,8 +560,9 @@ bool MIRGraph::CombineBlocks(struct BasicBlock* bb) { || (bb->block_type == kExceptionHandling) || (bb->block_type == kExitBlock) || (bb->block_type == kDead) - || ((bb->taken == NULL) || (bb->taken->block_type != kExceptionHandling)) - || (bb->successor_block_list.block_list_type != kNotUsed) + || (bb->taken == NullBasicBlockId) + || (GetBasicBlock(bb->taken)->block_type != kExceptionHandling) + || (bb->successor_block_list_type != kNotUsed) || (static_cast(bb->last_mir_insn->dalvikInsn.opcode) != kMirOpCheck)) { break; } @@ -578,19 +583,18 @@ bool MIRGraph::CombineBlocks(struct BasicBlock* bb) { break; } // OK - got one. Combine - BasicBlock* bb_next = bb->fall_through; + BasicBlock* bb_next = GetBasicBlock(bb->fall_through); DCHECK(!bb_next->catch_entry); DCHECK_EQ(Predecessors(bb_next), 1U); - MIR* t_mir = bb->last_mir_insn->prev; // Overwrite the kOpCheck insn with the paired opcode DCHECK_EQ(bb_next->first_mir_insn, throw_insn); *bb->last_mir_insn = *throw_insn; - bb->last_mir_insn->prev = t_mir; // Use the successor info from the next block - bb->successor_block_list = bb_next->successor_block_list; + bb->successor_block_list_type = bb_next->successor_block_list_type; + bb->successor_blocks = bb_next->successor_blocks; // Use the ending block linkage from the next block bb->fall_through = bb_next->fall_through; - bb->taken->block_type = kDead; // Kill the unused exception block + GetBasicBlock(bb->taken)->block_type = kDead; // Kill the unused exception block bb->taken = bb_next->taken; // Include the rest of the instructions bb->last_mir_insn = bb_next->last_mir_insn; @@ -631,20 +635,20 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { temp_ssa_register_v_->SetBit(this_reg); } } else if (bb->predecessors->Size() == 1) { - BasicBlock* pred_bb = bb->predecessors->Get(0); + BasicBlock* pred_bb = GetBasicBlock(bb->predecessors->Get(0)); temp_ssa_register_v_->Copy(pred_bb->data_flow_info->ending_null_check_v); if (pred_bb->block_type == kDalvikByteCode) { // Check to see if predecessor had an explicit null-check. MIR* last_insn = pred_bb->last_mir_insn; Instruction::Code last_opcode = last_insn->dalvikInsn.opcode; if (last_opcode == Instruction::IF_EQZ) { - if (pred_bb->fall_through == bb) { + if (pred_bb->fall_through == bb->id) { // The fall-through of a block following a IF_EQZ, set the vA of the IF_EQZ to show that // it can't be null. temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]); } } else if (last_opcode == Instruction::IF_NEZ) { - if (pred_bb->taken == bb) { + if (pred_bb->taken == bb->id) { // The taken block following a IF_NEZ, set the vA of the IF_NEZ to show that it can't be // null. temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]); @@ -653,12 +657,12 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { } } else { // Starting state is intersection of all incoming arcs - GrowableArray::Iterator iter(bb->predecessors); - BasicBlock* pred_bb = iter.Next(); + GrowableArray::Iterator iter(bb->predecessors); + BasicBlock* pred_bb = GetBasicBlock(iter.Next()); DCHECK(pred_bb != NULL); temp_ssa_register_v_->Copy(pred_bb->data_flow_info->ending_null_check_v); while (true) { - pred_bb = iter.Next(); + pred_bb = GetBasicBlock(iter.Next()); if (!pred_bb) break; if ((pred_bb->data_flow_info == NULL) || (pred_bb->data_flow_info->ending_null_check_v == NULL)) { @@ -691,9 +695,9 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { } else { if (next_mir) { LOG(WARNING) << "Unexpected opcode following new: " << next_mir->dalvikInsn.opcode; - } else if (bb->fall_through) { + } else if (bb->fall_through != NullBasicBlockId) { // Look in next basic block - struct BasicBlock* next_bb = bb->fall_through; + struct BasicBlock* next_bb = GetBasicBlock(bb->fall_through); for (MIR* tmir = next_bb->first_mir_insn; tmir != NULL; tmir =tmir->next) { if (static_cast(tmir->dalvikInsn.opcode) >= static_cast(kMirOpFirst)) { @@ -834,7 +838,7 @@ bool MIRGraph::BuildExtendedBBList(struct BasicBlock* bb) { } // Must be head of extended basic block. BasicBlock* start_bb = bb; - extended_basic_blocks_.push_back(bb); + extended_basic_blocks_.push_back(bb->id); bool terminated_by_return = false; // Visit blocks strictly dominated by this head. while (bb != NULL) { @@ -864,7 +868,7 @@ void MIRGraph::BasicBlockOptimization() { } // Perform extended basic block optimizations. for (unsigned int i = 0; i < extended_basic_blocks_.size(); i++) { - BasicBlockOpt(extended_basic_blocks_[i]); + BasicBlockOpt(GetBasicBlock(extended_basic_blocks_[i])); } } if (cu_->enable_debug & (1 << kDebugDumpCFG)) { diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc index df10f7eda0..963cbeb1d1 100644 --- a/compiler/dex/portable/mir_to_gbc.cc +++ b/compiler/dex/portable/mir_to_gbc.cc @@ -132,7 +132,7 @@ void MirConverter::ConvertPackedSwitch(BasicBlock* bb, ::llvm::Value* value = GetLLVMValue(rl_src.orig_sreg); ::llvm::SwitchInst* sw = - irb_->CreateSwitch(value, GetLLVMBlock(bb->fall_through->id), + irb_->CreateSwitch(value, GetLLVMBlock(bb->fall_through), payload->case_count); for (uint16_t i = 0; i < payload->case_count; ++i) { @@ -143,8 +143,8 @@ void MirConverter::ConvertPackedSwitch(BasicBlock* bb, ::llvm::MDNode* switch_node = ::llvm::MDNode::get(*context_, irb_->getInt32(table_offset)); sw->setMetadata("SwitchTable", switch_node); - bb->taken = NULL; - bb->fall_through = NULL; + bb->taken = NullBasicBlockId; + bb->fall_through = NullBasicBlockId; } void MirConverter::ConvertSparseSwitch(BasicBlock* bb, @@ -159,7 +159,7 @@ void MirConverter::ConvertSparseSwitch(BasicBlock* bb, ::llvm::Value* value = GetLLVMValue(rl_src.orig_sreg); ::llvm::SwitchInst* sw = - irb_->CreateSwitch(value, GetLLVMBlock(bb->fall_through->id), + irb_->CreateSwitch(value, GetLLVMBlock(bb->fall_through), payload->case_count); for (size_t i = 0; i < payload->case_count; ++i) { @@ -170,8 +170,8 @@ void MirConverter::ConvertSparseSwitch(BasicBlock* bb, ::llvm::MDNode* switch_node = ::llvm::MDNode::get(*context_, irb_->getInt32(table_offset)); sw->setMetadata("SwitchTable", switch_node); - bb->taken = NULL; - bb->fall_through = NULL; + bb->taken = NullBasicBlockId; + bb->fall_through = NullBasicBlockId; } void MirConverter::ConvertSget(int32_t field_index, @@ -311,22 +311,22 @@ void MirConverter::EmitSuspendCheck() { void MirConverter::ConvertCompareAndBranch(BasicBlock* bb, MIR* mir, ConditionCode cc, RegLocation rl_src1, RegLocation rl_src2) { - if (bb->taken->start_offset <= mir->offset) { + if (mir_graph_->GetBasicBlock(bb->taken)->start_offset <= mir->offset) { EmitSuspendCheck(); } ::llvm::Value* src1 = GetLLVMValue(rl_src1.orig_sreg); ::llvm::Value* src2 = GetLLVMValue(rl_src2.orig_sreg); ::llvm::Value* cond_value = ConvertCompare(cc, src1, src2); cond_value->setName(StringPrintf("t%d", temp_name_++)); - irb_->CreateCondBr(cond_value, GetLLVMBlock(bb->taken->id), - GetLLVMBlock(bb->fall_through->id)); + irb_->CreateCondBr(cond_value, GetLLVMBlock(bb->taken), + GetLLVMBlock(bb->fall_through)); // Don't redo the fallthrough branch in the BB driver - bb->fall_through = NULL; + bb->fall_through = NullBasicBlockId; } void MirConverter::ConvertCompareZeroAndBranch(BasicBlock* bb, MIR* mir, ConditionCode cc, RegLocation rl_src1) { - if (bb->taken->start_offset <= mir->offset) { + if (mir_graph_->GetBasicBlock(bb->taken)->start_offset <= mir->offset) { EmitSuspendCheck(); } ::llvm::Value* src1 = GetLLVMValue(rl_src1.orig_sreg); @@ -337,10 +337,10 @@ void MirConverter::ConvertCompareZeroAndBranch(BasicBlock* bb, src2 = irb_->getInt32(0); } ::llvm::Value* cond_value = ConvertCompare(cc, src1, src2); - irb_->CreateCondBr(cond_value, GetLLVMBlock(bb->taken->id), - GetLLVMBlock(bb->fall_through->id)); + irb_->CreateCondBr(cond_value, GetLLVMBlock(bb->taken), + GetLLVMBlock(bb->fall_through)); // Don't redo the fallthrough branch in the BB driver - bb->fall_through = NULL; + bb->fall_through = NullBasicBlockId; } ::llvm::Value* MirConverter::GenDivModOp(bool is_div, bool is_long, @@ -941,10 +941,10 @@ bool MirConverter::ConvertMIRNode(MIR* mir, BasicBlock* bb, case Instruction::GOTO: case Instruction::GOTO_16: case Instruction::GOTO_32: { - if (bb->taken->start_offset <= bb->start_offset) { + if (mir_graph_->GetBasicBlock(bb->taken)->start_offset <= bb->start_offset) { EmitSuspendCheck(); } - irb_->CreateBr(GetLLVMBlock(bb->taken->id)); + irb_->CreateBr(GetLLVMBlock(bb->taken)); } break; @@ -1190,11 +1190,11 @@ bool MirConverter::ConvertMIRNode(MIR* mir, BasicBlock* bb, * If it might rethrow, force termination * of the following block. */ - if (bb->fall_through == NULL) { + if (bb->fall_through == NullBasicBlockId) { irb_->CreateUnreachable(); } else { - bb->fall_through->fall_through = NULL; - bb->fall_through->taken = NULL; + mir_graph_->GetBasicBlock(bb->fall_through)->fall_through = NullBasicBlockId; + mir_graph_->GetBasicBlock(bb->fall_through)->taken = NullBasicBlockId; } break; @@ -1552,7 +1552,7 @@ void MirConverter::HandlePhiNodes(BasicBlock* bb, ::llvm::BasicBlock* llvm_bb) { if (rl_dest.high_word) { continue; // No Phi node - handled via low word } - int* incoming = reinterpret_cast(mir->dalvikInsn.vB); + BasicBlockId* incoming = mir->meta.phi_incoming; ::llvm::Type* phi_type = LlvmTypeFromLocRec(rl_dest); ::llvm::PHINode* phi = irb_->CreatePHI(phi_type, mir->ssa_rep->num_uses); @@ -1597,8 +1597,8 @@ void MirConverter::ConvertExtendedMIR(BasicBlock* bb, MIR* mir, break; } case kMirOpNop: - if ((mir == bb->last_mir_insn) && (bb->taken == NULL) && - (bb->fall_through == NULL)) { + if ((mir == bb->last_mir_insn) && (bb->taken == NullBasicBlockId) && + (bb->fall_through == NullBasicBlockId)) { irb_->CreateUnreachable(); } break; @@ -1718,25 +1718,23 @@ bool MirConverter::BlockBitcodeConversion(BasicBlock* bb) { SSARepresentation* ssa_rep = work_half->ssa_rep; work_half->ssa_rep = mir->ssa_rep; mir->ssa_rep = ssa_rep; - work_half->meta.original_opcode = work_half->dalvikInsn.opcode; work_half->dalvikInsn.opcode = static_cast(kMirOpNop); - if (bb->successor_block_list.block_list_type == kCatch) { + if (bb->successor_block_list_type == kCatch) { ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction( art::llvm::IntrinsicHelper::CatchTargets); ::llvm::Value* switch_key = irb_->CreateCall(intr, irb_->getInt32(mir->offset)); - GrowableArray::Iterator iter(bb->successor_block_list.blocks); + GrowableArray::Iterator iter(bb->successor_blocks); // New basic block to use for work half ::llvm::BasicBlock* work_bb = ::llvm::BasicBlock::Create(*context_, "", func_); ::llvm::SwitchInst* sw = - irb_->CreateSwitch(switch_key, work_bb, - bb->successor_block_list.blocks->Size()); + irb_->CreateSwitch(switch_key, work_bb, bb->successor_blocks->Size()); while (true) { SuccessorBlockInfo *successor_block_info = iter.Next(); if (successor_block_info == NULL) break; ::llvm::BasicBlock *target = - GetLLVMBlock(successor_block_info->block->id); + GetLLVMBlock(successor_block_info->block); int type_index = successor_block_info->key; sw->addCase(irb_->getInt32(type_index), target); } @@ -1761,9 +1759,9 @@ bool MirConverter::BlockBitcodeConversion(BasicBlock* bb) { } if (bb->block_type == kEntryBlock) { - entry_target_bb_ = GetLLVMBlock(bb->fall_through->id); - } else if ((bb->fall_through != NULL) && !bb->terminated_by_return) { - irb_->CreateBr(GetLLVMBlock(bb->fall_through->id)); + entry_target_bb_ = GetLLVMBlock(bb->fall_through); + } else if ((bb->fall_through != NullBasicBlockId) && !bb->terminated_by_return) { + irb_->CreateBr(GetLLVMBlock(bb->fall_through)); } return false; diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc index 3c646c40b6..cc40e99c52 100644 --- a/compiler/dex/quick/arm/assemble_arm.cc +++ b/compiler/dex/quick/arm/assemble_arm.cc @@ -1031,8 +1031,7 @@ void ArmMir2Lir::EncodeLIR(LIR* lir) { } else if (LIKELY(!lir->flags.is_nop)) { const ArmEncodingMap *encoder = &EncodingMap[lir->opcode]; uint32_t bits = encoder->skeleton; - int i; - for (i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) { uint32_t operand; uint32_t value; operand = lir->operands[i]; @@ -1088,7 +1087,7 @@ void ArmMir2Lir::EncodeLIR(LIR* lir) { case kFmtDfp: { DCHECK(ARM_DOUBLEREG(operand)); DCHECK_EQ((operand & 0x1), 0U); - int reg_name = (operand & ARM_FP_REG_MASK) >> 1; + uint32_t reg_name = (operand & ARM_FP_REG_MASK) >> 1; /* Snag the 1-bit slice and position it */ value = ((reg_name & 0x10) >> 4) << encoder->field_loc[i].end; /* Extract and position the 4-bit slice */ @@ -1155,9 +1154,9 @@ void ArmMir2Lir::AssembleLIR() { LIR* lir; LIR* prev_lir; int assembler_retries = 0; - int starting_offset = EncodeRange(first_lir_insn_, last_lir_insn_, 0); + CodeOffset starting_offset = EncodeRange(first_lir_insn_, last_lir_insn_, 0); data_offset_ = (starting_offset + 0x3) & ~0x3; - int offset_adjustment; + int32_t offset_adjustment; AssignDataOffsets(); /* @@ -1200,10 +1199,10 @@ void ArmMir2Lir::AssembleLIR() { * we revert to a multiple-instruction materialization sequence. */ LIR *lir_target = lir->target; - uintptr_t pc = (lir->offset + 4) & ~3; - uintptr_t target = lir_target->offset + + CodeOffset pc = (lir->offset + 4) & ~3; + CodeOffset target = lir_target->offset + ((lir_target->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); - int delta = target - pc; + int32_t delta = target - pc; if (res != kSuccess) { /* * In this case, we're just estimating and will do it again for real. Ensure offset @@ -1281,10 +1280,10 @@ void ArmMir2Lir::AssembleLIR() { } case kFixupCBxZ: { LIR *target_lir = lir->target; - uintptr_t pc = lir->offset + 4; - uintptr_t target = target_lir->offset + + CodeOffset pc = lir->offset + 4; + CodeOffset target = target_lir->offset + ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); - int delta = target - pc; + int32_t delta = target - pc; if (delta > 126 || delta < 0) { /* * Convert to cmp rx,#0 / b[eq/ne] tgt pair @@ -1351,10 +1350,10 @@ void ArmMir2Lir::AssembleLIR() { } case kFixupCondBranch: { LIR *target_lir = lir->target; - int delta = 0; + int32_t delta = 0; DCHECK(target_lir); - uintptr_t pc = lir->offset + 4; - uintptr_t target = target_lir->offset + + CodeOffset pc = lir->offset + 4; + CodeOffset target = target_lir->offset + ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); delta = target - pc; if ((lir->opcode == kThumbBCond) && (delta > 254 || delta < -256)) { @@ -1370,10 +1369,10 @@ void ArmMir2Lir::AssembleLIR() { } case kFixupT2Branch: { LIR *target_lir = lir->target; - uintptr_t pc = lir->offset + 4; - uintptr_t target = target_lir->offset + + CodeOffset pc = lir->offset + 4; + CodeOffset target = target_lir->offset + ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); - int delta = target - pc; + int32_t delta = target - pc; lir->operands[0] = delta >> 1; if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && lir->operands[0] == 0) { // Useless branch @@ -1387,10 +1386,10 @@ void ArmMir2Lir::AssembleLIR() { } case kFixupT1Branch: { LIR *target_lir = lir->target; - uintptr_t pc = lir->offset + 4; - uintptr_t target = target_lir->offset + + CodeOffset pc = lir->offset + 4; + CodeOffset target = target_lir->offset + ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); - int delta = target - pc; + int32_t delta = target - pc; if (delta > 2046 || delta < -2048) { // Convert to Thumb2BCond w/ kArmCondAl offset_adjustment -= lir->flags.size; @@ -1416,14 +1415,14 @@ void ArmMir2Lir::AssembleLIR() { case kFixupBlx1: { DCHECK(NEXT_LIR(lir)->opcode == kThumbBlx2); /* cur_pc is Thumb */ - uintptr_t cur_pc = (lir->offset + 4) & ~3; - uintptr_t target = lir->operands[1]; + CodeOffset cur_pc = (lir->offset + 4) & ~3; + CodeOffset target = lir->operands[1]; /* Match bit[1] in target with base */ if (cur_pc & 0x2) { target |= 0x2; } - int delta = target - cur_pc; + int32_t delta = target - cur_pc; DCHECK((delta >= -(1<<22)) && (delta <= ((1<<22)-2))); lir->operands[0] = (delta >> 12) & 0x7ff; @@ -1433,10 +1432,10 @@ void ArmMir2Lir::AssembleLIR() { case kFixupBl1: { DCHECK(NEXT_LIR(lir)->opcode == kThumbBl2); /* Both cur_pc and target are Thumb */ - uintptr_t cur_pc = lir->offset + 4; - uintptr_t target = lir->operands[1]; + CodeOffset cur_pc = lir->offset + 4; + CodeOffset target = lir->operands[1]; - int delta = target - cur_pc; + int32_t delta = target - cur_pc; DCHECK((delta >= -(1<<22)) && (delta <= ((1<<22)-2))); lir->operands[0] = (delta >> 12) & 0x7ff; @@ -1444,20 +1443,19 @@ void ArmMir2Lir::AssembleLIR() { break; } case kFixupAdr: { - SwitchTable *tab_rec = reinterpret_cast(lir->operands[2]); + EmbeddedData *tab_rec = reinterpret_cast(UnwrapPointer(lir->operands[2])); LIR* target = lir->target; - int target_disp = (tab_rec != NULL) ? tab_rec->offset + offset_adjustment + int32_t target_disp = (tab_rec != NULL) ? tab_rec->offset + offset_adjustment : target->offset + ((target->flags.generation == lir->flags.generation) ? 0 : offset_adjustment); - int disp = target_disp - ((lir->offset + 4) & ~3); + int32_t disp = target_disp - ((lir->offset + 4) & ~3); if (disp < 4096) { lir->operands[1] = disp; } else { // convert to ldimm16l, ldimm16h, add tgt, pc, operands[0] // TUNING: if this case fires often, it can be improved. Not expected to be common. LIR *new_mov16L = - RawLIR(lir->dalvik_offset, kThumb2MovImm16LST, - lir->operands[0], 0, reinterpret_cast(lir), - reinterpret_cast(tab_rec), 0, lir->target); + RawLIR(lir->dalvik_offset, kThumb2MovImm16LST, lir->operands[0], 0, + WrapPointer(lir), WrapPointer(tab_rec), 0, lir->target); new_mov16L->flags.size = EncodingMap[new_mov16L->opcode].size; new_mov16L->flags.fixup = kFixupMovImmLST; new_mov16L->offset = lir->offset; @@ -1467,11 +1465,9 @@ void ArmMir2Lir::AssembleLIR() { offset_adjustment += new_mov16L->flags.size; InsertFixupBefore(prev_lir, lir, new_mov16L); prev_lir = new_mov16L; // Now we've got a new prev. - LIR *new_mov16H = - RawLIR(lir->dalvik_offset, kThumb2MovImm16HST, - lir->operands[0], 0, reinterpret_cast(lir), - reinterpret_cast(tab_rec), 0, lir->target); + RawLIR(lir->dalvik_offset, kThumb2MovImm16HST, lir->operands[0], 0, + WrapPointer(lir), WrapPointer(tab_rec), 0, lir->target); new_mov16H->flags.size = EncodingMap[new_mov16H->opcode].size; new_mov16H->flags.fixup = kFixupMovImmHST; new_mov16H->offset = lir->offset; @@ -1499,27 +1495,27 @@ void ArmMir2Lir::AssembleLIR() { } case kFixupMovImmLST: { // operands[1] should hold disp, [2] has add, [3] has tab_rec - LIR *addPCInst = reinterpret_cast(lir->operands[2]); - SwitchTable *tab_rec = reinterpret_cast(lir->operands[3]); + LIR *addPCInst = reinterpret_cast(UnwrapPointer(lir->operands[2])); + EmbeddedData *tab_rec = reinterpret_cast(UnwrapPointer(lir->operands[3])); // If tab_rec is null, this is a literal load. Use target LIR* target = lir->target; - int target_disp = tab_rec ? tab_rec->offset : target->offset; + int32_t target_disp = tab_rec ? tab_rec->offset : target->offset; lir->operands[1] = (target_disp - (addPCInst->offset + 4)) & 0xffff; break; } case kFixupMovImmHST: { // operands[1] should hold disp, [2] has add, [3] has tab_rec - LIR *addPCInst = reinterpret_cast(lir->operands[2]); - SwitchTable *tab_rec = reinterpret_cast(lir->operands[3]); + LIR *addPCInst = reinterpret_cast(UnwrapPointer(lir->operands[2])); + EmbeddedData *tab_rec = reinterpret_cast(UnwrapPointer(lir->operands[3])); // If tab_rec is null, this is a literal load. Use target LIR* target = lir->target; - int target_disp = tab_rec ? tab_rec->offset : target->offset; + int32_t target_disp = tab_rec ? tab_rec->offset : target->offset; lir->operands[1] = ((target_disp - (addPCInst->offset + 4)) >> 16) & 0xffff; break; } case kFixupAlign4: { - int required_size = lir->offset & 0x2; + int32_t required_size = lir->offset & 0x2; if (lir->flags.size != required_size) { offset_adjustment += required_size - lir->flags.size; lir->flags.size = required_size; @@ -1647,7 +1643,7 @@ uint32_t ArmMir2Lir::EncodeRange(LIR* head_lir, LIR* tail_lir, uint32_t offset) void ArmMir2Lir::AssignDataOffsets() { /* Set up offsets for literals */ - int offset = data_offset_; + CodeOffset offset = data_offset_; offset = AssignLiteralOffset(offset); diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index 401da2abd4..51aca8540c 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -92,7 +92,7 @@ void ArmMir2Lir::LockLiveArgs(MIR* mir) { } /* Find the next MIR, which may be in a following basic block */ -// TODO: should this be a utility in mir_graph? +// TODO: make this a utility in mir_graph. MIR* ArmMir2Lir::GetNextMir(BasicBlock** p_bb, MIR* mir) { BasicBlock* bb = *p_bb; MIR* orig_mir = mir; @@ -103,7 +103,7 @@ MIR* ArmMir2Lir::GetNextMir(BasicBlock** p_bb, MIR* mir) { if (mir != NULL) { return mir; } else { - bb = bb->fall_through; + bb = mir_graph_->GetBasicBlock(bb->fall_through); *p_bb = bb; if (bb) { mir = bb->first_mir_insn; @@ -128,7 +128,7 @@ void ArmMir2Lir::GenPrintLabel(MIR* mir) { MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir, OpSize size, bool long_or_double, bool is_object) { - int field_offset; + int32_t field_offset; bool is_volatile; uint32_t field_idx = mir->dalvikInsn.vC; bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile); @@ -153,7 +153,7 @@ MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir, MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir, OpSize size, bool long_or_double, bool is_object) { - int field_offset; + int32_t field_offset; bool is_volatile; uint32_t field_idx = mir->dalvikInsn.vC; bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile); @@ -320,9 +320,9 @@ void ArmMir2Lir::GenSparseSwitch(MIR* mir, uint32_t table_offset, static_cast(arena_->Alloc(sizeof(SwitchTable), ArenaAllocator::kAllocData)); tab_rec->table = table; tab_rec->vaddr = current_dalvik_offset_; - int size = table[1]; + uint32_t size = table[1]; tab_rec->targets = static_cast(arena_->Alloc(size * sizeof(LIR*), - ArenaAllocator::kAllocLIR)); + ArenaAllocator::kAllocLIR)); switch_tables_.Insert(tab_rec); // Get the switch value @@ -338,7 +338,7 @@ void ArmMir2Lir::GenSparseSwitch(MIR* mir, uint32_t table_offset, r_key = tmp; } // Materialize a pointer to the switch table - NewLIR3(kThumb2Adr, rBase, 0, reinterpret_cast(tab_rec)); + NewLIR3(kThumb2Adr, rBase, 0, WrapPointer(tab_rec)); // Set up r_idx int r_idx = AllocTemp(); LoadConstant(r_idx, size); @@ -368,7 +368,7 @@ void ArmMir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset, static_cast(arena_->Alloc(sizeof(SwitchTable), ArenaAllocator::kAllocData)); tab_rec->table = table; tab_rec->vaddr = current_dalvik_offset_; - int size = table[1]; + uint32_t size = table[1]; tab_rec->targets = static_cast(arena_->Alloc(size * sizeof(LIR*), ArenaAllocator::kAllocLIR)); switch_tables_.Insert(tab_rec); @@ -377,7 +377,7 @@ void ArmMir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset, rl_src = LoadValue(rl_src, kCoreReg); int table_base = AllocTemp(); // Materialize a pointer to the switch table - NewLIR3(kThumb2Adr, table_base, 0, reinterpret_cast(tab_rec)); + NewLIR3(kThumb2Adr, table_base, 0, WrapPointer(tab_rec)); int low_key = s4FromSwitchData(&table[2]); int keyReg; // Remove the bias, if necessary @@ -433,7 +433,7 @@ void ArmMir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pHandleFillArrayData).Int32Value(), rARM_LR); // Materialize a pointer to the fill data image - NewLIR3(kThumb2Adr, r1, 0, reinterpret_cast(tab_rec)); + NewLIR3(kThumb2Adr, r1, 0, WrapPointer(tab_rec)); ClobberCalleeSave(); LIR* call_inst = OpReg(kOpBlx, rARM_LR); MarkSafepointPC(call_inst); diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h index aa5782b20c..0a3bfc10ee 100644 --- a/compiler/dex/quick/arm/codegen_arm.h +++ b/compiler/dex/quick/arm/codegen_arm.h @@ -74,7 +74,6 @@ class ArmMir2Lir : public Mir2Lir { uint32_t EncodeRange(LIR* head_lir, LIR* tail_lir, uint32_t starting_offset); int AssignInsnOffsets(); void AssignOffsets(); - AssemblerStatus AssembleInstructions(uintptr_t start_addr); void EncodeLIR(LIR* lir); void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix); void SetupTargetResourceMasks(LIR* lir, uint64_t flags); @@ -120,7 +119,7 @@ class ArmMir2Lir : public Mir2Lir { void GenDivZeroCheck(int reg_lo, int reg_hi); void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method); void GenExitSequence(); - void GenFillArrayData(uint32_t table_offset, RegLocation rl_src); + void GenFillArrayData(DexOffset table_offset, RegLocation rl_src); void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double); void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir); void GenSelect(BasicBlock* bb, MIR* mir); @@ -132,8 +131,8 @@ class ArmMir2Lir : public Mir2Lir { int first_bit, int second_bit); void GenNegDouble(RegLocation rl_dest, RegLocation rl_src); void GenNegFloat(RegLocation rl_dest, RegLocation rl_src); - void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src); - void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src); + void GenPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src); + void GenSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src); void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case); // Required for target - single operation generators. diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc index 08d6778129..480e0218d5 100644 --- a/compiler/dex/quick/arm/fp_arm.cc +++ b/compiler/dex/quick/arm/fp_arm.cc @@ -176,7 +176,7 @@ void ArmMir2Lir::GenConversion(Instruction::Code opcode, void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double) { - LIR* target = &block_label_list_[bb->taken->id]; + LIR* target = &block_label_list_[bb->taken]; RegLocation rl_src1; RegLocation rl_src2; if (is_double) { diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index b1772fd81f..69ea4e9ca3 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -122,8 +122,8 @@ void ArmMir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1, int32_t val_hi = High32Bits(val); DCHECK_GE(ModifiedImmediate(val_lo), 0); DCHECK_GE(ModifiedImmediate(val_hi), 0); - LIR* taken = &block_label_list_[bb->taken->id]; - LIR* not_taken = &block_label_list_[bb->fall_through->id]; + LIR* taken = &block_label_list_[bb->taken]; + LIR* not_taken = &block_label_list_[bb->fall_through]; rl_src1 = LoadValueWide(rl_src1, kCoreReg); int32_t low_reg = rl_src1.low_reg; int32_t high_reg = rl_src1.high_reg; @@ -178,23 +178,6 @@ void ArmMir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1, void ArmMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { RegLocation rl_result; RegLocation rl_src = mir_graph_->GetSrc(mir, 0); - // Temporary debugging code - int dest_sreg = mir->ssa_rep->defs[0]; - if ((dest_sreg < 0) || (dest_sreg >= mir_graph_->GetNumSSARegs())) { - LOG(INFO) << "Bad target sreg: " << dest_sreg << ", in " - << PrettyMethod(cu_->method_idx, *cu_->dex_file); - LOG(INFO) << "at dex offset 0x" << std::hex << mir->offset; - LOG(INFO) << "vreg = " << mir_graph_->SRegToVReg(dest_sreg); - LOG(INFO) << "num uses = " << mir->ssa_rep->num_uses; - if (mir->ssa_rep->num_uses == 1) { - LOG(INFO) << "CONST case, vals = " << mir->dalvikInsn.vB << ", " << mir->dalvikInsn.vC; - } else { - LOG(INFO) << "MOVE case, operands = " << mir->ssa_rep->uses[1] << ", " - << mir->ssa_rep->uses[2]; - } - CHECK(false) << "Invalid target sreg on Select."; - } - // End temporary debugging code RegLocation rl_dest = mir_graph_->GetDest(mir); rl_src = LoadValue(rl_src, kCoreReg); if (mir->ssa_rep->num_uses == 1) { @@ -270,8 +253,8 @@ void ArmMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) { return; } } - LIR* taken = &block_label_list_[bb->taken->id]; - LIR* not_taken = &block_label_list_[bb->fall_through->id]; + LIR* taken = &block_label_list_[bb->taken]; + LIR* not_taken = &block_label_list_[bb->fall_through]; rl_src1 = LoadValueWide(rl_src1, kCoreReg); rl_src2 = LoadValueWide(rl_src2, kCoreReg); OpRegReg(kOpCmp, rl_src1.high_reg, rl_src2.high_reg); diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc index 933c1a3b91..3395ae7a44 100644 --- a/compiler/dex/quick/arm/target_arm.cc +++ b/compiler/dex/quick/arm/target_arm.cc @@ -282,8 +282,8 @@ static char* DecodeFPCSRegList(int count, int base, char* buf) { return buf; } -static int ExpandImmediate(int value) { - int mode = (value & 0xf00) >> 8; +static int32_t ExpandImmediate(int value) { + int32_t mode = (value & 0xf00) >> 8; uint32_t bits = value & 0xff; switch (mode) { case 0: diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc index 00de8de70a..a2ac6ef53b 100644 --- a/compiler/dex/quick/arm/utility_arm.cc +++ b/compiler/dex/quick/arm/utility_arm.cc @@ -22,14 +22,14 @@ namespace art { /* This file contains codegen for the Thumb ISA. */ -static int EncodeImmSingle(int value) { - int res; - int bit_a = (value & 0x80000000) >> 31; - int not_bit_b = (value & 0x40000000) >> 30; - int bit_b = (value & 0x20000000) >> 29; - int b_smear = (value & 0x3e000000) >> 25; - int slice = (value & 0x01f80000) >> 19; - int zeroes = (value & 0x0007ffff); +static int32_t EncodeImmSingle(int32_t value) { + int32_t res; + int32_t bit_a = (value & 0x80000000) >> 31; + int32_t not_bit_b = (value & 0x40000000) >> 30; + int32_t bit_b = (value & 0x20000000) >> 29; + int32_t b_smear = (value & 0x3e000000) >> 25; + int32_t slice = (value & 0x01f80000) >> 19; + int32_t zeroes = (value & 0x0007ffff); if (zeroes != 0) return -1; if (bit_b) { @@ -47,15 +47,15 @@ static int EncodeImmSingle(int value) { * Determine whether value can be encoded as a Thumb2 floating point * immediate. If not, return -1. If so return encoded 8-bit value. */ -static int EncodeImmDouble(int64_t value) { - int res; - int bit_a = (value & 0x8000000000000000ll) >> 63; - int not_bit_b = (value & 0x4000000000000000ll) >> 62; - int bit_b = (value & 0x2000000000000000ll) >> 61; - int b_smear = (value & 0x3fc0000000000000ll) >> 54; - int slice = (value & 0x003f000000000000ll) >> 48; +static int32_t EncodeImmDouble(int64_t value) { + int32_t res; + int32_t bit_a = (value & 0x8000000000000000ll) >> 63; + int32_t not_bit_b = (value & 0x4000000000000000ll) >> 62; + int32_t bit_b = (value & 0x2000000000000000ll) >> 61; + int32_t b_smear = (value & 0x3fc0000000000000ll) >> 54; + int32_t slice = (value & 0x003f000000000000ll) >> 48; uint64_t zeroes = (value & 0x0000ffffffffffffll); - if (zeroes != 0) + if (zeroes != 0ull) return -1; if (bit_b) { if ((not_bit_b != 0) || (b_smear != 0xff)) @@ -96,8 +96,8 @@ LIR* ArmMir2Lir::LoadFPConstantValue(int r_dest, int value) { static int LeadingZeros(uint32_t val) { uint32_t alt; - int n; - int count; + int32_t n; + int32_t count; count = 16; n = 32; @@ -117,8 +117,8 @@ static int LeadingZeros(uint32_t val) { * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form. */ int ArmMir2Lir::ModifiedImmediate(uint32_t value) { - int z_leading; - int z_trailing; + int32_t z_leading; + int32_t z_trailing; uint32_t b0 = value & 0xff; /* Note: case of value==0 must use 0:000:0:0000000 encoding */ @@ -421,12 +421,12 @@ LIR* ArmMir2Lir::OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2) { LIR* ArmMir2Lir::OpRegRegImm(OpKind op, int r_dest, int r_src1, int value) { LIR* res; bool neg = (value < 0); - int abs_value = (neg) ? -value : value; + int32_t abs_value = (neg) ? -value : value; ArmOpcode opcode = kThumbBkpt; ArmOpcode alt_opcode = kThumbBkpt; bool all_low_regs = (ARM_LOWREG(r_dest) && ARM_LOWREG(r_src1)); - int mod_imm = ModifiedImmediate(value); - int mod_imm_neg = ModifiedImmediate(-value); + int32_t mod_imm = ModifiedImmediate(value); + int32_t mod_imm_neg = ModifiedImmediate(-value); switch (op) { case kOpLsl: @@ -544,7 +544,7 @@ LIR* ArmMir2Lir::OpRegRegImm(OpKind op, int r_dest, int r_src1, int value) { /* Handle Thumb-only variants here - otherwise punt to OpRegRegImm */ LIR* ArmMir2Lir::OpRegImm(OpKind op, int r_dest_src1, int value) { bool neg = (value < 0); - int abs_value = (neg) ? -value : value; + int32_t abs_value = (neg) ? -value : value; bool short_form = (((abs_value & 0xff) == abs_value) && ARM_LOWREG(r_dest_src1)); ArmOpcode opcode = kThumbBkpt; switch (op) { diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 617f35707c..2ce8f581b4 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -160,7 +160,8 @@ void Mir2Lir::DumpLIRInsn(LIR* lir, unsigned char* base_addr) { break; case kPseudoDalvikByteCodeBoundary: if (lir->operands[0] == 0) { - lir->operands[0] = reinterpret_cast("No instruction string"); + // NOTE: only used for debug listings. + lir->operands[0] = WrapPointer(ArenaStrdup("No instruction string")); } LOG(INFO) << "-------- dalvik offset: 0x" << std::hex << lir->dalvik_offset << " @ " << reinterpret_cast(lir->operands[0]); @@ -369,6 +370,17 @@ static void PushWord(std::vector&buf, int data) { buf.push_back((data >> 24) & 0xff); } +// Push 8 bytes on 64-bit systems; 4 on 32-bit systems. +static void PushPointer(std::vector&buf, void const* pointer) { + uintptr_t data = reinterpret_cast(pointer); + if (sizeof(void*) == sizeof(uint64_t)) { + PushWord(buf, (data >> (sizeof(void*) * 4)) & 0xFFFFFFFF); + PushWord(buf, data & 0xFFFFFFFF); + } else { + PushWord(buf, data); + } +} + static void AlignBuffer(std::vector&buf, size_t offset) { while (buf.size() < offset) { buf.push_back(0); @@ -395,9 +407,8 @@ void Mir2Lir::InstallLiteralPools() { static_cast(data_lir->operands[1]), code_buffer_.size()); const DexFile::MethodId& id = cu_->dex_file->GetMethodId(target); - // unique based on target to ensure code deduplication works - uint32_t unique_patch_value = reinterpret_cast(&id); - PushWord(code_buffer_, unique_patch_value); + // unique value based on target to ensure code deduplication works + PushPointer(code_buffer_, &id); data_lir = NEXT_LIR(data_lir); } data_lir = method_literal_list_; @@ -411,9 +422,8 @@ void Mir2Lir::InstallLiteralPools() { static_cast(data_lir->operands[1]), code_buffer_.size()); const DexFile::MethodId& id = cu_->dex_file->GetMethodId(target); - // unique based on target to ensure code deduplication works - uint32_t unique_patch_value = reinterpret_cast(&id); - PushWord(code_buffer_, unique_patch_value); + // unique value based on target to ensure code deduplication works + PushPointer(code_buffer_, &id); data_lir = NEXT_LIR(data_lir); } } @@ -449,7 +459,7 @@ void Mir2Lir::InstallSwitchTables() { LOG(INFO) << "Switch table for offset 0x" << std::hex << bx_offset; } if (tab_rec->table[0] == Instruction::kSparseSwitchSignature) { - const int* keys = reinterpret_cast(&(tab_rec->table[2])); + const int32_t* keys = reinterpret_cast(&(tab_rec->table[2])); for (int elems = 0; elems < tab_rec->table[1]; elems++) { int disp = tab_rec->targets[elems]->offset - bx_offset; if (cu_->verbose) { @@ -490,7 +500,7 @@ void Mir2Lir::InstallFillArrayData() { } } -static int AssignLiteralOffsetCommon(LIR* lir, int offset) { +static int AssignLiteralOffsetCommon(LIR* lir, CodeOffset offset) { for (; lir != NULL; lir = lir->next) { lir->offset = offset; offset += 4; @@ -498,6 +508,17 @@ static int AssignLiteralOffsetCommon(LIR* lir, int offset) { return offset; } +static int AssignLiteralPointerOffsetCommon(LIR* lir, CodeOffset offset) { + unsigned int element_size = sizeof(void*); + // Align to natural pointer size. + offset = (offset + (element_size - 1)) & ~(element_size - 1); + for (; lir != NULL; lir = lir->next) { + lir->offset = offset; + offset += element_size; + } + return offset; +} + // Make sure we have a code address for every declared catch entry bool Mir2Lir::VerifyCatchEntries() { bool success = true; @@ -607,8 +628,8 @@ class NativePcToReferenceMapBuilder { table_index = (table_index + 1) % entries_; } in_use_[table_index] = true; - SetNativeOffset(table_index, native_offset); - DCHECK_EQ(native_offset, GetNativeOffset(table_index)); + SetCodeOffset(table_index, native_offset); + DCHECK_EQ(native_offset, GetCodeOffset(table_index)); SetReferences(table_index, references); } @@ -617,7 +638,7 @@ class NativePcToReferenceMapBuilder { return NativePcOffsetToReferenceMap::Hash(native_offset) % entries_; } - uint32_t GetNativeOffset(size_t table_index) { + uint32_t GetCodeOffset(size_t table_index) { uint32_t native_offset = 0; size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); for (size_t i = 0; i < native_offset_width_; i++) { @@ -626,7 +647,7 @@ class NativePcToReferenceMapBuilder { return native_offset; } - void SetNativeOffset(size_t table_index, uint32_t native_offset) { + void SetCodeOffset(size_t table_index, uint32_t native_offset) { size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); for (size_t i = 0; i < native_offset_width_; i++) { (*table_)[table_offset + i] = (native_offset >> (i * 8)) & 0xFF; @@ -681,17 +702,17 @@ void Mir2Lir::CreateNativeGcMap() { } /* Determine the offset of each literal field */ -int Mir2Lir::AssignLiteralOffset(int offset) { +int Mir2Lir::AssignLiteralOffset(CodeOffset offset) { offset = AssignLiteralOffsetCommon(literal_list_, offset); - offset = AssignLiteralOffsetCommon(code_literal_list_, offset); - offset = AssignLiteralOffsetCommon(method_literal_list_, offset); + offset = AssignLiteralPointerOffsetCommon(code_literal_list_, offset); + offset = AssignLiteralPointerOffsetCommon(method_literal_list_, offset); return offset; } -int Mir2Lir::AssignSwitchTablesOffset(int offset) { +int Mir2Lir::AssignSwitchTablesOffset(CodeOffset offset) { GrowableArray::Iterator iterator(&switch_tables_); while (true) { - Mir2Lir::SwitchTable *tab_rec = iterator.Next(); + Mir2Lir::SwitchTable* tab_rec = iterator.Next(); if (tab_rec == NULL) break; tab_rec->offset = offset; if (tab_rec->table[0] == Instruction::kSparseSwitchSignature) { @@ -705,7 +726,7 @@ int Mir2Lir::AssignSwitchTablesOffset(int offset) { return offset; } -int Mir2Lir::AssignFillArrayDataOffset(int offset) { +int Mir2Lir::AssignFillArrayDataOffset(CodeOffset offset) { GrowableArray::Iterator iterator(&fill_array_data_); while (true) { Mir2Lir::FillArrayData *tab_rec = iterator.Next(); @@ -725,7 +746,7 @@ int Mir2Lir::AssignFillArrayDataOffset(int offset) { * branch table during the assembly phase. All resource flags * are set to prevent code motion. KeyVal is just there for debugging. */ -LIR* Mir2Lir::InsertCaseLabel(int vaddr, int keyVal) { +LIR* Mir2Lir::InsertCaseLabel(DexOffset vaddr, int keyVal) { LIR* boundary_lir = &block_label_list_[mir_graph_->FindBlock(vaddr)->id]; LIR* res = boundary_lir; if (cu_->verbose) { @@ -743,10 +764,10 @@ LIR* Mir2Lir::InsertCaseLabel(int vaddr, int keyVal) { return res; } -void Mir2Lir::MarkPackedCaseLabels(Mir2Lir::SwitchTable *tab_rec) { +void Mir2Lir::MarkPackedCaseLabels(Mir2Lir::SwitchTable* tab_rec) { const uint16_t* table = tab_rec->table; - int base_vaddr = tab_rec->vaddr; - const int *targets = reinterpret_cast(&table[4]); + DexOffset base_vaddr = tab_rec->vaddr; + const int32_t *targets = reinterpret_cast(&table[4]); int entries = table[1]; int low_key = s4FromSwitchData(&table[2]); for (int i = 0; i < entries; i++) { @@ -754,12 +775,12 @@ void Mir2Lir::MarkPackedCaseLabels(Mir2Lir::SwitchTable *tab_rec) { } } -void Mir2Lir::MarkSparseCaseLabels(Mir2Lir::SwitchTable *tab_rec) { +void Mir2Lir::MarkSparseCaseLabels(Mir2Lir::SwitchTable* tab_rec) { const uint16_t* table = tab_rec->table; - int base_vaddr = tab_rec->vaddr; + DexOffset base_vaddr = tab_rec->vaddr; int entries = table[1]; - const int* keys = reinterpret_cast(&table[2]); - const int* targets = &keys[entries]; + const int32_t* keys = reinterpret_cast(&table[2]); + const int32_t* targets = &keys[entries]; for (int i = 0; i < entries; i++) { tab_rec->targets[i] = InsertCaseLabel(base_vaddr + targets[i], keys[i]); } @@ -792,8 +813,8 @@ void Mir2Lir::DumpSparseSwitchTable(const uint16_t* table) { */ uint16_t ident = table[0]; int entries = table[1]; - const int* keys = reinterpret_cast(&table[2]); - const int* targets = &keys[entries]; + const int32_t* keys = reinterpret_cast(&table[2]); + const int32_t* targets = &keys[entries]; LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident << ", entries: " << std::dec << entries; for (int i = 0; i < entries; i++) { @@ -812,7 +833,7 @@ void Mir2Lir::DumpPackedSwitchTable(const uint16_t* table) { * Total size is (4+size*2) 16-bit code units. */ uint16_t ident = table[0]; - const int* targets = reinterpret_cast(&table[4]); + const int32_t* targets = reinterpret_cast(&table[4]); int entries = table[1]; int low_key = s4FromSwitchData(&table[2]); LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident @@ -824,8 +845,9 @@ void Mir2Lir::DumpPackedSwitchTable(const uint16_t* table) { } /* Set up special LIR to mark a Dalvik byte-code instruction start for pretty printing */ -void Mir2Lir::MarkBoundary(int offset, const char* inst_str) { - NewLIR1(kPseudoDalvikByteCodeBoundary, reinterpret_cast(inst_str)); +void Mir2Lir::MarkBoundary(DexOffset offset, const char* inst_str) { + // NOTE: only used for debug listings. + NewLIR1(kPseudoDalvikByteCodeBoundary, WrapPointer(ArenaStrdup(inst_str))); } bool Mir2Lir::EvaluateBranch(Instruction::Code opcode, int32_t src1, int32_t src2) { @@ -883,6 +905,7 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena intrinsic_launchpads_(arena, 2048, kGrowableArrayMisc), tempreg_info_(arena, 20, kGrowableArrayMisc), reginfo_map_(arena, 64, kGrowableArrayMisc), + pointer_storage_(arena, 128, kGrowableArrayMisc), data_offset_(0), total_size_(0), block_label_list_(NULL), @@ -900,6 +923,9 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena promotion_map_ = static_cast (arena_->Alloc((cu_->num_dalvik_registers + cu_->num_compiler_temps + 1) * sizeof(promotion_map_[0]), ArenaAllocator::kAllocRegAlloc)); + // Reserve pointer id 0 for NULL. + size_t null_idx = WrapPointer(NULL); + DCHECK_EQ(null_idx, 0U); } void Mir2Lir::Materialize() { diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 2670c23a0d..2b3404a9c7 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -40,7 +40,7 @@ void Mir2Lir::GenBarrier() { barrier->u.m.def_mask = ENCODE_ALL; } -// FIXME: need to do some work to split out targets with +// TODO: need to do some work to split out targets with // condition codes and those without LIR* Mir2Lir::GenCheck(ConditionCode c_code, ThrowKind kind) { DCHECK_NE(cu_->instruction_set, kMips); @@ -503,7 +503,7 @@ void Mir2Lir::HandleSuspendLaunchPads() { ResetRegPool(); ResetDefTracking(); LIR* lab = suspend_launchpads_.Get(i); - LIR* resume_lab = reinterpret_cast(lab->operands[0]); + LIR* resume_lab = reinterpret_cast(UnwrapPointer(lab->operands[0])); current_dalvik_offset_ = lab->operands[1]; AppendLIR(lab); int r_tgt = CallHelperSetup(helper_offset); @@ -518,12 +518,12 @@ void Mir2Lir::HandleIntrinsicLaunchPads() { ResetRegPool(); ResetDefTracking(); LIR* lab = intrinsic_launchpads_.Get(i); - CallInfo* info = reinterpret_cast(lab->operands[0]); + CallInfo* info = reinterpret_cast(UnwrapPointer(lab->operands[0])); current_dalvik_offset_ = info->offset; AppendLIR(lab); // NOTE: GenInvoke handles MarkSafepointPC GenInvoke(info); - LIR* resume_lab = reinterpret_cast(lab->operands[2]); + LIR* resume_lab = reinterpret_cast(UnwrapPointer(lab->operands[2])); if (resume_lab != NULL) { OpUnconditionalBranch(resume_lab); } @@ -1351,7 +1351,7 @@ static bool IsPopCountLE2(unsigned int x) { } // Returns the index of the lowest set bit in 'x'. -static int LowestSetBit(unsigned int x) { +static int32_t LowestSetBit(uint32_t x) { int bit_posn = 0; while ((x & 0xf) == 0) { bit_posn += 4; @@ -1752,8 +1752,8 @@ void Mir2Lir::GenSuspendTest(int opt_flags) { FlushAllRegs(); LIR* branch = OpTestSuspend(NULL); LIR* ret_lab = NewLIR0(kPseudoTargetLabel); - LIR* target = RawLIR(current_dalvik_offset_, kPseudoSuspendTarget, - reinterpret_cast(ret_lab), current_dalvik_offset_); + LIR* target = RawLIR(current_dalvik_offset_, kPseudoSuspendTarget, WrapPointer(ret_lab), + current_dalvik_offset_); branch->target = target; suspend_launchpads_.Insert(target); } @@ -1766,8 +1766,8 @@ void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target) { } OpTestSuspend(target); LIR* launch_pad = - RawLIR(current_dalvik_offset_, kPseudoSuspendTarget, - reinterpret_cast(target), current_dalvik_offset_); + RawLIR(current_dalvik_offset_, kPseudoSuspendTarget, WrapPointer(target), + current_dalvik_offset_); FlushAllRegs(); OpUnconditionalBranch(launch_pad); suspend_launchpads_.Insert(launch_pad); diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 0a0cc17ab2..3def7f5404 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -908,7 +908,7 @@ bool Mir2Lir::GenInlinedCharAt(CallInfo* info) { LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr); if (range_check) { // Set up a launch pad to allow retry in case of bounds violation */ - launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast(info)); + launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info)); intrinsic_launchpads_.Insert(launch_pad); OpRegReg(kOpCmp, rl_idx.low_reg, reg_max); FreeTemp(reg_max); @@ -919,7 +919,7 @@ bool Mir2Lir::GenInlinedCharAt(CallInfo* info) { reg_max = AllocTemp(); LoadWordDisp(rl_obj.low_reg, count_offset, reg_max); // Set up a launch pad to allow retry in case of bounds violation */ - launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast(info)); + launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info)); intrinsic_launchpads_.Insert(launch_pad); OpRegReg(kOpCmp, rl_idx.low_reg, reg_max); FreeTemp(reg_max); @@ -1085,7 +1085,7 @@ bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) { } int r_tgt = (cu_->instruction_set != kX86) ? LoadHelper(QUICK_ENTRYPOINT_OFFSET(pIndexOf)) : 0; GenNullCheck(rl_obj.s_reg_low, reg_ptr, info->opt_flags); - LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast(info)); + LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info)); intrinsic_launchpads_.Insert(launch_pad); OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, launch_pad); // NOTE: not a safepoint @@ -1095,7 +1095,7 @@ bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) { OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pIndexOf)); } LIR* resume_tgt = NewLIR0(kPseudoTargetLabel); - launch_pad->operands[2] = reinterpret_cast(resume_tgt); + launch_pad->operands[2] = WrapPointer(resume_tgt); // Record that we've already inlined & null checked info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK); RegLocation rl_return = GetReturn(false); @@ -1123,7 +1123,7 @@ bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info) { LoadHelper(QUICK_ENTRYPOINT_OFFSET(pStringCompareTo)) : 0; GenNullCheck(rl_this.s_reg_low, reg_this, info->opt_flags); // TUNING: check if rl_cmp.s_reg_low is already null checked - LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast(info)); + LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info)); intrinsic_launchpads_.Insert(launch_pad); OpCmpImmBranch(kCondEq, reg_cmp, 0, launch_pad); // NOTE: not a safepoint diff --git a/compiler/dex/quick/mips/assemble_mips.cc b/compiler/dex/quick/mips/assemble_mips.cc index 6bfccfd575..ea8b7a64c1 100644 --- a/compiler/dex/quick/mips/assemble_mips.cc +++ b/compiler/dex/quick/mips/assemble_mips.cc @@ -489,12 +489,12 @@ void MipsMir2Lir::ConvertShortToLongBranch(LIR* lir) { LIR* curr_pc = RawLIR(dalvik_offset, kMipsCurrPC); InsertLIRBefore(lir, curr_pc); LIR* anchor = RawLIR(dalvik_offset, kPseudoTargetLabel); - LIR* delta_hi = RawLIR(dalvik_offset, kMipsDeltaHi, r_AT, 0, - reinterpret_cast(anchor), 0, 0, lir->target); + LIR* delta_hi = RawLIR(dalvik_offset, kMipsDeltaHi, r_AT, 0, WrapPointer(anchor), 0, 0, + lir->target); InsertLIRBefore(lir, delta_hi); InsertLIRBefore(lir, anchor); - LIR* delta_lo = RawLIR(dalvik_offset, kMipsDeltaLo, r_AT, 0, - reinterpret_cast(anchor), 0, 0, lir->target); + LIR* delta_lo = RawLIR(dalvik_offset, kMipsDeltaLo, r_AT, 0, WrapPointer(anchor), 0, 0, + lir->target); InsertLIRBefore(lir, delta_lo); LIR* addu = RawLIR(dalvik_offset, kMipsAddu, r_AT, r_AT, r_RA); InsertLIRBefore(lir, addu); @@ -512,7 +512,7 @@ void MipsMir2Lir::ConvertShortToLongBranch(LIR* lir) { * instruction. In those cases we will try to substitute a new code * sequence or request that the trace be shortened and retried. */ -AssemblerStatus MipsMir2Lir::AssembleInstructions(uintptr_t start_addr) { +AssemblerStatus MipsMir2Lir::AssembleInstructions(CodeOffset start_addr) { LIR *lir; AssemblerStatus res = kSuccess; // Assume success @@ -538,8 +538,8 @@ AssemblerStatus MipsMir2Lir::AssembleInstructions(uintptr_t start_addr) { * and is found in lir->target. If operands[3] is non-NULL, * then it is a Switch/Data table. */ - int offset1 = (reinterpret_cast(lir->operands[2]))->offset; - SwitchTable *tab_rec = reinterpret_cast(lir->operands[3]); + int offset1 = (reinterpret_cast(UnwrapPointer(lir->operands[2])))->offset; + EmbeddedData *tab_rec = reinterpret_cast(UnwrapPointer(lir->operands[3])); int offset2 = tab_rec ? tab_rec->offset : lir->target->offset; int delta = offset2 - offset1; if ((delta & 0xffff) == delta && ((delta & 0x8000) == 0)) { @@ -565,21 +565,21 @@ AssemblerStatus MipsMir2Lir::AssembleInstructions(uintptr_t start_addr) { res = kRetryAll; } } else if (lir->opcode == kMipsDeltaLo) { - int offset1 = (reinterpret_cast(lir->operands[2]))->offset; - SwitchTable *tab_rec = reinterpret_cast(lir->operands[3]); + int offset1 = (reinterpret_cast(UnwrapPointer(lir->operands[2])))->offset; + EmbeddedData *tab_rec = reinterpret_cast(UnwrapPointer(lir->operands[3])); int offset2 = tab_rec ? tab_rec->offset : lir->target->offset; int delta = offset2 - offset1; lir->operands[1] = delta & 0xffff; } else if (lir->opcode == kMipsDeltaHi) { - int offset1 = (reinterpret_cast(lir->operands[2]))->offset; - SwitchTable *tab_rec = reinterpret_cast(lir->operands[3]); + int offset1 = (reinterpret_cast(UnwrapPointer(lir->operands[2])))->offset; + EmbeddedData *tab_rec = reinterpret_cast(UnwrapPointer(lir->operands[3])); int offset2 = tab_rec ? tab_rec->offset : lir->target->offset; int delta = offset2 - offset1; lir->operands[1] = (delta >> 16) & 0xffff; } else if (lir->opcode == kMipsB || lir->opcode == kMipsBal) { LIR *target_lir = lir->target; - uintptr_t pc = lir->offset + 4; - uintptr_t target = target_lir->offset; + CodeOffset pc = lir->offset + 4; + CodeOffset target = target_lir->offset; int delta = target - pc; if (delta & 0x3) { LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta; @@ -592,8 +592,8 @@ AssemblerStatus MipsMir2Lir::AssembleInstructions(uintptr_t start_addr) { } } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) { LIR *target_lir = lir->target; - uintptr_t pc = lir->offset + 4; - uintptr_t target = target_lir->offset; + CodeOffset pc = lir->offset + 4; + CodeOffset target = target_lir->offset; int delta = target - pc; if (delta & 0x3) { LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta; @@ -606,8 +606,8 @@ AssemblerStatus MipsMir2Lir::AssembleInstructions(uintptr_t start_addr) { } } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) { LIR *target_lir = lir->target; - uintptr_t pc = lir->offset + 4; - uintptr_t target = target_lir->offset; + CodeOffset pc = lir->offset + 4; + CodeOffset target = target_lir->offset; int delta = target - pc; if (delta & 0x3) { LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta; @@ -619,8 +619,8 @@ AssemblerStatus MipsMir2Lir::AssembleInstructions(uintptr_t start_addr) { lir->operands[2] = delta >> 2; } } else if (lir->opcode == kMipsJal) { - uintptr_t cur_pc = (start_addr + lir->offset + 4) & ~3; - uintptr_t target = lir->operands[0]; + CodeOffset cur_pc = (start_addr + lir->offset + 4) & ~3; + CodeOffset target = lir->operands[0]; /* ensure PC-region branch can be used */ DCHECK_EQ((cur_pc & 0xF0000000), (target & 0xF0000000)); if (target & 0x3) { @@ -629,11 +629,11 @@ AssemblerStatus MipsMir2Lir::AssembleInstructions(uintptr_t start_addr) { lir->operands[0] = target >> 2; } else if (lir->opcode == kMipsLahi) { /* ld address hi (via lui) */ LIR *target_lir = lir->target; - uintptr_t target = start_addr + target_lir->offset; + CodeOffset target = start_addr + target_lir->offset; lir->operands[1] = target >> 16; } else if (lir->opcode == kMipsLalo) { /* ld address lo (via ori) */ LIR *target_lir = lir->target; - uintptr_t target = start_addr + target_lir->offset; + CodeOffset target = start_addr + target_lir->offset; lir->operands[2] = lir->operands[2] + target; } } diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc index 9a5ca2ce67..18c8cf87f2 100644 --- a/compiler/dex/quick/mips/call_mips.cc +++ b/compiler/dex/quick/mips/call_mips.cc @@ -59,14 +59,14 @@ void MipsMir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir, * done: * */ -void MipsMir2Lir::GenSparseSwitch(MIR* mir, uint32_t table_offset, +void MipsMir2Lir::GenSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) { const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset; if (cu_->verbose) { DumpSparseSwitchTable(table); } // Add the table to the list - we'll process it later - SwitchTable *tab_rec = + SwitchTable* tab_rec = static_cast(arena_->Alloc(sizeof(SwitchTable), ArenaAllocator::kAllocData)); tab_rec->table = table; tab_rec->vaddr = current_dalvik_offset_; @@ -101,8 +101,7 @@ void MipsMir2Lir::GenSparseSwitch(MIR* mir, uint32_t table_offset, // Remember base label so offsets can be computed later tab_rec->anchor = base_label; int rBase = AllocTemp(); - NewLIR4(kMipsDelta, rBase, 0, reinterpret_cast(base_label), - reinterpret_cast(tab_rec)); + NewLIR4(kMipsDelta, rBase, 0, WrapPointer(base_label), WrapPointer(tab_rec)); OpRegRegReg(kOpAdd, rEnd, rEnd, rBase); // Grab switch test value @@ -138,20 +137,20 @@ void MipsMir2Lir::GenSparseSwitch(MIR* mir, uint32_t table_offset, * jr r_RA * done: */ -void MipsMir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset, +void MipsMir2Lir::GenPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) { const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset; if (cu_->verbose) { DumpPackedSwitchTable(table); } // Add the table to the list - we'll process it later - SwitchTable *tab_rec = + SwitchTable* tab_rec = static_cast(arena_->Alloc(sizeof(SwitchTable), ArenaAllocator::kAllocData)); tab_rec->table = table; tab_rec->vaddr = current_dalvik_offset_; int size = table[1]; tab_rec->targets = static_cast(arena_->Alloc(size * sizeof(LIR*), - ArenaAllocator::kAllocLIR)); + ArenaAllocator::kAllocLIR)); switch_tables_.Insert(tab_rec); // Get the switch value @@ -196,8 +195,7 @@ void MipsMir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset, // Materialize the table base pointer int rBase = AllocTemp(); - NewLIR4(kMipsDelta, rBase, 0, reinterpret_cast(base_label), - reinterpret_cast(tab_rec)); + NewLIR4(kMipsDelta, rBase, 0, WrapPointer(base_label), WrapPointer(tab_rec)); // Load the displacement from the switch table int r_disp = AllocTemp(); @@ -222,10 +220,10 @@ void MipsMir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset, * * Total size is 4+(width * size + 1)/2 16-bit code units. */ -void MipsMir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { +void MipsMir2Lir::GenFillArrayData(DexOffset table_offset, RegLocation rl_src) { const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset; // Add the table to the list - we'll process it later - FillArrayData *tab_rec = + FillArrayData* tab_rec = reinterpret_cast(arena_->Alloc(sizeof(FillArrayData), ArenaAllocator::kAllocData)); tab_rec->table = table; @@ -252,8 +250,7 @@ void MipsMir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { LIR* base_label = NewLIR0(kPseudoTargetLabel); // Materialize a pointer to the fill data image - NewLIR4(kMipsDelta, rMIPS_ARG1, 0, reinterpret_cast(base_label), - reinterpret_cast(tab_rec)); + NewLIR4(kMipsDelta, rMIPS_ARG1, 0, WrapPointer(base_label), WrapPointer(tab_rec)); // And go... ClobberCalleeSave(); diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h index 387fef35b8..0be20e8ea5 100644 --- a/compiler/dex/quick/mips/codegen_mips.h +++ b/compiler/dex/quick/mips/codegen_mips.h @@ -74,7 +74,7 @@ class MipsMir2Lir : public Mir2Lir { void AssembleLIR(); int AssignInsnOffsets(); void AssignOffsets(); - AssemblerStatus AssembleInstructions(uintptr_t start_addr); + AssemblerStatus AssembleInstructions(CodeOffset start_addr); void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix); void SetupTargetResourceMasks(LIR* lir, uint64_t flags); const char* GetTargetInstFmt(int opcode); diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc index 5d9ae33921..2ba2c8487d 100644 --- a/compiler/dex/quick/mips/utility_mips.cc +++ b/compiler/dex/quick/mips/utility_mips.cc @@ -93,7 +93,7 @@ LIR* MipsMir2Lir::LoadConstantNoClobber(int r_dest, int value) { } else if ((value < 0) && (value >= -32768)) { res = NewLIR3(kMipsAddiu, r_dest, r_ZERO, value); } else { - res = NewLIR2(kMipsLui, r_dest, value>>16); + res = NewLIR2(kMipsLui, r_dest, value >> 16); if (value & 0xffff) NewLIR3(kMipsOri, r_dest, r_dest, value); } diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h index f293700bb9..1a30b7aef0 100644 --- a/compiler/dex/quick/mir_to_lir-inl.h +++ b/compiler/dex/quick/mir_to_lir-inl.h @@ -43,7 +43,7 @@ inline void Mir2Lir::ClobberBody(RegisterInfo* p) { } } -inline LIR* Mir2Lir::RawLIR(int dalvik_offset, int opcode, int op0, +inline LIR* Mir2Lir::RawLIR(DexOffset dalvik_offset, int opcode, int op0, int op1, int op2, int op3, int op4, LIR* target) { LIR* insn = static_cast(arena_->Alloc(sizeof(LIR), ArenaAllocator::kAllocLIR)); insn->dalvik_offset = dalvik_offset; diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc index 2b26c3de80..197e200fc3 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -241,9 +241,9 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list case Instruction::GOTO_16: case Instruction::GOTO_32: if (mir_graph_->IsBackedge(bb, bb->taken)) { - GenSuspendTestAndBranch(opt_flags, &label_list[bb->taken->id]); + GenSuspendTestAndBranch(opt_flags, &label_list[bb->taken]); } else { - OpUnconditionalBranch(&label_list[bb->taken->id]); + OpUnconditionalBranch(&label_list[bb->taken]); } break; @@ -272,23 +272,22 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list case Instruction::IF_GE: case Instruction::IF_GT: case Instruction::IF_LE: { - LIR* taken = &label_list[bb->taken->id]; - LIR* fall_through = &label_list[bb->fall_through->id]; + LIR* taken = &label_list[bb->taken]; + LIR* fall_through = &label_list[bb->fall_through]; // Result known at compile time? if (rl_src[0].is_const && rl_src[1].is_const) { bool is_taken = EvaluateBranch(opcode, mir_graph_->ConstantValue(rl_src[0].orig_sreg), mir_graph_->ConstantValue(rl_src[1].orig_sreg)); - BasicBlock* target = is_taken ? bb->taken : bb->fall_through; - if (mir_graph_->IsBackedge(bb, target)) { + BasicBlockId target_id = is_taken ? bb->taken : bb->fall_through; + if (mir_graph_->IsBackedge(bb, target_id)) { GenSuspendTest(opt_flags); } - OpUnconditionalBranch(&label_list[target->id]); + OpUnconditionalBranch(&label_list[target_id]); } else { if (mir_graph_->IsBackwardsBranch(bb)) { GenSuspendTest(opt_flags); } - GenCompareAndBranch(opcode, rl_src[0], rl_src[1], taken, - fall_through); + GenCompareAndBranch(opcode, rl_src[0], rl_src[1], taken, fall_through); } break; } @@ -299,16 +298,16 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list case Instruction::IF_GEZ: case Instruction::IF_GTZ: case Instruction::IF_LEZ: { - LIR* taken = &label_list[bb->taken->id]; - LIR* fall_through = &label_list[bb->fall_through->id]; + LIR* taken = &label_list[bb->taken]; + LIR* fall_through = &label_list[bb->fall_through]; // Result known at compile time? if (rl_src[0].is_const) { bool is_taken = EvaluateBranch(opcode, mir_graph_->ConstantValue(rl_src[0].orig_sreg), 0); - BasicBlock* target = is_taken ? bb->taken : bb->fall_through; - if (mir_graph_->IsBackedge(bb, target)) { + BasicBlockId target_id = is_taken ? bb->taken : bb->fall_through; + if (mir_graph_->IsBackedge(bb, target_id)) { GenSuspendTest(opt_flags); } - OpUnconditionalBranch(&label_list[target->id]); + OpUnconditionalBranch(&label_list[target_id]); } else { if (mir_graph_->IsBackwardsBranch(bb)) { GenSuspendTest(opt_flags); @@ -831,8 +830,9 @@ void Mir2Lir::MethodMIR2LIR() { while (curr_bb != NULL) { MethodBlockCodeGen(curr_bb); // If the fall_through block is no longer laid out consecutively, drop in a branch. - if ((curr_bb->fall_through != NULL) && (curr_bb->fall_through != next_bb)) { - OpUnconditionalBranch(&block_label_list_[curr_bb->fall_through->id]); + BasicBlock* curr_bb_fall_through = mir_graph_->GetBasicBlock(curr_bb->fall_through); + if ((curr_bb_fall_through != NULL) && (curr_bb_fall_through != next_bb)) { + OpUnconditionalBranch(&block_label_list_[curr_bb->fall_through]); } curr_bb = next_bb; do { diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 5df2672fe2..d629b44ddb 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -30,6 +30,14 @@ namespace art { +/* + * TODO: refactoring pass to move these (and other) typdefs towards usage style of runtime to + * add type safety (see runtime/offsets.h). + */ +typedef uint32_t DexOffset; // Dex offset in code units. +typedef uint16_t NarrowDexOffset; // For use in structs, Dex offsets range from 0 .. 0xffff. +typedef uint32_t CodeOffset; // Native code offset in bytes. + // Set to 1 to measure cost of suspend check. #define NO_SUSPEND 0 @@ -119,8 +127,8 @@ struct AssemblyInfo { }; struct LIR { - int offset; // Offset of this instruction. - uint16_t dalvik_offset; // Offset of Dalvik opcode in code units (16-bit words). + CodeOffset offset; // Offset of this instruction. + NarrowDexOffset dalvik_offset; // Offset of Dalvik opcode in code units (16-bit words). int16_t opcode; LIR* next; LIR* prev; @@ -134,10 +142,10 @@ struct LIR { unsigned int fixup:8; // Fixup kind. } flags; union { - UseDefMasks m; // Use & Def masks used during optimization. - AssemblyInfo a; // Instruction encoding used during assembly phase. + UseDefMasks m; // Use & Def masks used during optimization. + AssemblyInfo a; // Instruction encoding used during assembly phase. } u; - int operands[5]; // [0..4] = [dest, src1, src2, extra, extra2]. + int32_t operands[5]; // [0..4] = [dest, src1, src2, extra, extra2]. }; // Target-specific initialization. @@ -184,19 +192,23 @@ Mir2Lir* X86CodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, class Mir2Lir : public Backend { public: - struct SwitchTable { - int offset; - const uint16_t* table; // Original dex table. - int vaddr; // Dalvik offset of switch opcode. - LIR* anchor; // Reference instruction for relative offsets. - LIR** targets; // Array of case targets. + /* + * Auxiliary information describing the location of data embedded in the Dalvik + * byte code stream. + */ + struct EmbeddedData { + CodeOffset offset; // Code offset of data block. + const uint16_t* table; // Original dex data. + DexOffset vaddr; // Dalvik offset of parent opcode. }; - struct FillArrayData { - int offset; - const uint16_t* table; // Original dex table. - int size; - int vaddr; // Dalvik offset of FILL_ARRAY_DATA opcode. + struct FillArrayData : EmbeddedData { + int32_t size; + }; + + struct SwitchTable : EmbeddedData { + LIR* anchor; // Reference instruction for relative offsets. + LIR** targets; // Array of case targets. }; /* Static register use counts */ @@ -260,6 +272,34 @@ class Mir2Lir : public Backend { return (opcode < 0); } + /* + * LIR operands are 32-bit integers. Sometimes, (especially for managing + * instructions which require PC-relative fixups), we need the operands to carry + * pointers. To do this, we assign these pointers an index in pointer_storage_, and + * hold that index in the operand array. + * TUNING: If use of these utilities becomes more common on 32-bit builds, it + * may be worth conditionally-compiling a set of identity functions here. + */ + uint32_t WrapPointer(void* pointer) { + uint32_t res = pointer_storage_.Size(); + pointer_storage_.Insert(pointer); + return res; + } + + void* UnwrapPointer(size_t index) { + return pointer_storage_.Get(index); + } + + // strdup(), but allocates from the arena. + char* ArenaStrdup(const char* str) { + size_t len = strlen(str) + 1; + char* res = reinterpret_cast(arena_->Alloc(len, ArenaAllocator::kAllocMisc)); + if (res != NULL) { + strncpy(res, str, len); + } + return res; + } + // Shared by all targets - implemented in codegen_util.cc void AppendLIR(LIR* lir); void InsertLIRBefore(LIR* current_lir, LIR* new_lir); @@ -277,7 +317,7 @@ class Mir2Lir : public Backend { void DumpLIRInsn(LIR* arg, unsigned char* base_addr); void DumpPromotionMap(); void CodegenDump(); - LIR* RawLIR(int dalvik_offset, int opcode, int op0 = 0, int op1 = 0, + LIR* RawLIR(DexOffset dalvik_offset, int opcode, int op0 = 0, int op1 = 0, int op2 = 0, int op3 = 0, int op4 = 0, LIR* target = NULL); LIR* NewLIR0(int opcode); LIR* NewLIR1(int opcode, int dest); @@ -292,7 +332,7 @@ class Mir2Lir : public Backend { void ProcessSwitchTables(); void DumpSparseSwitchTable(const uint16_t* table); void DumpPackedSwitchTable(const uint16_t* table); - void MarkBoundary(int offset, const char* inst_str); + void MarkBoundary(DexOffset offset, const char* inst_str); void NopLIR(LIR* lir); void UnlinkLIR(LIR* lir); bool EvaluateBranch(Instruction::Code opcode, int src1, int src2); @@ -307,12 +347,12 @@ class Mir2Lir : public Backend { bool VerifyCatchEntries(); void CreateMappingTables(); void CreateNativeGcMap(); - int AssignLiteralOffset(int offset); - int AssignSwitchTablesOffset(int offset); - int AssignFillArrayDataOffset(int offset); - LIR* InsertCaseLabel(int vaddr, int keyVal); - void MarkPackedCaseLabels(Mir2Lir::SwitchTable *tab_rec); - void MarkSparseCaseLabels(Mir2Lir::SwitchTable *tab_rec); + int AssignLiteralOffset(CodeOffset offset); + int AssignSwitchTablesOffset(CodeOffset offset); + int AssignFillArrayDataOffset(CodeOffset offset); + LIR* InsertCaseLabel(DexOffset vaddr, int keyVal); + void MarkPackedCaseLabels(Mir2Lir::SwitchTable* tab_rec); + void MarkSparseCaseLabels(Mir2Lir::SwitchTable* tab_rec); // Shared by all targets - implemented in local_optimizations.cc void ConvertMemOpIntoMove(LIR* orig_lir, int dest, int src); @@ -642,7 +682,7 @@ class Mir2Lir : public Backend { virtual void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) = 0; virtual void GenExitSequence() = 0; - virtual void GenFillArrayData(uint32_t table_offset, + virtual void GenFillArrayData(DexOffset table_offset, RegLocation rl_src) = 0; virtual void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double) = 0; @@ -655,9 +695,9 @@ class Mir2Lir : public Backend { int second_bit) = 0; virtual void GenNegDouble(RegLocation rl_dest, RegLocation rl_src) = 0; virtual void GenNegFloat(RegLocation rl_dest, RegLocation rl_src) = 0; - virtual void GenPackedSwitch(MIR* mir, uint32_t table_offset, + virtual void GenPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) = 0; - virtual void GenSparseSwitch(MIR* mir, uint32_t table_offset, + virtual void GenSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) = 0; virtual void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case) = 0; @@ -672,13 +712,10 @@ class Mir2Lir : public Backend { // Required for target - single operation generators. virtual LIR* OpUnconditionalBranch(LIR* target) = 0; - virtual LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, - LIR* target) = 0; - virtual LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, - LIR* target) = 0; + virtual LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target) = 0; + virtual LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target) = 0; virtual LIR* OpCondBranch(ConditionCode cc, LIR* target) = 0; - virtual LIR* OpDecAndBranch(ConditionCode c_code, int reg, - LIR* target) = 0; + virtual LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target) = 0; virtual LIR* OpFpRegCopy(int r_dest, int r_src) = 0; virtual LIR* OpIT(ConditionCode cond, const char* guide) = 0; virtual LIR* OpMem(OpKind op, int rBase, int disp) = 0; @@ -690,16 +727,13 @@ class Mir2Lir : public Backend { virtual LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset) = 0; virtual LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2) = 0; virtual LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value) = 0; - virtual LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, - int r_src2) = 0; + virtual LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2) = 0; virtual LIR* OpTestSuspend(LIR* target) = 0; virtual LIR* OpThreadMem(OpKind op, ThreadOffset thread_offset) = 0; virtual LIR* OpVldm(int rBase, int count) = 0; virtual LIR* OpVstm(int rBase, int count) = 0; - virtual void OpLea(int rBase, int reg1, int reg2, int scale, - int offset) = 0; - virtual void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, - int src_hi) = 0; + virtual void OpLea(int rBase, int reg1, int reg2, int scale, int offset) = 0; + virtual void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi) = 0; virtual void OpTlsCmp(ThreadOffset offset, int val) = 0; virtual bool InexpensiveConstantInt(int32_t value) = 0; virtual bool InexpensiveConstantFloat(int32_t value) = 0; @@ -752,6 +786,7 @@ class Mir2Lir : public Backend { GrowableArray intrinsic_launchpads_; GrowableArray tempreg_info_; GrowableArray reginfo_map_; + GrowableArray pointer_storage_; /* * Holds mapping from native PC to dex PC for safepoints where we may deoptimize. * Native PC is on the return address of the safepointed operation. Dex PC is for @@ -763,9 +798,9 @@ class Mir2Lir : public Backend { * immediately preceed the instruction. */ std::vector dex2pc_mapping_table_; - int current_code_offset_; // Working byte offset of machine instructons. - int data_offset_; // starting offset of literal pool. - int total_size_; // header + code size. + CodeOffset current_code_offset_; // Working byte offset of machine instructons. + CodeOffset data_offset_; // starting offset of literal pool. + size_t total_size_; // header + code size. LIR* block_label_list_; PromotionMap* promotion_map_; /* @@ -777,8 +812,8 @@ class Mir2Lir : public Backend { * in the CompilationUnit struct before codegen for each instruction. * The low-level LIR creation utilites will pull it from here. Rework this. */ - int current_dalvik_offset_; - int estimated_native_code_size_; // Just an estimate; used to reserve code_buffer_ size. + DexOffset current_dalvik_offset_; + size_t estimated_native_code_size_; // Just an estimate; used to reserve code_buffer_ size. RegisterPool* reg_pool_; /* * Sanity checking for the register temp tracking. The same ssa diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc index 7927ff9864..41a57afca1 100644 --- a/compiler/dex/quick/ralloc_util.cc +++ b/compiler/dex/quick/ralloc_util.cc @@ -66,10 +66,9 @@ void Mir2Lir::DumpRegPool(RegisterInfo* p, int num_regs) { LOG(INFO) << "================================================"; for (int i = 0; i < num_regs; i++) { LOG(INFO) << StringPrintf( - "R[%d]: T:%d, U:%d, P:%d, p:%d, LV:%d, D:%d, SR:%d, ST:%x, EN:%x", + "R[%d]: T:%d, U:%d, P:%d, p:%d, LV:%d, D:%d, SR:%d", p[i].reg, p[i].is_temp, p[i].in_use, p[i].pair, p[i].partner, - p[i].live, p[i].dirty, p[i].s_reg, reinterpret_cast(p[i].def_start), - reinterpret_cast(p[i].def_end)); + p[i].live, p[i].dirty, p[i].s_reg); } LOG(INFO) << "================================================"; } @@ -769,9 +768,9 @@ RegLocation Mir2Lir::UpdateRawLoc(RegLocation loc) { RegLocation Mir2Lir::EvalLocWide(RegLocation loc, int reg_class, bool update) { DCHECK(loc.wide); - int new_regs; - int low_reg; - int high_reg; + int32_t new_regs; + int32_t low_reg; + int32_t high_reg; loc = UpdateLocWide(loc); diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc index 064ff31bcd..fb8e75fc1b 100644 --- a/compiler/dex/quick/x86/assemble_x86.cc +++ b/compiler/dex/quick/x86/assemble_x86.cc @@ -1090,11 +1090,13 @@ void X86Mir2Lir::EmitPcRel(const X86EncodingMap* entry, uint8_t reg, int base_or_table, uint8_t index, int scale, int table_or_disp) { int disp; if (entry->opcode == kX86PcRelLoadRA) { - Mir2Lir::SwitchTable *tab_rec = reinterpret_cast(table_or_disp); + Mir2Lir::EmbeddedData *tab_rec = + reinterpret_cast(UnwrapPointer(table_or_disp)); disp = tab_rec->offset; } else { DCHECK(entry->opcode == kX86PcRelAdr); - Mir2Lir::FillArrayData *tab_rec = reinterpret_cast(base_or_table); + Mir2Lir::EmbeddedData *tab_rec = + reinterpret_cast(UnwrapPointer(base_or_table)); disp = tab_rec->offset; } if (entry->skeleton.prefix1 != 0) { @@ -1161,7 +1163,7 @@ void X86Mir2Lir::EmitUnimplemented(const X86EncodingMap* entry, LIR* lir) { * instruction. In those cases we will try to substitute a new code * sequence or request that the trace be shortened and retried. */ -AssemblerStatus X86Mir2Lir::AssembleInstructions(uintptr_t start_addr) { +AssemblerStatus X86Mir2Lir::AssembleInstructions(CodeOffset start_addr) { LIR *lir; AssemblerStatus res = kSuccess; // Assume success @@ -1181,13 +1183,13 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(uintptr_t start_addr) { LIR *target_lir = lir->target; DCHECK(target_lir != NULL); int delta = 0; - uintptr_t pc; + CodeOffset pc; if (IS_SIMM8(lir->operands[0])) { pc = lir->offset + 2 /* opcode + rel8 */; } else { pc = lir->offset + 6 /* 2 byte opcode + rel32 */; } - uintptr_t target = target_lir->offset; + CodeOffset target = target_lir->offset; delta = target - pc; if (IS_SIMM8(delta) != IS_SIMM8(lir->operands[0])) { if (kVerbosePcFixup) { @@ -1211,8 +1213,8 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(uintptr_t start_addr) { case kX86Jcc32: { LIR *target_lir = lir->target; DCHECK(target_lir != NULL); - uintptr_t pc = lir->offset + 6 /* 2 byte opcode + rel32 */; - uintptr_t target = target_lir->offset; + CodeOffset pc = lir->offset + 6 /* 2 byte opcode + rel32 */; + CodeOffset target = target_lir->offset; int delta = target - pc; if (kVerbosePcFixup) { LOG(INFO) << "Source:"; @@ -1228,13 +1230,13 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(uintptr_t start_addr) { LIR *target_lir = lir->target; DCHECK(target_lir != NULL); int delta = 0; - uintptr_t pc; + CodeOffset pc; if (IS_SIMM8(lir->operands[0])) { pc = lir->offset + 2 /* opcode + rel8 */; } else { pc = lir->offset + 5 /* opcode + rel32 */; } - uintptr_t target = target_lir->offset; + CodeOffset target = target_lir->offset; delta = target - pc; if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && delta == 0) { // Useless branch @@ -1257,8 +1259,8 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(uintptr_t start_addr) { case kX86Jmp32: { LIR *target_lir = lir->target; DCHECK(target_lir != NULL); - uintptr_t pc = lir->offset + 5 /* opcode + rel32 */; - uintptr_t target = target_lir->offset; + CodeOffset pc = lir->offset + 5 /* opcode + rel32 */; + CodeOffset target = target_lir->offset; int delta = target - pc; lir->operands[0] = delta; break; diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc index 7fad6f07d1..17924b0f08 100644 --- a/compiler/dex/quick/x86/call_x86.cc +++ b/compiler/dex/quick/x86/call_x86.cc @@ -31,15 +31,15 @@ void X86Mir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir, * The sparse table in the literal pool is an array of * pairs. */ -void X86Mir2Lir::GenSparseSwitch(MIR* mir, uint32_t table_offset, +void X86Mir2Lir::GenSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) { const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset; if (cu_->verbose) { DumpSparseSwitchTable(table); } int entries = table[1]; - const int* keys = reinterpret_cast(&table[2]); - const int* targets = &keys[entries]; + const int32_t* keys = reinterpret_cast(&table[2]); + const int32_t* targets = &keys[entries]; rl_src = LoadValue(rl_src, kCoreReg); for (int i = 0; i < entries; i++) { int key = keys[i]; @@ -66,15 +66,15 @@ void X86Mir2Lir::GenSparseSwitch(MIR* mir, uint32_t table_offset, * jmp r_start_of_method * done: */ -void X86Mir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset, +void X86Mir2Lir::GenPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) { const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset; if (cu_->verbose) { DumpPackedSwitchTable(table); } // Add the table to the list - we'll process it later - SwitchTable *tab_rec = - static_cast(arena_->Alloc(sizeof(SwitchTable), ArenaAllocator::kAllocData)); + SwitchTable* tab_rec = + static_cast(arena_->Alloc(sizeof(SwitchTable), ArenaAllocator::kAllocData)); tab_rec->table = table; tab_rec->vaddr = current_dalvik_offset_; int size = table[1]; @@ -103,8 +103,7 @@ void X86Mir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset, // Load the displacement from the switch table int disp_reg = AllocTemp(); - NewLIR5(kX86PcRelLoadRA, disp_reg, start_of_method_reg, keyReg, 2, - reinterpret_cast(tab_rec)); + NewLIR5(kX86PcRelLoadRA, disp_reg, start_of_method_reg, keyReg, 2, WrapPointer(tab_rec)); // Add displacement to start of method OpRegReg(kOpAdd, start_of_method_reg, disp_reg); // ..and go! @@ -126,10 +125,10 @@ void X86Mir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset, * * Total size is 4+(width * size + 1)/2 16-bit code units. */ -void X86Mir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { +void X86Mir2Lir::GenFillArrayData(DexOffset table_offset, RegLocation rl_src) { const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset; // Add the table to the list - we'll process it later - FillArrayData *tab_rec = + FillArrayData* tab_rec = static_cast(arena_->Alloc(sizeof(FillArrayData), ArenaAllocator::kAllocData)); tab_rec->table = table; tab_rec->vaddr = current_dalvik_offset_; @@ -144,7 +143,7 @@ void X86Mir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { LoadValueDirectFixed(rl_src, rX86_ARG0); // Materialize a pointer to the fill data image NewLIR1(kX86StartOfMethod, rX86_ARG2); - NewLIR2(kX86PcRelAdr, rX86_ARG1, reinterpret_cast(tab_rec)); + NewLIR2(kX86PcRelAdr, rX86_ARG1, WrapPointer(tab_rec)); NewLIR2(kX86Add32RR, rX86_ARG1, rX86_ARG2); CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pHandleFillArrayData), rX86_ARG0, rX86_ARG1, true); diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index c266e39bbe..b1d95ffcdf 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -74,7 +74,7 @@ class X86Mir2Lir : public Mir2Lir { void AssembleLIR(); int AssignInsnOffsets(); void AssignOffsets(); - AssemblerStatus AssembleInstructions(uintptr_t start_addr); + AssemblerStatus AssembleInstructions(CodeOffset start_addr); void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix); void SetupTargetResourceMasks(LIR* lir, uint64_t flags); const char* GetTargetInstFmt(int opcode); @@ -119,7 +119,7 @@ class X86Mir2Lir : public Mir2Lir { void GenDivZeroCheck(int reg_lo, int reg_hi); void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method); void GenExitSequence(); - void GenFillArrayData(uint32_t table_offset, RegLocation rl_src); + void GenFillArrayData(DexOffset table_offset, RegLocation rl_src); void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double); void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir); void GenSelect(BasicBlock* bb, MIR* mir); @@ -129,8 +129,8 @@ class X86Mir2Lir : public Mir2Lir { int lit, int first_bit, int second_bit); void GenNegDouble(RegLocation rl_dest, RegLocation rl_src); void GenNegFloat(RegLocation rl_dest, RegLocation rl_src); - void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src); - void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src); + void GenPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src); + void GenSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src); void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case); // Single operation generators. diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc index f736b5e28f..c9d6bfc8cc 100644 --- a/compiler/dex/quick/x86/fp_x86.cc +++ b/compiler/dex/quick/x86/fp_x86.cc @@ -284,8 +284,8 @@ void X86Mir2Lir::GenCmpFP(Instruction::Code code, RegLocation rl_dest, void X86Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double) { - LIR* taken = &block_label_list_[bb->taken->id]; - LIR* not_taken = &block_label_list_[bb->fall_through->id]; + LIR* taken = &block_label_list_[bb->taken]; + LIR* not_taken = &block_label_list_[bb->fall_through]; LIR* branch = NULL; RegLocation rl_src1; RegLocation rl_src2; diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc index 14f5348c12..324d975fc8 100644 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -166,7 +166,7 @@ void X86Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { } void X86Mir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) { - LIR* taken = &block_label_list_[bb->taken->id]; + LIR* taken = &block_label_list_[bb->taken]; RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0); RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2); FlushAllRegs(); diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index 0f005dab26..901ac9e69d 100644 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -223,7 +223,7 @@ std::string X86Mir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char buf += StringPrintf("%d", operand); break; case 'p': { - SwitchTable *tab_rec = reinterpret_cast(operand); + EmbeddedData *tab_rec = reinterpret_cast(UnwrapPointer(operand)); buf += StringPrintf("0x%08x", tab_rec->offset); break; } @@ -238,7 +238,7 @@ std::string X86Mir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char break; case 't': buf += StringPrintf("0x%08x (L%p)", - reinterpret_cast(base_addr) + reinterpret_cast(base_addr) + lir->offset + operand, lir->target); break; default: diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc index 0ca5fd4aa3..eb0d412bae 100644 --- a/compiler/dex/ssa_transformation.cc +++ b/compiler/dex/ssa_transformation.cc @@ -38,18 +38,18 @@ BasicBlock* MIRGraph::NeedsVisit(BasicBlock* bb) { } BasicBlock* MIRGraph::NextUnvisitedSuccessor(BasicBlock* bb) { - BasicBlock* res = NeedsVisit(bb->fall_through); + BasicBlock* res = NeedsVisit(GetBasicBlock(bb->fall_through)); if (res == NULL) { - res = NeedsVisit(bb->taken); + res = NeedsVisit(GetBasicBlock(bb->taken)); if (res == NULL) { - if (bb->successor_block_list.block_list_type != kNotUsed) { - GrowableArray::Iterator iterator(bb->successor_block_list.blocks); + if (bb->successor_block_list_type != kNotUsed) { + GrowableArray::Iterator iterator(bb->successor_blocks); while (true) { SuccessorBlockInfo *sbi = iterator.Next(); if (sbi == NULL) { break; } - res = NeedsVisit(sbi->block); + res = NeedsVisit(GetBasicBlock(sbi->block)); if (res != NULL) { break; } @@ -63,7 +63,9 @@ BasicBlock* MIRGraph::NextUnvisitedSuccessor(BasicBlock* bb) { void MIRGraph::MarkPreOrder(BasicBlock* block) { block->visited = true; /* Enqueue the pre_order block id */ - dfs_order_->Insert(block->id); + if (block->id != NullBasicBlockId) { + dfs_order_->Insert(block->id); + } } void MIRGraph::RecordDFSOrders(BasicBlock* block) { @@ -79,7 +81,9 @@ void MIRGraph::RecordDFSOrders(BasicBlock* block) { continue; } curr->dfs_id = dfs_post_order_->Size(); - dfs_post_order_->Insert(curr->id); + if (curr->id != NullBasicBlockId) { + dfs_post_order_->Insert(curr->id); + } succ.pop_back(); } } @@ -88,7 +92,8 @@ void MIRGraph::RecordDFSOrders(BasicBlock* block) { void MIRGraph::ComputeDFSOrders() { /* Initialize or reset the DFS pre_order list */ if (dfs_order_ == NULL) { - dfs_order_ = new (arena_) GrowableArray(arena_, GetNumBlocks(), kGrowableArrayDfsOrder); + dfs_order_ = new (arena_) GrowableArray(arena_, GetNumBlocks(), + kGrowableArrayDfsOrder); } else { /* Just reset the used length on the counter */ dfs_order_->Reset(); @@ -96,7 +101,8 @@ void MIRGraph::ComputeDFSOrders() { /* Initialize or reset the DFS post_order list */ if (dfs_post_order_ == NULL) { - dfs_post_order_ = new (arena_) GrowableArray(arena_, GetNumBlocks(), kGrowableArrayDfsPostOrder); + dfs_post_order_ = new (arena_) GrowableArray(arena_, GetNumBlocks(), + kGrowableArrayDfsPostOrder); } else { /* Just reset the used length on the counter */ dfs_post_order_->Reset(); @@ -169,7 +175,7 @@ void MIRGraph::ComputeDomPostOrderTraversal(BasicBlock* bb) { if (dom_post_order_traversal_ == NULL) { // First time - create the array. dom_post_order_traversal_ = - new (arena_) GrowableArray(arena_, num_reachable_blocks_, + new (arena_) GrowableArray(arena_, num_reachable_blocks_, kGrowableArrayDomPostOrderTraversal); } else { dom_post_order_traversal_->Reset(); @@ -193,11 +199,13 @@ void MIRGraph::ComputeDomPostOrderTraversal(BasicBlock* bb) { std::make_pair(new_bb, new (arena_) ArenaBitVector::Iterator(new_bb->i_dominated))); } else { // no successor/next - dom_post_order_traversal_->Insert(curr_bb->id); + if (curr_bb->id != NullBasicBlockId) { + dom_post_order_traversal_->Insert(curr_bb->id); + } work_stack.pop_back(); /* hacky loop detection */ - if (curr_bb->taken && curr_bb->dominators->IsBitSet(curr_bb->taken->id)) { + if ((curr_bb->taken != NullBasicBlockId) && curr_bb->dominators->IsBitSet(curr_bb->taken)) { attributes_ |= METHOD_HAS_LOOP; } } @@ -210,7 +218,7 @@ void MIRGraph::CheckForDominanceFrontier(BasicBlock* dom_bb, * TODO - evaluate whether phi will ever need to be inserted into exit * blocks. */ - if (succ_bb->i_dom != dom_bb && + if (succ_bb->i_dom != dom_bb->id && succ_bb->block_type == kDalvikByteCode && succ_bb->hidden == false) { dom_bb->dom_frontier->SetBit(succ_bb->id); @@ -220,20 +228,20 @@ void MIRGraph::CheckForDominanceFrontier(BasicBlock* dom_bb, /* Worker function to compute the dominance frontier */ bool MIRGraph::ComputeDominanceFrontier(BasicBlock* bb) { /* Calculate DF_local */ - if (bb->taken) { - CheckForDominanceFrontier(bb, bb->taken); + if (bb->taken != NullBasicBlockId) { + CheckForDominanceFrontier(bb, GetBasicBlock(bb->taken)); } - if (bb->fall_through) { - CheckForDominanceFrontier(bb, bb->fall_through); + if (bb->fall_through != NullBasicBlockId) { + CheckForDominanceFrontier(bb, GetBasicBlock(bb->fall_through)); } - if (bb->successor_block_list.block_list_type != kNotUsed) { - GrowableArray::Iterator iterator(bb->successor_block_list.blocks); + if (bb->successor_block_list_type != kNotUsed) { + GrowableArray::Iterator iterator(bb->successor_blocks); while (true) { SuccessorBlockInfo *successor_block_info = iterator.Next(); if (successor_block_info == NULL) { break; } - BasicBlock* succ_bb = successor_block_info->block; + BasicBlock* succ_bb = GetBasicBlock(successor_block_info->block); CheckForDominanceFrontier(bb, succ_bb); } } @@ -306,17 +314,17 @@ int MIRGraph::FindCommonParent(int block1, int block2) { /* Worker function to compute each block's immediate dominator */ bool MIRGraph::ComputeblockIDom(BasicBlock* bb) { /* Special-case entry block */ - if (bb == GetEntryBlock()) { + if ((bb->id == NullBasicBlockId) || (bb == GetEntryBlock())) { return false; } /* Iterate through the predecessors */ - GrowableArray::Iterator iter(bb->predecessors); + GrowableArray::Iterator iter(bb->predecessors); /* Find the first processed predecessor */ int idom = -1; while (true) { - BasicBlock* pred_bb = iter.Next(); + BasicBlock* pred_bb = GetBasicBlock(iter.Next()); CHECK(pred_bb != NULL); if (i_dom_list_[pred_bb->dfs_id] != NOTVISITED) { idom = pred_bb->dfs_id; @@ -326,7 +334,7 @@ bool MIRGraph::ComputeblockIDom(BasicBlock* bb) { /* Scan the rest of the predecessors */ while (true) { - BasicBlock* pred_bb = iter.Next(); + BasicBlock* pred_bb = GetBasicBlock(iter.Next()); if (!pred_bb) { break; } @@ -352,7 +360,7 @@ bool MIRGraph::ComputeBlockDominators(BasicBlock* bb) { if (bb == GetEntryBlock()) { bb->dominators->ClearAllBits(); } else { - bb->dominators->Copy(bb->i_dom->dominators); + bb->dominators->Copy(GetBasicBlock(bb->i_dom)->dominators); } bb->dominators->SetBit(bb->id); return false; @@ -364,7 +372,7 @@ bool MIRGraph::SetDominators(BasicBlock* bb) { DCHECK_NE(idom_dfs_idx, NOTVISITED); int i_dom_idx = dfs_post_order_->Get(idom_dfs_idx); BasicBlock* i_dom = GetBasicBlock(i_dom_idx); - bb->i_dom = i_dom; + bb->i_dom = i_dom->id; /* Add bb to the i_dominated set of the immediate dominator block */ i_dom->i_dominated->SetBit(bb->id); } @@ -412,7 +420,7 @@ void MIRGraph::ComputeDominators() { } else { temp_block_v_->ClearAllBits(); } - GetEntryBlock()->i_dom = NULL; + GetEntryBlock()->i_dom = 0; PreOrderDfsIterator iter3(this); for (BasicBlock* bb = iter3.Next(); bb != NULL; bb = iter3.Next()) { @@ -463,20 +471,22 @@ bool MIRGraph::ComputeBlockLiveIns(BasicBlock* bb) { return false; } temp_dalvik_register_v->Copy(bb->data_flow_info->live_in_v); - if (bb->taken && bb->taken->data_flow_info) - ComputeSuccLineIn(temp_dalvik_register_v, bb->taken->data_flow_info->live_in_v, + BasicBlock* bb_taken = GetBasicBlock(bb->taken); + BasicBlock* bb_fall_through = GetBasicBlock(bb->fall_through); + if (bb_taken && bb_taken->data_flow_info) + ComputeSuccLineIn(temp_dalvik_register_v, bb_taken->data_flow_info->live_in_v, bb->data_flow_info->def_v); - if (bb->fall_through && bb->fall_through->data_flow_info) - ComputeSuccLineIn(temp_dalvik_register_v, bb->fall_through->data_flow_info->live_in_v, + if (bb_fall_through && bb_fall_through->data_flow_info) + ComputeSuccLineIn(temp_dalvik_register_v, bb_fall_through->data_flow_info->live_in_v, bb->data_flow_info->def_v); - if (bb->successor_block_list.block_list_type != kNotUsed) { - GrowableArray::Iterator iterator(bb->successor_block_list.blocks); + if (bb->successor_block_list_type != kNotUsed) { + GrowableArray::Iterator iterator(bb->successor_blocks); while (true) { SuccessorBlockInfo *successor_block_info = iterator.Next(); if (successor_block_info == NULL) { break; } - BasicBlock* succ_bb = successor_block_info->block; + BasicBlock* succ_bb = GetBasicBlock(successor_block_info->block); if (succ_bb->data_flow_info) { ComputeSuccLineIn(temp_dalvik_register_v, succ_bb->data_flow_info->live_in_v, bb->data_flow_info->def_v); @@ -579,50 +589,37 @@ void MIRGraph::InsertPhiNodes() { * predecessor blocks */ bool MIRGraph::InsertPhiNodeOperands(BasicBlock* bb) { - MIR *mir; - std::vector uses; - std::vector incoming_arc; - /* Phi nodes are at the beginning of each block */ - for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { + for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { if (mir->dalvikInsn.opcode != static_cast(kMirOpPhi)) return true; int ssa_reg = mir->ssa_rep->defs[0]; DCHECK_GE(ssa_reg, 0); // Shouldn't see compiler temps here int v_reg = SRegToVReg(ssa_reg); - uses.clear(); - incoming_arc.clear(); - /* Iterate through the predecessors */ - GrowableArray::Iterator iter(bb->predecessors); + GrowableArray::Iterator iter(bb->predecessors); + size_t num_uses = bb->predecessors->Size(); + mir->ssa_rep->num_uses = num_uses; + int* uses = static_cast(arena_->Alloc(sizeof(int) * num_uses, + ArenaAllocator::kAllocDFInfo)); + mir->ssa_rep->uses = uses; + mir->ssa_rep->fp_use = + static_cast(arena_->Alloc(sizeof(bool) * num_uses, ArenaAllocator::kAllocDFInfo)); + BasicBlockId* incoming = + static_cast(arena_->Alloc(sizeof(BasicBlockId) * num_uses, + ArenaAllocator::kAllocDFInfo)); + mir->meta.phi_incoming = incoming; + int idx = 0; while (true) { - BasicBlock* pred_bb = iter.Next(); + BasicBlock* pred_bb = GetBasicBlock(iter.Next()); if (!pred_bb) { break; } int ssa_reg = pred_bb->data_flow_info->vreg_to_ssa_map[v_reg]; - uses.push_back(ssa_reg); - incoming_arc.push_back(pred_bb->id); - } - - /* Count the number of SSA registers for a Dalvik register */ - int num_uses = uses.size(); - mir->ssa_rep->num_uses = num_uses; - mir->ssa_rep->uses = - static_cast(arena_->Alloc(sizeof(int) * num_uses, ArenaAllocator::kAllocDFInfo)); - mir->ssa_rep->fp_use = - static_cast(arena_->Alloc(sizeof(bool) * num_uses, ArenaAllocator::kAllocDFInfo)); - int* incoming = - static_cast(arena_->Alloc(sizeof(int) * num_uses, ArenaAllocator::kAllocDFInfo)); - // TODO: Ugly, rework (but don't burden each MIR/LIR for Phi-only needs) - mir->dalvikInsn.vB = reinterpret_cast(incoming); - - /* Set the uses array for the phi node */ - int *use_ptr = mir->ssa_rep->uses; - for (int i = 0; i < num_uses; i++) { - *use_ptr++ = uses[i]; - *incoming++ = incoming_arc[i]; + uses[idx] = ssa_reg; + incoming[idx] = pred_bb->id; + idx++; } } @@ -644,24 +641,24 @@ void MIRGraph::DoDFSPreOrderSSARename(BasicBlock* block) { static_cast(arena_->Alloc(map_size, ArenaAllocator::kAllocDalvikToSSAMap)); memcpy(saved_ssa_map, vreg_to_ssa_map_, map_size); - if (block->fall_through) { - DoDFSPreOrderSSARename(block->fall_through); + if (block->fall_through != NullBasicBlockId) { + DoDFSPreOrderSSARename(GetBasicBlock(block->fall_through)); /* Restore SSA map snapshot */ memcpy(vreg_to_ssa_map_, saved_ssa_map, map_size); } - if (block->taken) { - DoDFSPreOrderSSARename(block->taken); + if (block->taken != NullBasicBlockId) { + DoDFSPreOrderSSARename(GetBasicBlock(block->taken)); /* Restore SSA map snapshot */ memcpy(vreg_to_ssa_map_, saved_ssa_map, map_size); } - if (block->successor_block_list.block_list_type != kNotUsed) { - GrowableArray::Iterator iterator(block->successor_block_list.blocks); + if (block->successor_block_list_type != kNotUsed) { + GrowableArray::Iterator iterator(block->successor_blocks); while (true) { SuccessorBlockInfo *successor_block_info = iterator.Next(); if (successor_block_info == NULL) { break; } - BasicBlock* succ_bb = successor_block_info->block; + BasicBlock* succ_bb = GetBasicBlock(successor_block_info->block); DoDFSPreOrderSSARename(succ_bb); /* Restore SSA map snapshot */ memcpy(vreg_to_ssa_map_, saved_ssa_map, map_size); -- cgit v1.2.3-59-g8ed1b From 4db179d1821a9e78819d5adc8057a72f49e2aed8 Mon Sep 17 00:00:00 2001 From: buzbee Date: Wed, 23 Oct 2013 12:16:39 -0700 Subject: Null check elimination improvement See b/10862777 Improves the null check elimination pass by tracking visibility of object definitions, rather than successful uses of object dereferences. For boot class path, increases static null check elimination success rate from 98.4% to 98.6%. Reduces size of boot.oat by ~300K bytes. Fixes loop nesting depth computation, which is used by register promotion, and tweaked the heuristics. Fixes a bug in verbose listing output in which a basic block id is directly dereferenced, rather than first being converted to a pointer. Change-Id: Id01c20b533cdb12ea8fc4be576438407d0a34cec --- compiler/dex/mir_dataflow.cc | 3 +- compiler/dex/mir_optimization.cc | 86 +++++++++++++++++++++++--------------- compiler/dex/quick/codegen_util.cc | 3 +- compiler/dex/ssa_transformation.cc | 1 + 4 files changed, 58 insertions(+), 35 deletions(-) (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc index 9c8ce23ca5..11e19dc43f 100644 --- a/compiler/dex/mir_dataflow.cc +++ b/compiler/dex/mir_dataflow.cc @@ -1243,7 +1243,8 @@ bool MIRGraph::CountUses(struct BasicBlock* bb) { if (mir->ssa_rep == NULL) { continue; } - uint32_t weight = std::min(16U, static_cast(bb->nesting_depth)); + // Each level of nesting adds *16 to count, up to 3 levels deep. + uint32_t weight = std::min(3U, static_cast(bb->nesting_depth) * 4); for (int i = 0; i < mir->ssa_rep->num_uses; i++) { int s_reg = mir->ssa_rep->uses[i]; raw_use_counts_.Increment(s_reg); diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index 3cd158ffc0..0b453b142f 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -629,10 +629,15 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { */ if ((bb->block_type == kEntryBlock) | bb->catch_entry) { temp_ssa_register_v_->ClearAllBits(); + // Assume all ins are objects. + for (uint16_t in_reg = cu_->num_dalvik_registers - cu_->num_ins; + in_reg < cu_->num_dalvik_registers; in_reg++) { + temp_ssa_register_v_->SetBit(in_reg); + } if ((cu_->access_flags & kAccStatic) == 0) { // If non-static method, mark "this" as non-null int this_reg = cu_->num_dalvik_registers - cu_->num_ins; - temp_ssa_register_v_->SetBit(this_reg); + temp_ssa_register_v_->ClearBit(this_reg); } } else if (bb->predecessors->Size() == 1) { BasicBlock* pred_bb = GetBasicBlock(bb->predecessors->Get(0)); @@ -645,18 +650,18 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { if (pred_bb->fall_through == bb->id) { // The fall-through of a block following a IF_EQZ, set the vA of the IF_EQZ to show that // it can't be null. - temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]); + temp_ssa_register_v_->ClearBit(last_insn->ssa_rep->uses[0]); } } else if (last_opcode == Instruction::IF_NEZ) { if (pred_bb->taken == bb->id) { // The taken block following a IF_NEZ, set the vA of the IF_NEZ to show that it can't be // null. - temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]); + temp_ssa_register_v_->ClearBit(last_insn->ssa_rep->uses[0]); } } } } else { - // Starting state is intersection of all incoming arcs + // Starting state is union of all incoming arcs GrowableArray::Iterator iter(bb->predecessors); BasicBlock* pred_bb = GetBasicBlock(iter.Next()); DCHECK(pred_bb != NULL); @@ -668,10 +673,13 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { (pred_bb->data_flow_info->ending_null_check_v == NULL)) { continue; } - temp_ssa_register_v_->Intersect(pred_bb->data_flow_info->ending_null_check_v); + temp_ssa_register_v_->Union(pred_bb->data_flow_info->ending_null_check_v); } } + // At this point, temp_ssa_register_v_ shows which sregs have an object definition with + // no intervening uses. + // Walk through the instruction in the block, updating as necessary for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { if (mir->ssa_rep == NULL) { @@ -679,11 +687,41 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { } int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; - // Mark target of NEW* as non-null - if (df_attributes & DF_NON_NULL_DST) { + // Already nullchecked? + if ((df_attributes & DF_HAS_NULL_CHKS) && !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) { + int src_idx; + if (df_attributes & DF_NULL_CHK_1) { + src_idx = 1; + } else if (df_attributes & DF_NULL_CHK_2) { + src_idx = 2; + } else { + src_idx = 0; + } + int src_sreg = mir->ssa_rep->uses[src_idx]; + if (!temp_ssa_register_v_->IsBitSet(src_sreg)) { + // Eliminate the null check + mir->optimization_flags |= MIR_IGNORE_NULL_CHECK; + } else { + // Mark s_reg as null-checked + temp_ssa_register_v_->ClearBit(src_sreg); + } + } + + if ((df_attributes & (DF_REF_A | DF_NULL_TRANSFER_0 | DF_NULL_TRANSFER_N)) == 0) { + continue; + } + + // First, mark all object definitions as requiring null check. + if ((df_attributes & (DF_DA | DF_REF_A)) == (DF_DA | DF_REF_A)) { temp_ssa_register_v_->SetBit(mir->ssa_rep->defs[0]); } + // Now, remove mark from all object definitions we know are non-null. + if (df_attributes & DF_NON_NULL_DST) { + // Mark target of NEW* as non-null + temp_ssa_register_v_->ClearBit(mir->ssa_rep->defs[0]); + } + // Mark non-null returns from invoke-style NEW* if (df_attributes & DF_NON_NULL_RET) { MIR* next_mir = mir->next; @@ -691,7 +729,7 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { if (next_mir && next_mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) { // Mark as null checked - temp_ssa_register_v_->SetBit(next_mir->ssa_rep->defs[0]); + temp_ssa_register_v_->ClearBit(next_mir->ssa_rep->defs[0]); } else { if (next_mir) { LOG(WARNING) << "Unexpected opcode following new: " << next_mir->dalvikInsn.opcode; @@ -706,7 +744,7 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { // First non-pseudo should be MOVE_RESULT_OBJECT if (tmir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) { // Mark as null checked - temp_ssa_register_v_->SetBit(tmir->ssa_rep->defs[0]); + temp_ssa_register_v_->ClearBit(tmir->ssa_rep->defs[0]); } else { LOG(WARNING) << "Unexpected op after new: " << tmir->dalvikInsn.opcode; } @@ -719,40 +757,22 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { /* * Propagate nullcheck state on register copies (including * Phi pseudo copies. For the latter, nullcheck state is - * the "and" of all the Phi's operands. + * the "or" of all the Phi's operands. */ if (df_attributes & (DF_NULL_TRANSFER_0 | DF_NULL_TRANSFER_N)) { int tgt_sreg = mir->ssa_rep->defs[0]; int operands = (df_attributes & DF_NULL_TRANSFER_0) ? 1 : mir->ssa_rep->num_uses; - bool null_checked = true; + bool needs_null_check = false; for (int i = 0; i < operands; i++) { - null_checked &= temp_ssa_register_v_->IsBitSet(mir->ssa_rep->uses[i]); + needs_null_check |= temp_ssa_register_v_->IsBitSet(mir->ssa_rep->uses[i]); } - if (null_checked) { + if (needs_null_check) { temp_ssa_register_v_->SetBit(tgt_sreg); - } - } - - // Already nullchecked? - if ((df_attributes & DF_HAS_NULL_CHKS) && !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) { - int src_idx; - if (df_attributes & DF_NULL_CHK_1) { - src_idx = 1; - } else if (df_attributes & DF_NULL_CHK_2) { - src_idx = 2; } else { - src_idx = 0; + temp_ssa_register_v_->ClearBit(tgt_sreg); } - int src_sreg = mir->ssa_rep->uses[src_idx]; - if (temp_ssa_register_v_->IsBitSet(src_sreg)) { - // Eliminate the null check - mir->optimization_flags |= MIR_IGNORE_NULL_CHECK; - } else { - // Mark s_reg as null-checked - temp_ssa_register_v_->SetBit(src_sreg); - } - } + } } // Did anything change? diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 2ce8f581b4..cc185f54ee 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -164,7 +164,8 @@ void Mir2Lir::DumpLIRInsn(LIR* lir, unsigned char* base_addr) { lir->operands[0] = WrapPointer(ArenaStrdup("No instruction string")); } LOG(INFO) << "-------- dalvik offset: 0x" << std::hex - << lir->dalvik_offset << " @ " << reinterpret_cast(lir->operands[0]); + << lir->dalvik_offset << " @ " + << reinterpret_cast(UnwrapPointer(lir->operands[0])); break; case kPseudoExitBlock: LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest; diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc index eb0d412bae..c86a788470 100644 --- a/compiler/dex/ssa_transformation.cc +++ b/compiler/dex/ssa_transformation.cc @@ -206,6 +206,7 @@ void MIRGraph::ComputeDomPostOrderTraversal(BasicBlock* bb) { /* hacky loop detection */ if ((curr_bb->taken != NullBasicBlockId) && curr_bb->dominators->IsBitSet(curr_bb->taken)) { + curr_bb->nesting_depth++; attributes_ |= METHOD_HAS_LOOP; } } -- cgit v1.2.3-59-g8ed1b From a61f49539a59b610e557b5513695295639496750 Mon Sep 17 00:00:00 2001 From: buzbee Date: Fri, 23 Aug 2013 14:27:06 -0700 Subject: Add timing logger to Quick compiler Current Quick compiler breakdown for compiling the boot class path: MIR2LIR: 29.674% MIROpt:SSATransform: 17.656% MIROpt:BBOpt: 11.508% BuildMIRGraph: 7.815% Assemble: 6.898% MIROpt:ConstantProp: 5.151% Cleanup: 4.916% MIROpt:NullCheckElimination: 4.085% RegisterAllocation: 3.972% GcMap: 2.359% Launchpads: 2.147% PcMappingTable: 2.145% MIROpt:CodeLayout: 0.697% LiteralData: 0.654% SpecialMIR2LIR: 0.323% Change-Id: I9f77e825faf79e6f6b214bb42edcc4b36f55d291 --- compiler/dex/compiler_ir.h | 11 ++++++++++- compiler/dex/frontend.cc | 32 ++++++++++++++++++++++++++++++++ compiler/dex/frontend.h | 1 + compiler/dex/quick/arm/assemble_arm.cc | 4 ++++ compiler/dex/quick/codegen_util.cc | 2 ++ compiler/dex/quick/mips/assemble_mips.cc | 4 ++++ compiler/dex/quick/mir_to_lir.cc | 4 +++- compiler/dex/quick/x86/assemble_x86.cc | 4 ++++ 8 files changed, 60 insertions(+), 2 deletions(-) (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h index bdc31547cb..0d7209e438 100644 --- a/compiler/dex/compiler_ir.h +++ b/compiler/dex/compiler_ir.h @@ -29,6 +29,7 @@ #include "llvm/intrinsic_helper.h" #include "llvm/ir_builder.h" #include "safe_map.h" +#include "base/timing_logger.h" namespace art { @@ -68,7 +69,14 @@ struct CompilationUnit { compiler_flip_match(false), arena(pool), mir_graph(NULL), - cg(NULL) {} + cg(NULL), + timings("QuickCompiler", true, false) { + } + + void StartTimingSplit(const char* label); + void NewTimingSplit(const char* label); + void EndTiming(); + /* * Fields needed/generated by common frontend and generally used throughout * the compiler. @@ -109,6 +117,7 @@ struct CompilationUnit { UniquePtr mir_graph; // MIR container. UniquePtr cg; // Target-specific codegen. + base::TimingLogger timings; }; } // namespace art diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index 2952570436..2f8521f788 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -24,6 +24,7 @@ #include "runtime.h" #include "backend.h" #include "base/logging.h" +#include "base/timing_logger.h" #if defined(ART_USE_PORTABLE_COMPILER) #include "dex/portable/mir_to_gbc.h" @@ -104,8 +105,30 @@ static uint32_t kCompilerDebugFlags = 0 | // Enable debug/testing modes // (1 << kDebugVerifyBitcode) | // (1 << kDebugShowSummaryMemoryUsage) | // (1 << kDebugShowFilterStats) | + // (1 << kDebugTimings) | 0; +// TODO: Add a cumulative version of logging, and combine with dex2oat --dump-timing +void CompilationUnit::StartTimingSplit(const char* label) { + if (enable_debug & (1 << kDebugTimings)) { + timings.StartSplit(label); + } +} + +void CompilationUnit::NewTimingSplit(const char* label) { + if (enable_debug & (1 << kDebugTimings)) { + timings.NewSplit(label); + } +} + +void CompilationUnit::EndTiming() { + if (enable_debug & (1 << kDebugTimings)) { + timings.EndSplit(); + LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file); + LOG(INFO) << Dumpable(timings); + } +} + static CompiledMethod* CompileMethod(CompilerDriver& compiler, const CompilerBackend compiler_backend, const DexFile::CodeItem* code_item, @@ -175,6 +198,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, (1 << kPromoteCompilerTemps)); } + cu.StartTimingSplit("BuildMIRGraph"); cu.mir_graph.reset(new MIRGraph(&cu, &cu.arena)); /* Gathering opcode stats? */ @@ -192,22 +216,28 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, } #endif + cu.NewTimingSplit("MIROpt:CodeLayout"); + /* Do a code layout pass */ cu.mir_graph->CodeLayout(); /* Perform SSA transformation for the whole method */ + cu.NewTimingSplit("MIROpt:SSATransform"); cu.mir_graph->SSATransformation(); /* Do constant propagation */ + cu.NewTimingSplit("MIROpt:ConstantProp"); cu.mir_graph->PropagateConstants(); /* Count uses */ cu.mir_graph->MethodUseCount(); /* Perform null check elimination */ + cu.NewTimingSplit("MIROpt:NullCheckElimination"); cu.mir_graph->NullCheckElimination(); /* Combine basic blocks where possible */ + cu.NewTimingSplit("MIROpt:BBOpt"); cu.mir_graph->BasicBlockCombine(); /* Do some basic block optimizations */ @@ -250,6 +280,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, cu.cg->Materialize(); + cu.NewTimingSplit("Cleanup"); result = cu.cg->GetCompiledMethod(); if (result) { @@ -270,6 +301,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, << " " << PrettyMethod(method_idx, dex_file); } + cu.EndTiming(); return result; } diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h index 6c33d109e3..43f68554b5 100644 --- a/compiler/dex/frontend.h +++ b/compiler/dex/frontend.h @@ -78,6 +78,7 @@ enum debugControlVector { kDebugVerifyBitcode, kDebugShowSummaryMemoryUsage, kDebugShowFilterStats, + kDebugTimings }; class LLVMInfo { diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc index cc40e99c52..2a6e656901 100644 --- a/compiler/dex/quick/arm/assemble_arm.cc +++ b/compiler/dex/quick/arm/assemble_arm.cc @@ -1153,6 +1153,7 @@ void ArmMir2Lir::EncodeLIR(LIR* lir) { void ArmMir2Lir::AssembleLIR() { LIR* lir; LIR* prev_lir; + cu_->NewTimingSplit("Assemble"); int assembler_retries = 0; CodeOffset starting_offset = EncodeRange(first_lir_insn_, last_lir_insn_, 0); data_offset_ = (starting_offset + 0x3) & ~0x3; @@ -1574,6 +1575,7 @@ void ArmMir2Lir::AssembleLIR() { data_offset_ = (code_buffer_.size() + 0x3) & ~0x3; + cu_->NewTimingSplit("LiteralData"); // Install literals InstallLiteralPools(); @@ -1584,8 +1586,10 @@ void ArmMir2Lir::AssembleLIR() { InstallFillArrayData(); // Create the mapping table and native offset to reference map. + cu_->NewTimingSplit("PcMappingTable"); CreateMappingTables(); + cu_->NewTimingSplit("GcMap"); CreateNativeGcMap(); } diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 2ce8f581b4..a6653fab19 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -929,6 +929,7 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena } void Mir2Lir::Materialize() { + cu_->NewTimingSplit("RegisterAllocation"); CompilerInitializeRegAlloc(); // Needs to happen after SSA naming /* Allocate Registers using simple local allocation scheme */ @@ -940,6 +941,7 @@ void Mir2Lir::Materialize() { * special codegen doesn't succeed, first_lir_insn_ will * set to NULL; */ + cu_->NewTimingSplit("SpecialMIR2LIR"); SpecialMIR2LIR(mir_graph_->GetSpecialCase()); } diff --git a/compiler/dex/quick/mips/assemble_mips.cc b/compiler/dex/quick/mips/assemble_mips.cc index ea8b7a64c1..5f5e5e44ac 100644 --- a/compiler/dex/quick/mips/assemble_mips.cc +++ b/compiler/dex/quick/mips/assemble_mips.cc @@ -768,6 +768,7 @@ void MipsMir2Lir::AssignOffsets() { * TODO: consolidate w/ Arm assembly mechanism. */ void MipsMir2Lir::AssembleLIR() { + cu_->NewTimingSplit("Assemble"); AssignOffsets(); int assembler_retries = 0; /* @@ -792,6 +793,7 @@ void MipsMir2Lir::AssembleLIR() { } // Install literals + cu_->NewTimingSplit("LiteralData"); InstallLiteralPools(); // Install switch tables @@ -801,8 +803,10 @@ void MipsMir2Lir::AssembleLIR() { InstallFillArrayData(); // Create the mapping table and native offset to reference map. + cu_->NewTimingSplit("PcMappingTable"); CreateMappingTables(); + cu_->NewTimingSplit("GcMap"); CreateNativeGcMap(); } diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc index 197e200fc3..fa9a3ad566 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -819,6 +819,8 @@ void Mir2Lir::SpecialMIR2LIR(SpecialCaseHandler special_case) { } void Mir2Lir::MethodMIR2LIR() { + cu_->NewTimingSplit("MIR2LIR"); + // Hold the labels of each block. block_label_list_ = static_cast(arena_->Alloc(sizeof(LIR) * mir_graph_->GetNumBlocks(), @@ -839,7 +841,7 @@ void Mir2Lir::MethodMIR2LIR() { next_bb = iter.Next(); } while ((next_bb != NULL) && (next_bb->block_type == kDead)); } - + cu_->NewTimingSplit("Launchpads"); HandleSuspendLaunchPads(); HandleThrowLaunchPads(); diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc index fb8e75fc1b..0e302608d8 100644 --- a/compiler/dex/quick/x86/assemble_x86.cc +++ b/compiler/dex/quick/x86/assemble_x86.cc @@ -1443,6 +1443,7 @@ void X86Mir2Lir::AssignOffsets() { * TODO: consolidate w/ Arm assembly mechanism. */ void X86Mir2Lir::AssembleLIR() { + cu_->NewTimingSplit("Assemble"); AssignOffsets(); int assembler_retries = 0; /* @@ -1466,6 +1467,7 @@ void X86Mir2Lir::AssembleLIR() { } } + cu_->NewTimingSplit("LiteralData"); // Install literals InstallLiteralPools(); @@ -1476,8 +1478,10 @@ void X86Mir2Lir::AssembleLIR() { InstallFillArrayData(); // Create the mapping table and native offset to reference map. + cu_->NewTimingSplit("PcMappingTable"); CreateMappingTables(); + cu_->NewTimingSplit("GcMap"); CreateNativeGcMap(); } -- cgit v1.2.3-59-g8ed1b From 31aa97cfec5ee76b2f2496464e1b6f9e11d21a29 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 25 Oct 2013 23:07:29 +0000 Subject: Revert "Null check elimination improvement" This reverts commit 4db179d1821a9e78819d5adc8057a72f49e2aed8. Change-Id: I059c15c85860c6c9f235b5dabaaef2edebaf1de2 --- compiler/dex/mir_dataflow.cc | 3 +- compiler/dex/mir_optimization.cc | 86 +++++++++++++++----------------------- compiler/dex/quick/codegen_util.cc | 3 +- compiler/dex/ssa_transformation.cc | 1 - 4 files changed, 35 insertions(+), 58 deletions(-) (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc index 11e19dc43f..9c8ce23ca5 100644 --- a/compiler/dex/mir_dataflow.cc +++ b/compiler/dex/mir_dataflow.cc @@ -1243,8 +1243,7 @@ bool MIRGraph::CountUses(struct BasicBlock* bb) { if (mir->ssa_rep == NULL) { continue; } - // Each level of nesting adds *16 to count, up to 3 levels deep. - uint32_t weight = std::min(3U, static_cast(bb->nesting_depth) * 4); + uint32_t weight = std::min(16U, static_cast(bb->nesting_depth)); for (int i = 0; i < mir->ssa_rep->num_uses; i++) { int s_reg = mir->ssa_rep->uses[i]; raw_use_counts_.Increment(s_reg); diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index 0b453b142f..3cd158ffc0 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -629,15 +629,10 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { */ if ((bb->block_type == kEntryBlock) | bb->catch_entry) { temp_ssa_register_v_->ClearAllBits(); - // Assume all ins are objects. - for (uint16_t in_reg = cu_->num_dalvik_registers - cu_->num_ins; - in_reg < cu_->num_dalvik_registers; in_reg++) { - temp_ssa_register_v_->SetBit(in_reg); - } if ((cu_->access_flags & kAccStatic) == 0) { // If non-static method, mark "this" as non-null int this_reg = cu_->num_dalvik_registers - cu_->num_ins; - temp_ssa_register_v_->ClearBit(this_reg); + temp_ssa_register_v_->SetBit(this_reg); } } else if (bb->predecessors->Size() == 1) { BasicBlock* pred_bb = GetBasicBlock(bb->predecessors->Get(0)); @@ -650,18 +645,18 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { if (pred_bb->fall_through == bb->id) { // The fall-through of a block following a IF_EQZ, set the vA of the IF_EQZ to show that // it can't be null. - temp_ssa_register_v_->ClearBit(last_insn->ssa_rep->uses[0]); + temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]); } } else if (last_opcode == Instruction::IF_NEZ) { if (pred_bb->taken == bb->id) { // The taken block following a IF_NEZ, set the vA of the IF_NEZ to show that it can't be // null. - temp_ssa_register_v_->ClearBit(last_insn->ssa_rep->uses[0]); + temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]); } } } } else { - // Starting state is union of all incoming arcs + // Starting state is intersection of all incoming arcs GrowableArray::Iterator iter(bb->predecessors); BasicBlock* pred_bb = GetBasicBlock(iter.Next()); DCHECK(pred_bb != NULL); @@ -673,13 +668,10 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { (pred_bb->data_flow_info->ending_null_check_v == NULL)) { continue; } - temp_ssa_register_v_->Union(pred_bb->data_flow_info->ending_null_check_v); + temp_ssa_register_v_->Intersect(pred_bb->data_flow_info->ending_null_check_v); } } - // At this point, temp_ssa_register_v_ shows which sregs have an object definition with - // no intervening uses. - // Walk through the instruction in the block, updating as necessary for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { if (mir->ssa_rep == NULL) { @@ -687,39 +679,9 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { } int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; - // Already nullchecked? - if ((df_attributes & DF_HAS_NULL_CHKS) && !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) { - int src_idx; - if (df_attributes & DF_NULL_CHK_1) { - src_idx = 1; - } else if (df_attributes & DF_NULL_CHK_2) { - src_idx = 2; - } else { - src_idx = 0; - } - int src_sreg = mir->ssa_rep->uses[src_idx]; - if (!temp_ssa_register_v_->IsBitSet(src_sreg)) { - // Eliminate the null check - mir->optimization_flags |= MIR_IGNORE_NULL_CHECK; - } else { - // Mark s_reg as null-checked - temp_ssa_register_v_->ClearBit(src_sreg); - } - } - - if ((df_attributes & (DF_REF_A | DF_NULL_TRANSFER_0 | DF_NULL_TRANSFER_N)) == 0) { - continue; - } - - // First, mark all object definitions as requiring null check. - if ((df_attributes & (DF_DA | DF_REF_A)) == (DF_DA | DF_REF_A)) { - temp_ssa_register_v_->SetBit(mir->ssa_rep->defs[0]); - } - - // Now, remove mark from all object definitions we know are non-null. + // Mark target of NEW* as non-null if (df_attributes & DF_NON_NULL_DST) { - // Mark target of NEW* as non-null - temp_ssa_register_v_->ClearBit(mir->ssa_rep->defs[0]); + temp_ssa_register_v_->SetBit(mir->ssa_rep->defs[0]); } // Mark non-null returns from invoke-style NEW* @@ -729,7 +691,7 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { if (next_mir && next_mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) { // Mark as null checked - temp_ssa_register_v_->ClearBit(next_mir->ssa_rep->defs[0]); + temp_ssa_register_v_->SetBit(next_mir->ssa_rep->defs[0]); } else { if (next_mir) { LOG(WARNING) << "Unexpected opcode following new: " << next_mir->dalvikInsn.opcode; @@ -744,7 +706,7 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { // First non-pseudo should be MOVE_RESULT_OBJECT if (tmir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) { // Mark as null checked - temp_ssa_register_v_->ClearBit(tmir->ssa_rep->defs[0]); + temp_ssa_register_v_->SetBit(tmir->ssa_rep->defs[0]); } else { LOG(WARNING) << "Unexpected op after new: " << tmir->dalvikInsn.opcode; } @@ -757,22 +719,40 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { /* * Propagate nullcheck state on register copies (including * Phi pseudo copies. For the latter, nullcheck state is - * the "or" of all the Phi's operands. + * the "and" of all the Phi's operands. */ if (df_attributes & (DF_NULL_TRANSFER_0 | DF_NULL_TRANSFER_N)) { int tgt_sreg = mir->ssa_rep->defs[0]; int operands = (df_attributes & DF_NULL_TRANSFER_0) ? 1 : mir->ssa_rep->num_uses; - bool needs_null_check = false; + bool null_checked = true; for (int i = 0; i < operands; i++) { - needs_null_check |= temp_ssa_register_v_->IsBitSet(mir->ssa_rep->uses[i]); + null_checked &= temp_ssa_register_v_->IsBitSet(mir->ssa_rep->uses[i]); } - if (needs_null_check) { + if (null_checked) { temp_ssa_register_v_->SetBit(tgt_sreg); - } else { - temp_ssa_register_v_->ClearBit(tgt_sreg); } } + + // Already nullchecked? + if ((df_attributes & DF_HAS_NULL_CHKS) && !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) { + int src_idx; + if (df_attributes & DF_NULL_CHK_1) { + src_idx = 1; + } else if (df_attributes & DF_NULL_CHK_2) { + src_idx = 2; + } else { + src_idx = 0; + } + int src_sreg = mir->ssa_rep->uses[src_idx]; + if (temp_ssa_register_v_->IsBitSet(src_sreg)) { + // Eliminate the null check + mir->optimization_flags |= MIR_IGNORE_NULL_CHECK; + } else { + // Mark s_reg as null-checked + temp_ssa_register_v_->SetBit(src_sreg); + } + } } // Did anything change? diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index cc185f54ee..2ce8f581b4 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -164,8 +164,7 @@ void Mir2Lir::DumpLIRInsn(LIR* lir, unsigned char* base_addr) { lir->operands[0] = WrapPointer(ArenaStrdup("No instruction string")); } LOG(INFO) << "-------- dalvik offset: 0x" << std::hex - << lir->dalvik_offset << " @ " - << reinterpret_cast(UnwrapPointer(lir->operands[0])); + << lir->dalvik_offset << " @ " << reinterpret_cast(lir->operands[0]); break; case kPseudoExitBlock: LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest; diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc index c86a788470..eb0d412bae 100644 --- a/compiler/dex/ssa_transformation.cc +++ b/compiler/dex/ssa_transformation.cc @@ -206,7 +206,6 @@ void MIRGraph::ComputeDomPostOrderTraversal(BasicBlock* bb) { /* hacky loop detection */ if ((curr_bb->taken != NullBasicBlockId) && curr_bb->dominators->IsBitSet(curr_bb->taken)) { - curr_bb->nesting_depth++; attributes_ |= METHOD_HAS_LOOP; } } -- cgit v1.2.3-59-g8ed1b From 0b1191cfece83f6f8d4101575a06555a2d13387a Mon Sep 17 00:00:00 2001 From: Bill Buzbee Date: Mon, 28 Oct 2013 22:11:59 +0000 Subject: Revert "Revert "Null check elimination improvement"" This reverts commit 31aa97cfec5ee76b2f2496464e1b6f9e11d21a29. ..and thereby brings back change 380165, which was reverted because it was buggy. Three problems with the original CL: 1. The author ran the pre-submit tests, but used -j24 and failed to search the output for fail messages. 2. The new null check analysis pass uses an interative approach to identify whether a null check is needed. It is possible that the null-check-required state may oscillate, and a logic error caused it to stick in the "no check needed" state. 3. Our old nemesis Dalvik untyped constants, in which 0 values can be used both as object reference and non-object references. This CL conservatively treats all CONST definitions as potential object definitions for the purposes of null check elimination. Change-Id: I3c1744e44318276e42989502a314585e56ac57a0 --- compiler/dex/mir_dataflow.cc | 3 +- compiler/dex/mir_graph.h | 2 +- compiler/dex/mir_optimization.cc | 94 +++++++++++++++++++++++++------------- compiler/dex/quick/codegen_util.cc | 3 +- compiler/dex/ssa_transformation.cc | 1 + 5 files changed, 67 insertions(+), 36 deletions(-) (limited to 'compiler/dex/quick/codegen_util.cc') diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc index 9c8ce23ca5..11e19dc43f 100644 --- a/compiler/dex/mir_dataflow.cc +++ b/compiler/dex/mir_dataflow.cc @@ -1243,7 +1243,8 @@ bool MIRGraph::CountUses(struct BasicBlock* bb) { if (mir->ssa_rep == NULL) { continue; } - uint32_t weight = std::min(16U, static_cast(bb->nesting_depth)); + // Each level of nesting adds *16 to count, up to 3 levels deep. + uint32_t weight = std::min(3U, static_cast(bb->nesting_depth) * 4); for (int i = 0; i < mir->ssa_rep->num_uses; i++) { int s_reg = mir->ssa_rep->uses[i]; raw_use_counts_.Increment(s_reg); diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 8dda7c4c7e..a69dde0da3 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -149,7 +149,7 @@ enum DataFlowAttributePos { #define DF_C_IS_REG (DF_UC) #define DF_IS_GETTER_OR_SETTER (DF_IS_GETTER | DF_IS_SETTER) #define DF_USES_FP (DF_FP_A | DF_FP_B | DF_FP_C) - +#define DF_NULL_TRANSFER (DF_NULL_TRANSFER_0 | DF_NULL_TRANSFER_N) enum OatMethodAttributes { kIsLeaf, // Method is leaf. kHasLoop, // Method contains simple loop. diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index 3cd158ffc0..f5913a5ad4 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -629,10 +629,15 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { */ if ((bb->block_type == kEntryBlock) | bb->catch_entry) { temp_ssa_register_v_->ClearAllBits(); + // Assume all ins are objects. + for (uint16_t in_reg = cu_->num_dalvik_registers - cu_->num_ins; + in_reg < cu_->num_dalvik_registers; in_reg++) { + temp_ssa_register_v_->SetBit(in_reg); + } if ((cu_->access_flags & kAccStatic) == 0) { // If non-static method, mark "this" as non-null int this_reg = cu_->num_dalvik_registers - cu_->num_ins; - temp_ssa_register_v_->SetBit(this_reg); + temp_ssa_register_v_->ClearBit(this_reg); } } else if (bb->predecessors->Size() == 1) { BasicBlock* pred_bb = GetBasicBlock(bb->predecessors->Get(0)); @@ -645,18 +650,18 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { if (pred_bb->fall_through == bb->id) { // The fall-through of a block following a IF_EQZ, set the vA of the IF_EQZ to show that // it can't be null. - temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]); + temp_ssa_register_v_->ClearBit(last_insn->ssa_rep->uses[0]); } } else if (last_opcode == Instruction::IF_NEZ) { if (pred_bb->taken == bb->id) { // The taken block following a IF_NEZ, set the vA of the IF_NEZ to show that it can't be // null. - temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]); + temp_ssa_register_v_->ClearBit(last_insn->ssa_rep->uses[0]); } } } } else { - // Starting state is intersection of all incoming arcs + // Starting state is union of all incoming arcs GrowableArray::Iterator iter(bb->predecessors); BasicBlock* pred_bb = GetBasicBlock(iter.Next()); DCHECK(pred_bb != NULL); @@ -668,10 +673,13 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { (pred_bb->data_flow_info->ending_null_check_v == NULL)) { continue; } - temp_ssa_register_v_->Intersect(pred_bb->data_flow_info->ending_null_check_v); + temp_ssa_register_v_->Union(pred_bb->data_flow_info->ending_null_check_v); } } + // At this point, temp_ssa_register_v_ shows which sregs have an object definition with + // no intervening uses. + // Walk through the instruction in the block, updating as necessary for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { if (mir->ssa_rep == NULL) { @@ -679,11 +687,49 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { } int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode]; - // Mark target of NEW* as non-null - if (df_attributes & DF_NON_NULL_DST) { + // Might need a null check? + if (df_attributes & DF_HAS_NULL_CHKS) { + int src_idx; + if (df_attributes & DF_NULL_CHK_1) { + src_idx = 1; + } else if (df_attributes & DF_NULL_CHK_2) { + src_idx = 2; + } else { + src_idx = 0; + } + int src_sreg = mir->ssa_rep->uses[src_idx]; + if (!temp_ssa_register_v_->IsBitSet(src_sreg)) { + // Eliminate the null check. + mir->optimization_flags |= MIR_IGNORE_NULL_CHECK; + } else { + // Do the null check. + mir->optimization_flags &= ~MIR_IGNORE_NULL_CHECK; + // Mark s_reg as null-checked + temp_ssa_register_v_->ClearBit(src_sreg); + } + } + + if ((df_attributes & DF_A_WIDE) || + (df_attributes & (DF_REF_A | DF_SETS_CONST | DF_NULL_TRANSFER)) == 0) { + continue; + } + + /* + * First, mark all object definitions as requiring null check. + * Note: we can't tell if a CONST definition might be used as an object, so treat + * them all as object definitions. + */ + if (((df_attributes & (DF_DA | DF_REF_A)) == (DF_DA | DF_REF_A)) || + (df_attributes & DF_SETS_CONST)) { temp_ssa_register_v_->SetBit(mir->ssa_rep->defs[0]); } + // Now, remove mark from all object definitions we know are non-null. + if (df_attributes & DF_NON_NULL_DST) { + // Mark target of NEW* as non-null + temp_ssa_register_v_->ClearBit(mir->ssa_rep->defs[0]); + } + // Mark non-null returns from invoke-style NEW* if (df_attributes & DF_NON_NULL_RET) { MIR* next_mir = mir->next; @@ -691,7 +737,7 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { if (next_mir && next_mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) { // Mark as null checked - temp_ssa_register_v_->SetBit(next_mir->ssa_rep->defs[0]); + temp_ssa_register_v_->ClearBit(next_mir->ssa_rep->defs[0]); } else { if (next_mir) { LOG(WARNING) << "Unexpected opcode following new: " << next_mir->dalvikInsn.opcode; @@ -706,7 +752,7 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { // First non-pseudo should be MOVE_RESULT_OBJECT if (tmir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) { // Mark as null checked - temp_ssa_register_v_->SetBit(tmir->ssa_rep->defs[0]); + temp_ssa_register_v_->ClearBit(tmir->ssa_rep->defs[0]); } else { LOG(WARNING) << "Unexpected op after new: " << tmir->dalvikInsn.opcode; } @@ -719,40 +765,22 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb) { /* * Propagate nullcheck state on register copies (including * Phi pseudo copies. For the latter, nullcheck state is - * the "and" of all the Phi's operands. + * the "or" of all the Phi's operands. */ if (df_attributes & (DF_NULL_TRANSFER_0 | DF_NULL_TRANSFER_N)) { int tgt_sreg = mir->ssa_rep->defs[0]; int operands = (df_attributes & DF_NULL_TRANSFER_0) ? 1 : mir->ssa_rep->num_uses; - bool null_checked = true; + bool needs_null_check = false; for (int i = 0; i < operands; i++) { - null_checked &= temp_ssa_register_v_->IsBitSet(mir->ssa_rep->uses[i]); + needs_null_check |= temp_ssa_register_v_->IsBitSet(mir->ssa_rep->uses[i]); } - if (null_checked) { + if (needs_null_check) { temp_ssa_register_v_->SetBit(tgt_sreg); - } - } - - // Already nullchecked? - if ((df_attributes & DF_HAS_NULL_CHKS) && !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) { - int src_idx; - if (df_attributes & DF_NULL_CHK_1) { - src_idx = 1; - } else if (df_attributes & DF_NULL_CHK_2) { - src_idx = 2; } else { - src_idx = 0; + temp_ssa_register_v_->ClearBit(tgt_sreg); } - int src_sreg = mir->ssa_rep->uses[src_idx]; - if (temp_ssa_register_v_->IsBitSet(src_sreg)) { - // Eliminate the null check - mir->optimization_flags |= MIR_IGNORE_NULL_CHECK; - } else { - // Mark s_reg as null-checked - temp_ssa_register_v_->SetBit(src_sreg); - } - } + } } // Did anything change? diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index a6653fab19..dfbc887299 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -164,7 +164,8 @@ void Mir2Lir::DumpLIRInsn(LIR* lir, unsigned char* base_addr) { lir->operands[0] = WrapPointer(ArenaStrdup("No instruction string")); } LOG(INFO) << "-------- dalvik offset: 0x" << std::hex - << lir->dalvik_offset << " @ " << reinterpret_cast(lir->operands[0]); + << lir->dalvik_offset << " @ " + << reinterpret_cast(UnwrapPointer(lir->operands[0])); break; case kPseudoExitBlock: LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest; diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc index b6c892212c..0d8bd07f40 100644 --- a/compiler/dex/ssa_transformation.cc +++ b/compiler/dex/ssa_transformation.cc @@ -206,6 +206,7 @@ void MIRGraph::ComputeDomPostOrderTraversal(BasicBlock* bb) { /* hacky loop detection */ if ((curr_bb->taken != NullBasicBlockId) && curr_bb->dominators->IsBitSet(curr_bb->taken)) { + curr_bb->nesting_depth++; attributes_ |= METHOD_HAS_LOOP; } } -- cgit v1.2.3-59-g8ed1b