diff options
author | 2016-03-21 17:10:24 +0000 | |
---|---|---|
committer | 2016-03-21 17:39:20 +0000 | |
commit | 3c94f0945ed596ceee39783fa075f013b65e80a1 (patch) | |
tree | c10b5808a5d7157371c2750823e6a168c73aa231 /compiler/dex/mir_graph.cc | |
parent | 162629ee8ac0fee2df0c0cdec27dff34bc6f0062 (diff) |
Remove Quick from tree.
So long, old friend.
Change-Id: I0241c798a34b92bf994fed83888da67d6e7f1891
Diffstat (limited to 'compiler/dex/mir_graph.cc')
-rw-r--r-- | compiler/dex/mir_graph.cc | 2589 |
1 files changed, 0 insertions, 2589 deletions
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc deleted file mode 100644 index 6dc148dfdb..0000000000 --- a/compiler/dex/mir_graph.cc +++ /dev/null @@ -1,2589 +0,0 @@ -/* - * Copyright (C) 2013 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 "mir_graph.h" - -#include <inttypes.h> -#include <queue> -#include <unistd.h> - -#include "base/bit_vector-inl.h" -#include "base/logging.h" -#include "base/stl_util.h" -#include "base/stringprintf.h" -#include "base/scoped_arena_containers.h" -#include "compiler_ir.h" -#include "dex_file-inl.h" -#include "dex_flags.h" -#include "dex_instruction-inl.h" -#include "driver/compiler_driver.h" -#include "driver/dex_compilation_unit.h" -#include "dex/quick/quick_compiler.h" -#include "leb128.h" -#include "pass_driver_me_post_opt.h" -#include "stack.h" -#include "utils.h" - -namespace art { - -#define MAX_PATTERN_LEN 5 - -const char* MIRGraph::extended_mir_op_names_[kMirOpLast - kMirOpFirst] = { - "Phi", - "Copy", - "FusedCmplFloat", - "FusedCmpgFloat", - "FusedCmplDouble", - "FusedCmpgDouble", - "FusedCmpLong", - "Nop", - "OpNullCheck", - "OpRangeCheck", - "OpDivZeroCheck", - "Check", - "Select", - "ConstVector", - "MoveVector", - "PackedMultiply", - "PackedAddition", - "PackedSubtract", - "PackedShiftLeft", - "PackedSignedShiftRight", - "PackedUnsignedShiftRight", - "PackedAnd", - "PackedOr", - "PackedXor", - "PackedAddReduce", - "PackedReduce", - "PackedSet", - "ReserveVectorRegisters", - "ReturnVectorRegisters", - "MemBarrier", - "PackedArrayGet", - "PackedArrayPut", - "MaddInt", - "MsubInt", - "MaddLong", - "MsubLong", -}; - -MIRGraph::MIRGraph(CompilationUnit* cu, ArenaAllocator* arena) - : reg_location_(nullptr), - block_id_map_(std::less<unsigned int>(), arena->Adapter()), - cu_(cu), - ssa_base_vregs_(arena->Adapter(kArenaAllocSSAToDalvikMap)), - ssa_subscripts_(arena->Adapter(kArenaAllocSSAToDalvikMap)), - vreg_to_ssa_map_(nullptr), - ssa_last_defs_(nullptr), - is_constant_v_(nullptr), - constant_values_(nullptr), - use_counts_(arena->Adapter()), - raw_use_counts_(arena->Adapter()), - num_reachable_blocks_(0), - max_num_reachable_blocks_(0), - dfs_orders_up_to_date_(false), - domination_up_to_date_(false), - mir_ssa_rep_up_to_date_(false), - topological_order_up_to_date_(false), - dfs_order_(arena->Adapter(kArenaAllocDfsPreOrder)), - dfs_post_order_(arena->Adapter(kArenaAllocDfsPostOrder)), - dom_post_order_traversal_(arena->Adapter(kArenaAllocDomPostOrder)), - topological_order_(arena->Adapter(kArenaAllocTopologicalSortOrder)), - topological_order_loop_ends_(arena->Adapter(kArenaAllocTopologicalSortOrder)), - topological_order_indexes_(arena->Adapter(kArenaAllocTopologicalSortOrder)), - topological_order_loop_head_stack_(arena->Adapter(kArenaAllocTopologicalSortOrder)), - max_nested_loops_(0u), - i_dom_list_(nullptr), - temp_scoped_alloc_(), - block_list_(arena->Adapter(kArenaAllocBBList)), - try_block_addr_(nullptr), - entry_block_(nullptr), - exit_block_(nullptr), - current_code_item_(nullptr), - m_units_(arena->Adapter()), - method_stack_(arena->Adapter()), - current_method_(kInvalidEntry), - current_offset_(kInvalidEntry), - def_count_(0), - opcode_count_(nullptr), - num_ssa_regs_(0), - extended_basic_blocks_(arena->Adapter()), - method_sreg_(0), - attributes_(METHOD_IS_LEAF), // Start with leaf assumption, change on encountering invoke. - checkstats_(nullptr), - arena_(arena), - backward_branches_(0), - forward_branches_(0), - num_non_special_compiler_temps_(0), - max_available_special_compiler_temps_(1), // We only need the method ptr as a special temp for now. - requested_backend_temp_(false), - compiler_temps_committed_(false), - punt_to_interpreter_(false), - merged_df_flags_(0u), - ifield_lowering_infos_(arena->Adapter(kArenaAllocLoweringInfo)), - sfield_lowering_infos_(arena->Adapter(kArenaAllocLoweringInfo)), - method_lowering_infos_(arena->Adapter(kArenaAllocLoweringInfo)), - suspend_checks_in_loops_(nullptr) { - memset(&temp_, 0, sizeof(temp_)); - use_counts_.reserve(256); - raw_use_counts_.reserve(256); - block_list_.reserve(100); - try_block_addr_ = new (arena_) ArenaBitVector(arena_, 0, true /* expandable */); - - - if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) { - // X86 requires a temp to keep track of the method address. - // TODO For x86_64, addressing can be done with RIP. When that is implemented, - // this needs to be updated to reserve 0 temps for BE. - max_available_non_special_compiler_temps_ = cu_->target64 ? 2 : 1; - reserved_temps_for_backend_ = max_available_non_special_compiler_temps_; - } else { - // Other architectures do not have a known lower bound for non-special temps. - // We allow the update of the max to happen at BE initialization stage and simply set 0 for now. - max_available_non_special_compiler_temps_ = 0; - reserved_temps_for_backend_ = 0; - } -} - -MIRGraph::~MIRGraph() { - STLDeleteElements(&block_list_); - STLDeleteElements(&m_units_); -} - -/* - * Parse an instruction, return the length of the instruction - */ -int MIRGraph::ParseInsn(const uint16_t* code_ptr, MIR::DecodedInstruction* decoded_instruction) { - const Instruction* inst = Instruction::At(code_ptr); - decoded_instruction->opcode = inst->Opcode(); - decoded_instruction->vA = inst->HasVRegA() ? inst->VRegA() : 0; - decoded_instruction->vB = inst->HasVRegB() ? inst->VRegB() : 0; - decoded_instruction->vB_wide = inst->HasWideVRegB() ? inst->WideVRegB() : 0; - decoded_instruction->vC = inst->HasVRegC() ? inst->VRegC() : 0; - if (inst->HasVarArgs35c()) { - inst->GetVarArgs(decoded_instruction->arg); - } - return inst->SizeInCodeUnits(); -} - - -/* Split an existing block from the specified code offset into two */ -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 = nullptr; // Will be set to instruction before split. - while (insn) { - if (insn->offset == code_offset) break; - prev = insn; - insn = insn->next; - } - if (insn == nullptr) { - LOG(FATAL) << "Break split failed"; - } - // Now insn is at the instruction where we want to split, namely - // insn will be the first instruction of the "bottom" block. - // Similarly, prev will be the last instruction of the "top" block - - BasicBlock* bottom_block = CreateNewBB(kDalvikByteCode); - - bottom_block->start_offset = code_offset; - bottom_block->first_mir_insn = insn; - bottom_block->last_mir_insn = orig_block->last_mir_insn; - - /* If this block was terminated by a return, conditional branch or throw, - * the flag needs to go with the bottom block - */ - bottom_block->terminated_by_return = orig_block->terminated_by_return; - orig_block->terminated_by_return = false; - - bottom_block->conditional_branch = orig_block->conditional_branch; - orig_block->conditional_branch = false; - - bottom_block->explicit_throw = orig_block->explicit_throw; - orig_block->explicit_throw = false; - - /* Handle the taken path */ - bottom_block->taken = orig_block->taken; - if (bottom_block->taken != NullBasicBlockId) { - orig_block->taken = NullBasicBlockId; - BasicBlock* bb_taken = GetBasicBlock(bottom_block->taken); - bb_taken->ErasePredecessor(orig_block->id); - bb_taken->predecessors.push_back(bottom_block->id); - } - - /* Handle the fallthrough path */ - bottom_block->fall_through = orig_block->fall_through; - orig_block->fall_through = bottom_block->id; - bottom_block->predecessors.push_back(orig_block->id); - if (bottom_block->fall_through != NullBasicBlockId) { - BasicBlock* bb_fall_through = GetBasicBlock(bottom_block->fall_through); - bb_fall_through->ErasePredecessor(orig_block->id); - bb_fall_through->predecessors.push_back(bottom_block->id); - } - - /* Handle the successor list */ - if (orig_block->successor_block_list_type != kNotUsed) { - bottom_block->successor_block_list_type = orig_block->successor_block_list_type; - bottom_block->successor_blocks.swap(orig_block->successor_blocks); - orig_block->successor_block_list_type = kNotUsed; - DCHECK(orig_block->successor_blocks.empty()); // Empty after the swap() above. - for (SuccessorBlockInfo* successor_block_info : bottom_block->successor_blocks) { - BasicBlock* bb = GetBasicBlock(successor_block_info->block); - if (bb != nullptr) { - bb->ErasePredecessor(orig_block->id); - bb->predecessors.push_back(bottom_block->id); - } - } - } - - orig_block->last_mir_insn = prev; - prev->next = nullptr; - - /* - * Update the immediate predecessor block pointer so that outgoing edges - * can be applied to the proper block. - */ - if (immed_pred_block_p) { - 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. - DCHECK(insn != nullptr); - DCHECK(insn != orig_block->first_mir_insn); - DCHECK(insn == bottom_block->first_mir_insn); - DCHECK_EQ(insn->offset, bottom_block->start_offset); - // Scan the "bottom" instructions, remapping them to the - // newly created "bottom" block. - MIR* p = insn; - p->bb = bottom_block->id; - while (p != bottom_block->last_mir_insn) { - p = p->next; - DCHECK(p != nullptr); - p->bb = bottom_block->id; - } - - return bottom_block; -} - -/* - * Given a code offset, find out the block that starts with it. If the offset - * is in the middle of an existing block, split it into two. If immed_pred_block_p - * is not non-null and is the block being split, update *immed_pred_block_p to - * point to the bottom block so that outgoing edges can be set up properly - * (by the caller) - * Utilizes a map for fast lookup of the typical cases. - */ -BasicBlock* MIRGraph::FindBlock(DexOffset code_offset, bool create, - BasicBlock** immed_pred_block_p, - ScopedArenaVector<uint16_t>* dex_pc_to_block_map) { - if (UNLIKELY(code_offset >= current_code_item_->insns_size_in_code_units_)) { - // There can be a fall-through out of the method code. We shall record such a block - // here (assuming create==true) and check that it's dead at the end of InlineMethod(). - // Though we're only aware of the cases where code_offset is exactly the same as - // insns_size_in_code_units_, treat greater code_offset the same just in case. - code_offset = current_code_item_->insns_size_in_code_units_; - } - - int block_id = (*dex_pc_to_block_map)[code_offset]; - BasicBlock* bb = GetBasicBlock(block_id); - - if ((bb != nullptr) && (bb->start_offset == code_offset)) { - // Does this containing block start with the desired instruction? - return bb; - } - - // No direct hit. - if (!create) { - return nullptr; - } - - if (bb != nullptr) { - // The target exists somewhere in an existing block. - BasicBlock* bottom_block = SplitBlock(code_offset, bb, bb == *immed_pred_block_p ? immed_pred_block_p : nullptr); - DCHECK(bottom_block != nullptr); - MIR* p = bottom_block->first_mir_insn; - BasicBlock* orig_block = bb; - DCHECK_EQ((*dex_pc_to_block_map)[p->offset], orig_block->id); - // Scan the "bottom" instructions, remapping them to the - // newly created "bottom" block. - (*dex_pc_to_block_map)[p->offset] = bottom_block->id; - while (p != bottom_block->last_mir_insn) { - p = p->next; - DCHECK(p != nullptr); - 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. Since the 2nd half of a split operation is always - * the first in a BasicBlock, we can't hit it here. - */ - if ((opcode == kMirOpCheck) || !MIR::DecodedInstruction::IsPseudoMirOp(opcode)) { - BasicBlockId mapped_id = (*dex_pc_to_block_map)[p->offset]; - // At first glance the instructions should all be mapped to orig_block. - // However, multiple instructions may correspond to the same dex, hence an earlier - // instruction may have already moved the mapping for dex to bottom_block. - DCHECK((mapped_id == orig_block->id) || (mapped_id == bottom_block->id)); - (*dex_pc_to_block_map)[p->offset] = bottom_block->id; - } - } - return bottom_block; - } - - // Create a new block. - bb = CreateNewBB(kDalvikByteCode); - bb->start_offset = code_offset; - (*dex_pc_to_block_map)[bb->start_offset] = bb->id; - return bb; -} - - -/* Identify code range in try blocks and set up the empty catch blocks */ -void MIRGraph::ProcessTryCatchBlocks(ScopedArenaVector<uint16_t>* dex_pc_to_block_map) { - int tries_size = current_code_item_->tries_size_; - DexOffset offset; - - if (tries_size == 0) { - return; - } - - for (int i = 0; i < tries_size; i++) { - const DexFile::TryItem* pTry = - DexFile::GetTryItems(*current_code_item_, i); - 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); - } - } - - // Iterate over each of the handlers to enqueue the empty Catch blocks. - const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*current_code_item_, 0); - uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr); - for (uint32_t idx = 0; idx < handlers_size; idx++) { - CatchHandlerIterator iterator(handlers_ptr); - for (; iterator.HasNext(); iterator.Next()) { - uint32_t address = iterator.GetHandlerAddress(); - FindBlock(address, true /*create*/, /* immed_pred_block_p */ nullptr, dex_pc_to_block_map); - } - handlers_ptr = iterator.EndDataPointer(); - } -} - -bool MIRGraph::IsBadMonitorExitCatch(NarrowDexOffset monitor_exit_offset, - NarrowDexOffset catch_offset) { - // Catches for monitor-exit during stack unwinding have the pattern - // move-exception (move)* (goto)? monitor-exit throw - // In the currently generated dex bytecode we see these catching a bytecode range including - // either its own or an identical monitor-exit, http://b/15745363 . This function checks if - // it's the case for a given monitor-exit and catch block so that we can ignore it. - // (We don't want to ignore all monitor-exit catches since one could enclose a synchronized - // block in a try-block and catch the NPE, Error or Throwable and we should let it through; - // even though a throwing monitor-exit certainly indicates a bytecode error.) - const Instruction* monitor_exit = Instruction::At(current_code_item_->insns_ + monitor_exit_offset); - DCHECK(monitor_exit->Opcode() == Instruction::MONITOR_EXIT); - int monitor_reg = monitor_exit->VRegA_11x(); - const Instruction* check_insn = Instruction::At(current_code_item_->insns_ + catch_offset); - if (check_insn->Opcode() == Instruction::MOVE_EXCEPTION) { - if (check_insn->VRegA_11x() == monitor_reg) { - // Unexpected move-exception to the same register. Probably not the pattern we're looking for. - return false; - } - check_insn = check_insn->Next(); - } - while (true) { - int dest = -1; - bool wide = false; - switch (check_insn->Opcode()) { - case Instruction::MOVE_WIDE: - wide = true; - FALLTHROUGH_INTENDED; - case Instruction::MOVE_OBJECT: - case Instruction::MOVE: - dest = check_insn->VRegA_12x(); - break; - - case Instruction::MOVE_WIDE_FROM16: - wide = true; - FALLTHROUGH_INTENDED; - case Instruction::MOVE_OBJECT_FROM16: - case Instruction::MOVE_FROM16: - dest = check_insn->VRegA_22x(); - break; - - case Instruction::MOVE_WIDE_16: - wide = true; - FALLTHROUGH_INTENDED; - case Instruction::MOVE_OBJECT_16: - case Instruction::MOVE_16: - dest = check_insn->VRegA_32x(); - break; - - case Instruction::GOTO: - case Instruction::GOTO_16: - case Instruction::GOTO_32: - check_insn = check_insn->RelativeAt(check_insn->GetTargetOffset()); - FALLTHROUGH_INTENDED; - default: - return check_insn->Opcode() == Instruction::MONITOR_EXIT && - check_insn->VRegA_11x() == monitor_reg; - } - - if (dest == monitor_reg || (wide && dest + 1 == monitor_reg)) { - return false; - } - - check_insn = check_insn->Next(); - } -} - -/* Process instructions with the kBranch flag */ -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, - ScopedArenaVector<uint16_t>* dex_pc_to_block_map) { - DexOffset target = cur_offset; - switch (insn->dalvikInsn.opcode) { - case Instruction::GOTO: - case Instruction::GOTO_16: - case Instruction::GOTO_32: - target += insn->dalvikInsn.vA; - break; - case Instruction::IF_EQ: - case Instruction::IF_NE: - case Instruction::IF_LT: - case Instruction::IF_GE: - case Instruction::IF_GT: - case Instruction::IF_LE: - cur_block->conditional_branch = true; - target += insn->dalvikInsn.vC; - break; - case Instruction::IF_EQZ: - case Instruction::IF_NEZ: - case Instruction::IF_LTZ: - case Instruction::IF_GEZ: - case Instruction::IF_GTZ: - case Instruction::IF_LEZ: - cur_block->conditional_branch = true; - target += insn->dalvikInsn.vB; - break; - default: - LOG(FATAL) << "Unexpected opcode(" << insn->dalvikInsn.opcode << ") with kBranch set"; - } - CountBranch(target); - BasicBlock* taken_block = FindBlock(target, /* create */ true, - /* immed_pred_block_p */ &cur_block, - dex_pc_to_block_map); - DCHECK(taken_block != nullptr); - cur_block->taken = taken_block->id; - taken_block->predecessors.push_back(cur_block->id); - - /* Always terminate the current block for conditional branches */ - if (flags & Instruction::kContinue) { - BasicBlock* fallthrough_block = FindBlock(cur_offset + width, - /* create */ - true, - /* immed_pred_block_p */ - &cur_block, - dex_pc_to_block_map); - DCHECK(fallthrough_block != nullptr); - cur_block->fall_through = fallthrough_block->id; - fallthrough_block->predecessors.push_back(cur_block->id); - } else if (code_ptr < code_end) { - FindBlock(cur_offset + width, /* create */ true, /* immed_pred_block_p */ nullptr, dex_pc_to_block_map); - } - return cur_block; -} - -/* Process instructions with the kSwitch flag */ -BasicBlock* MIRGraph::ProcessCanSwitch(BasicBlock* cur_block, MIR* insn, DexOffset cur_offset, - int width, int flags ATTRIBUTE_UNUSED, - ScopedArenaVector<uint16_t>* dex_pc_to_block_map) { - const uint16_t* switch_data = - reinterpret_cast<const uint16_t*>(GetCurrentInsns() + cur_offset + - static_cast<int32_t>(insn->dalvikInsn.vB)); - int size; - const int* keyTable; - const int* target_table; - int i; - int first_key; - - /* - * Packed switch data format: - * ushort ident = 0x0100 magic value - * ushort size number of entries in the table - * int first_key first (and lowest) switch case value - * int targets[size] branch targets, relative to switch opcode - * - * Total size is (4+size*2) 16-bit code units. - */ - if (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) { - DCHECK_EQ(static_cast<int>(switch_data[0]), - static_cast<int>(Instruction::kPackedSwitchSignature)); - size = switch_data[1]; - first_key = switch_data[2] | (switch_data[3] << 16); - target_table = reinterpret_cast<const int*>(&switch_data[4]); - keyTable = nullptr; // Make the compiler happy. - /* - * Sparse switch data format: - * ushort ident = 0x0200 magic value - * ushort size number of entries in the table; > 0 - * int keys[size] keys, sorted low-to-high; 32-bit aligned - * int targets[size] branch targets, relative to switch opcode - * - * Total size is (2+size*4) 16-bit code units. - */ - } else { - DCHECK_EQ(static_cast<int>(switch_data[0]), - static_cast<int>(Instruction::kSparseSwitchSignature)); - size = switch_data[1]; - keyTable = reinterpret_cast<const int*>(&switch_data[2]); - target_table = reinterpret_cast<const int*>(&switch_data[2 + size*2]); - first_key = 0; // To make the compiler happy. - } - - if (cur_block->successor_block_list_type != kNotUsed) { - LOG(FATAL) << "Successor block list already in use: " - << static_cast<int>(cur_block->successor_block_list_type); - } - cur_block->successor_block_list_type = - (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ? kPackedSwitch : kSparseSwitch; - cur_block->successor_blocks.reserve(size); - - for (i = 0; i < size; i++) { - BasicBlock* case_block = FindBlock(cur_offset + target_table[i], /* create */ true, - /* immed_pred_block_p */ &cur_block, - dex_pc_to_block_map); - DCHECK(case_block != nullptr); - SuccessorBlockInfo* successor_block_info = - static_cast<SuccessorBlockInfo*>(arena_->Alloc(sizeof(SuccessorBlockInfo), - kArenaAllocSuccessors)); - 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_blocks.push_back(successor_block_info); - case_block->predecessors.push_back(cur_block->id); - } - - /* Fall-through case */ - BasicBlock* fallthrough_block = FindBlock(cur_offset + width, /* create */ true, - /* immed_pred_block_p */ nullptr, - dex_pc_to_block_map); - DCHECK(fallthrough_block != nullptr); - cur_block->fall_through = fallthrough_block->id; - fallthrough_block->predecessors.push_back(cur_block->id); - return cur_block; -} - -/* Process instructions with the kThrow flag */ -BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, - MIR* insn, - DexOffset cur_offset, - int width, - int flags ATTRIBUTE_UNUSED, - ArenaBitVector* try_block_addr, - const uint16_t* code_ptr, - const uint16_t* code_end, - ScopedArenaVector<uint16_t>* dex_pc_to_block_map) { - bool in_try_block = try_block_addr->IsBitSet(cur_offset); - bool is_throw = (insn->dalvikInsn.opcode == Instruction::THROW); - - /* In try block */ - if (in_try_block) { - CatchHandlerIterator iterator(*current_code_item_, cur_offset); - - 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<int>(cur_block->successor_block_list_type); - } - - for (; iterator.HasNext(); iterator.Next()) { - BasicBlock* catch_block = FindBlock(iterator.GetHandlerAddress(), false /* create */, - nullptr /* immed_pred_block_p */, - dex_pc_to_block_map); - if (insn->dalvikInsn.opcode == Instruction::MONITOR_EXIT && - IsBadMonitorExitCatch(insn->offset, catch_block->start_offset)) { - // Don't allow monitor-exit to catch its own exception, http://b/15745363 . - continue; - } - if (cur_block->successor_block_list_type == kNotUsed) { - cur_block->successor_block_list_type = kCatch; - } - catch_block->catch_entry = true; - if (kIsDebugBuild) { - catches_.insert(catch_block->start_offset); - } - SuccessorBlockInfo* successor_block_info = reinterpret_cast<SuccessorBlockInfo*> - (arena_->Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessors)); - successor_block_info->block = catch_block->id; - successor_block_info->key = iterator.GetHandlerTypeIndex(); - cur_block->successor_blocks.push_back(successor_block_info); - catch_block->predecessors.push_back(cur_block->id); - } - in_try_block = (cur_block->successor_block_list_type != kNotUsed); - } - bool build_all_edges = - (cu_->disable_opt & (1 << kSuppressExceptionEdges)) || is_throw || in_try_block; - if (!in_try_block && build_all_edges) { - BasicBlock* eh_block = CreateNewBB(kExceptionHandling); - cur_block->taken = eh_block->id; - eh_block->start_offset = cur_offset; - eh_block->predecessors.push_back(cur_block->id); - } - - if (is_throw) { - cur_block->explicit_throw = true; - if (code_ptr < code_end) { - // Force creation of new block following THROW via side-effect. - FindBlock(cur_offset + width, /* create */ true, /* immed_pred_block_p */ nullptr, dex_pc_to_block_map); - } - if (!in_try_block) { - // Don't split a THROW that can't rethrow - we're done. - return cur_block; - } - } - - if (!build_all_edges) { - /* - * Even though there is an exception edge here, control cannot return to this - * method. Thus, for the purposes of dataflow analysis and optimization, we can - * ignore the edge. Doing this reduces compile time, and increases the scope - * of the basic-block level optimization pass. - */ - return cur_block; - } - - /* - * Split the potentially-throwing instruction into two parts. - * The first half will be a pseudo-op that captures the exception - * edges and terminates the basic block. It always falls through. - * Then, create a new basic block that begins with the throwing instruction - * (minus exceptions). Note: this new basic block must NOT be entered into - * the block_map. If the potentially-throwing instruction is the target of a - * future branch, we need to find the check psuedo half. The new - * basic block containing the work portion of the instruction should - * only be entered via fallthrough from the block containing the - * 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 = CreateNewBB(kDalvikByteCode); - new_block->start_offset = insn->offset; - cur_block->fall_through = new_block->id; - new_block->predecessors.push_back(cur_block->id); - MIR* new_insn = NewMIR(); - *new_insn = *insn; - insn->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpCheck); - // Associate the two halves. - insn->meta.throw_insn = new_insn; - new_block->AppendMIR(new_insn); - return new_block; -} - -/* 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 ATTRIBUTE_UNUSED, uint16_t class_def_idx, - uint32_t method_idx, jobject class_loader, const DexFile& dex_file, - Handle<mirror::DexCache> dex_cache) { - current_code_item_ = code_item; - method_stack_.push_back(std::make_pair(current_method_, current_offset_)); - current_method_ = m_units_.size(); - current_offset_ = 0; - // TODO: will need to snapshot stack image and use that as the mir context identification. - m_units_.push_back(new (arena_) DexCompilationUnit( - cu_, class_loader, Runtime::Current()->GetClassLinker(), dex_file, current_code_item_, - class_def_idx, method_idx, access_flags, - cu_->compiler_driver->GetVerifiedMethod(&dex_file, method_idx), dex_cache)); - const uint16_t* code_ptr = current_code_item_->insns_; - const uint16_t* code_end = - 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_.reserve(block_list_.size() + current_code_item_->insns_size_in_code_units_); - // FindBlock lookup cache. - ScopedArenaAllocator allocator(&cu_->arena_stack); - ScopedArenaVector<uint16_t> dex_pc_to_block_map(allocator.Adapter()); - dex_pc_to_block_map.resize(current_code_item_->insns_size_in_code_units_ + - 1 /* Fall-through on last insn; dead or punt to interpreter. */); - - // 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_); - - // If this is the first method, set up default entry and exit blocks. - if (current_method_ == 0) { - DCHECK(entry_block_ == nullptr); - DCHECK(exit_block_ == nullptr); - DCHECK_EQ(GetNumBlocks(), 0U); - // Use id 0 to represent a null block. - BasicBlock* null_block = CreateNewBB(kNullBlock); - DCHECK_EQ(null_block->id, NullBasicBlockId); - null_block->hidden = true; - entry_block_ = CreateNewBB(kEntryBlock); - exit_block_ = CreateNewBB(kExitBlock); - } else { - UNIMPLEMENTED(FATAL) << "Nested inlining not implemented."; - /* - * Will need to manage storage for ins & outs, push prevous state and update - * insert point. - */ - } - - /* Current block to record parsed instructions */ - BasicBlock* cur_block = CreateNewBB(kDalvikByteCode); - DCHECK_EQ(current_offset_, 0U); - cur_block->start_offset = current_offset_; - // TODO: for inlining support, insert at the insert point rather than entry block. - entry_block_->fall_through = cur_block->id; - cur_block->predecessors.push_back(entry_block_->id); - - /* Identify code range in try blocks and set up the empty catch blocks */ - ProcessTryCatchBlocks(&dex_pc_to_block_map); - - uint64_t merged_df_flags = 0u; - - /* Parse all instructions and put them into containing basic blocks */ - while (code_ptr < code_end) { - MIR *insn = NewMIR(); - insn->offset = current_offset_; - insn->m_unit_index = current_method_; - int width = ParseInsn(code_ptr, &insn->dalvikInsn); - Instruction::Code opcode = insn->dalvikInsn.opcode; - if (opcode_count_ != nullptr) { - opcode_count_[static_cast<int>(opcode)]++; - } - - int flags = insn->dalvikInsn.FlagsOf(); - int verify_flags = Instruction::VerifyFlagsOf(insn->dalvikInsn.opcode); - - uint64_t df_flags = GetDataFlowAttributes(insn); - merged_df_flags |= df_flags; - - if (df_flags & DF_HAS_DEFS) { - def_count_ += (df_flags & DF_A_WIDE) ? 2 : 1; - } - - if (df_flags & DF_LVN) { - cur_block->use_lvn = true; // Run local value numbering on this basic block. - } - - // Check for inline data block signatures. - if (opcode == Instruction::NOP) { - // A simple NOP will have a width of 1 at this point, embedded data NOP > 1. - if ((width == 1) && ((current_offset_ & 0x1) == 0x1) && ((code_end - code_ptr) > 1)) { - // Could be an aligning nop. If an embedded data NOP follows, treat pair as single unit. - uint16_t following_raw_instruction = code_ptr[1]; - if ((following_raw_instruction == Instruction::kSparseSwitchSignature) || - (following_raw_instruction == Instruction::kPackedSwitchSignature) || - (following_raw_instruction == Instruction::kArrayDataSignature)) { - width += Instruction::At(code_ptr + 1)->SizeInCodeUnits(); - } - } - if (width == 1) { - // It is a simple nop - treat normally. - cur_block->AppendMIR(insn); - } else { - DCHECK(cur_block->fall_through == NullBasicBlockId); - DCHECK(cur_block->taken == NullBasicBlockId); - // Unreachable instruction, mark for no continuation and end basic block. - flags &= ~Instruction::kContinue; - FindBlock(current_offset_ + width, /* create */ true, - /* immed_pred_block_p */ nullptr, &dex_pc_to_block_map); - } - } else { - cur_block->AppendMIR(insn); - } - - // Associate the starting dex_pc for this opcode with its containing basic block. - dex_pc_to_block_map[insn->offset] = cur_block->id; - - code_ptr += width; - - if (flags & Instruction::kBranch) { - cur_block = ProcessCanBranch(cur_block, insn, current_offset_, - width, flags, code_ptr, code_end, &dex_pc_to_block_map); - } else if (flags & Instruction::kReturn) { - cur_block->terminated_by_return = true; - cur_block->fall_through = exit_block_->id; - exit_block_->predecessors.push_back(cur_block->id); - /* - * Terminate the current block if there are instructions - * afterwards. - */ - if (code_ptr < code_end) { - /* - * Create a fallthrough block for real instructions - * (incl. NOP). - */ - FindBlock(current_offset_ + width, /* create */ true, - /* immed_pred_block_p */ nullptr, &dex_pc_to_block_map); - } - } else if (flags & Instruction::kThrow) { - cur_block = ProcessCanThrow(cur_block, insn, current_offset_, width, flags, try_block_addr_, - code_ptr, code_end, &dex_pc_to_block_map); - } else if (flags & Instruction::kSwitch) { - cur_block = ProcessCanSwitch(cur_block, insn, current_offset_, width, - flags, &dex_pc_to_block_map); - } - if (verify_flags & Instruction::kVerifyVarArgRange || - verify_flags & Instruction::kVerifyVarArgRangeNonZero) { - /* - * The Quick backend's runtime model includes a gap between a method's - * argument ("in") vregs and the rest of its vregs. Handling a range instruction - * which spans the gap is somewhat complicated, and should not happen - * in normal usage of dx. Punt to the interpreter. - */ - int first_reg_in_range = insn->dalvikInsn.vC; - int last_reg_in_range = first_reg_in_range + insn->dalvikInsn.vA - 1; - if (IsInVReg(first_reg_in_range) != IsInVReg(last_reg_in_range)) { - punt_to_interpreter_ = true; - } - } - current_offset_ += width; - BasicBlock* next_block = FindBlock(current_offset_, /* create */ false, - /* immed_pred_block_p */ nullptr, - &dex_pc_to_block_map); - if (next_block) { - /* - * The next instruction could be the target of a previously parsed - * forward branch so a block is already created. If the current - * instruction is not an unconditional branch, connect them through - * the fall-through link. - */ - 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 == NullBasicBlockId) && (flags & Instruction::kContinue)) { - cur_block->fall_through = next_block->id; - next_block->predecessors.push_back(cur_block->id); - } - cur_block = next_block; - } - } - merged_df_flags_ = merged_df_flags; - - if (cu_->enable_debug & (1 << kDebugDumpCFG)) { - DumpCFG("/sdcard/1_post_parse_cfg/", true); - } - - if (cu_->verbose) { - DumpMIRGraph(); - } - - // Check if there's been a fall-through out of the method code. - BasicBlockId out_bb_id = dex_pc_to_block_map[current_code_item_->insns_size_in_code_units_]; - if (UNLIKELY(out_bb_id != NullBasicBlockId)) { - // Eagerly calculate DFS order to determine if the block is dead. - DCHECK(!DfsOrdersUpToDate()); - ComputeDFSOrders(); - BasicBlock* out_bb = GetBasicBlock(out_bb_id); - DCHECK(out_bb != nullptr); - if (out_bb->block_type != kDead) { - LOG(WARNING) << "Live fall-through out of method in " << PrettyMethod(method_idx, dex_file); - SetPuntToInterpreter(true); - } - } -} - -void MIRGraph::ShowOpcodeStats() { - DCHECK(opcode_count_ != nullptr); - LOG(INFO) << "Opcode Count"; - for (int i = 0; i < kNumPackedOpcodes; i++) { - if (opcode_count_[i] != 0) { - LOG(INFO) << "-C- " << Instruction::Name(static_cast<Instruction::Code>(i)) - << " " << opcode_count_[i]; - } - } -} - -uint64_t MIRGraph::GetDataFlowAttributes(Instruction::Code opcode) { - DCHECK_LT((size_t) opcode, (sizeof(oat_data_flow_attributes_) / sizeof(oat_data_flow_attributes_[0]))); - return oat_data_flow_attributes_[opcode]; -} - -uint64_t MIRGraph::GetDataFlowAttributes(MIR* mir) { - DCHECK(mir != nullptr); - Instruction::Code opcode = mir->dalvikInsn.opcode; - return GetDataFlowAttributes(opcode); -} - -// The path can easily surpass FS limits because of parameters etc. Use pathconf to get FS -// restrictions here. Note that a successful invocation will return an actual value. If the path -// is too long for some reason, the return will be ENAMETOOLONG. Then cut off part of the name. -// -// It's possible the path is not valid, or some other errors appear. In that case return false. -static bool CreateDumpFile(std::string& fname, const char* dir_prefix, NarrowDexOffset start_offset, - const char *suffix, int nr, std::string* output) { - std::string dir = StringPrintf("./%s", dir_prefix); - int64_t max_name_length = pathconf(dir.c_str(), _PC_NAME_MAX); - if (max_name_length <= 0) { - PLOG(ERROR) << "Could not get file name restrictions for " << dir; - return false; - } - - std::string name = StringPrintf("%s%x%s_%d.dot", fname.c_str(), start_offset, - suffix == nullptr ? "" : suffix, nr); - std::string fpath; - if (static_cast<int64_t>(name.size()) > max_name_length) { - std::string suffix_str = StringPrintf("_%d.dot", nr); - name = name.substr(0, static_cast<size_t>(max_name_length) - suffix_str.size()) + suffix_str; - } - // Sanity check. - DCHECK_LE(name.size(), static_cast<size_t>(max_name_length)); - - *output = StringPrintf("%s%s", dir_prefix, name.c_str()); - return true; -} - -// TODO: use a configurable base prefix, and adjust callers to supply pass name. -/* Dump the CFG into a DOT graph */ -void MIRGraph::DumpCFG(const char* dir_prefix, bool all_blocks, const char *suffix) { - FILE* file; - static AtomicInteger cnt(0); - - // Increment counter to get a unique file number. - cnt++; - int nr = cnt.LoadRelaxed(); - - std::string fname(PrettyMethod(cu_->method_idx, *cu_->dex_file)); - ReplaceSpecialChars(fname); - std::string fpath; - if (!CreateDumpFile(fname, dir_prefix, GetBasicBlock(GetEntryBlock()->fall_through)->start_offset, - suffix, nr, &fpath)) { - LOG(ERROR) << "Could not create dump file name for " << fname; - return; - } - file = fopen(fpath.c_str(), "w"); - if (file == nullptr) { - PLOG(ERROR) << "Could not open " << fpath << " for DumpCFG."; - return; - } - fprintf(file, "digraph G {\n"); - - fprintf(file, " rankdir=TB\n"); - - int num_blocks = all_blocks ? GetNumBlocks() : num_reachable_blocks_; - int idx; - - for (idx = 0; idx < num_blocks; idx++) { - int block_idx = all_blocks ? idx : dfs_order_[idx]; - BasicBlock* bb = GetBasicBlock(block_idx); - if (bb == nullptr) continue; - if (bb->block_type == kDead) continue; - if (bb->hidden) continue; - if (bb->block_type == kEntryBlock) { - fprintf(file, " entry_%d [shape=Mdiamond];\n", bb->id); - } else if (bb->block_type == kExitBlock) { - fprintf(file, " exit_%d [shape=Mdiamond];\n", bb->id); - } else if (bb->block_type == kDalvikByteCode) { - fprintf(file, " block%04x_%d [shape=record,label = \"{ \\\n", - bb->start_offset, bb->id); - const MIR* mir; - fprintf(file, " {block id %d\\l}%s\\\n", bb->id, - bb->first_mir_insn ? " | " : " "); - for (mir = bb->first_mir_insn; mir; mir = mir->next) { - int opcode = mir->dalvikInsn.opcode; - fprintf(file, " {%04x %s %s %s %s %s %s %s %s %s\\l}%s\\\n", mir->offset, - mir->ssa_rep ? GetDalvikDisassembly(mir) : - !MIR::DecodedInstruction::IsPseudoMirOp(opcode) ? - Instruction::Name(mir->dalvikInsn.opcode) : - extended_mir_op_names_[opcode - kMirOpFirst], - (mir->optimization_flags & MIR_IGNORE_RANGE_CHECK) != 0 ? " no_rangecheck" : " ", - (mir->optimization_flags & MIR_IGNORE_NULL_CHECK) != 0 ? " no_nullcheck" : " ", - (mir->optimization_flags & MIR_IGNORE_SUSPEND_CHECK) != 0 ? " no_suspendcheck" : " ", - (mir->optimization_flags & MIR_STORE_NON_TEMPORAL) != 0 ? " non_temporal" : " ", - (mir->optimization_flags & MIR_CALLEE) != 0 ? " inlined" : " ", - (mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0 ? " cl_inited" : " ", - (mir->optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0 ? " cl_in_cache" : " ", - (mir->optimization_flags & MIR_IGNORE_DIV_ZERO_CHECK) != 0 ? " no_div_check" : " ", - mir->next ? " | " : " "); - } - fprintf(file, " }\"];\n\n"); - } else if (bb->block_type == kExceptionHandling) { - char block_name[BLOCK_NAME_LEN]; - - GetBlockName(bb, block_name); - fprintf(file, " %s [shape=invhouse];\n", block_name); - } - - char block_name1[BLOCK_NAME_LEN], block_name2[BLOCK_NAME_LEN]; - - if (bb->taken != NullBasicBlockId) { - GetBlockName(bb, block_name1); - GetBlockName(GetBasicBlock(bb->taken), block_name2); - fprintf(file, " %s:s -> %s:n [style=dotted]\n", - block_name1, block_name2); - } - if (bb->fall_through != NullBasicBlockId) { - GetBlockName(bb, block_name1); - GetBlockName(GetBasicBlock(bb->fall_through), block_name2); - fprintf(file, " %s:s -> %s:n\n", block_name1, block_name2); - } - - 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_type == kCatch) ? "Mrecord" : "record"); - - int last_succ_id = static_cast<int>(bb->successor_blocks.size() - 1u); - int succ_id = 0; - for (SuccessorBlockInfo* successor_block_info : bb->successor_blocks) { - BasicBlock* dest_block = GetBasicBlock(successor_block_info->block); - fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n", - succ_id, - successor_block_info->key, - dest_block->start_offset, - (succ_id != last_succ_id) ? " | " : " "); - ++succ_id; - } - fprintf(file, " }\"];\n\n"); - - GetBlockName(bb, block_name1); - fprintf(file, " %s:s -> succ%04x_%d:n [style=dashed]\n", - block_name1, bb->start_offset, bb->id); - - // Link the successor pseudo-block with all of its potential targets. - succ_id = 0; - for (SuccessorBlockInfo* successor_block_info : bb->successor_blocks) { - 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, - bb->id, succ_id++, block_name2); - } - } - fprintf(file, "\n"); - - if (cu_->verbose) { - /* Display the dominator tree */ - GetBlockName(bb, block_name1); - fprintf(file, " cfg%s [label=\"%s\", shape=none];\n", - block_name1, block_name1); - if (bb->i_dom) { - GetBlockName(GetBasicBlock(bb->i_dom), block_name2); - fprintf(file, " cfg%s:s -> cfg%s:n\n\n", block_name2, block_name1); - } - } - } - fprintf(file, "}\n"); - fclose(file); -} - -/* Insert an MIR instruction to the end of a basic block. */ -void BasicBlock::AppendMIR(MIR* mir) { - // Insert it after the last MIR. - InsertMIRListAfter(last_mir_insn, mir, mir); -} - -void BasicBlock::AppendMIRList(MIR* first_list_mir, MIR* last_list_mir) { - // Insert it after the last MIR. - InsertMIRListAfter(last_mir_insn, first_list_mir, last_list_mir); -} - -void BasicBlock::AppendMIRList(const std::vector<MIR*>& insns) { - for (std::vector<MIR*>::const_iterator it = insns.begin(); it != insns.end(); it++) { - MIR* new_mir = *it; - - // Add a copy of each MIR. - InsertMIRListAfter(last_mir_insn, new_mir, new_mir); - } -} - -/* Insert a MIR instruction after the specified MIR. */ -void BasicBlock::InsertMIRAfter(MIR* current_mir, MIR* new_mir) { - InsertMIRListAfter(current_mir, new_mir, new_mir); -} - -void BasicBlock::InsertMIRListAfter(MIR* insert_after, MIR* first_list_mir, MIR* last_list_mir) { - // If no MIR, we are done. - if (first_list_mir == nullptr || last_list_mir == nullptr) { - return; - } - - // If insert_after is null, assume BB is empty. - if (insert_after == nullptr) { - first_mir_insn = first_list_mir; - last_mir_insn = last_list_mir; - last_list_mir->next = nullptr; - } else { - MIR* after_list = insert_after->next; - insert_after->next = first_list_mir; - last_list_mir->next = after_list; - if (after_list == nullptr) { - last_mir_insn = last_list_mir; - } - } - - // Set this BB to be the basic block of the MIRs. - MIR* last = last_list_mir->next; - for (MIR* mir = first_list_mir; mir != last; mir = mir->next) { - mir->bb = id; - } -} - -/* Insert an MIR instruction to the head of a basic block. */ -void BasicBlock::PrependMIR(MIR* mir) { - InsertMIRListBefore(first_mir_insn, mir, mir); -} - -void BasicBlock::PrependMIRList(MIR* first_list_mir, MIR* last_list_mir) { - // Insert it before the first MIR. - InsertMIRListBefore(first_mir_insn, first_list_mir, last_list_mir); -} - -void BasicBlock::PrependMIRList(const std::vector<MIR*>& to_add) { - for (std::vector<MIR*>::const_iterator it = to_add.begin(); it != to_add.end(); it++) { - MIR* mir = *it; - - InsertMIRListBefore(first_mir_insn, mir, mir); - } -} - -/* Insert a MIR instruction before the specified MIR. */ -void BasicBlock::InsertMIRBefore(MIR* current_mir, MIR* new_mir) { - // Insert as a single element list. - return InsertMIRListBefore(current_mir, new_mir, new_mir); -} - -MIR* BasicBlock::FindPreviousMIR(MIR* mir) { - MIR* current = first_mir_insn; - - while (current != nullptr) { - MIR* next = current->next; - - if (next == mir) { - return current; - } - - current = next; - } - - return nullptr; -} - -void BasicBlock::InsertMIRListBefore(MIR* insert_before, MIR* first_list_mir, MIR* last_list_mir) { - // If no MIR, we are done. - if (first_list_mir == nullptr || last_list_mir == nullptr) { - return; - } - - // If insert_before is null, assume BB is empty. - if (insert_before == nullptr) { - first_mir_insn = first_list_mir; - last_mir_insn = last_list_mir; - last_list_mir->next = nullptr; - } else { - if (first_mir_insn == insert_before) { - last_list_mir->next = first_mir_insn; - first_mir_insn = first_list_mir; - } else { - // Find the preceding MIR. - MIR* before_list = FindPreviousMIR(insert_before); - DCHECK(before_list != nullptr); - before_list->next = first_list_mir; - last_list_mir->next = insert_before; - } - } - - // Set this BB to be the basic block of the MIRs. - for (MIR* mir = first_list_mir; mir != last_list_mir->next; mir = mir->next) { - mir->bb = id; - } -} - -bool BasicBlock::RemoveMIR(MIR* mir) { - // Remove as a single element list. - return RemoveMIRList(mir, mir); -} - -bool BasicBlock::RemoveMIRList(MIR* first_list_mir, MIR* last_list_mir) { - if (first_list_mir == nullptr) { - return false; - } - - // Try to find the MIR. - MIR* before_list = nullptr; - MIR* after_list = nullptr; - - // If we are removing from the beginning of the MIR list. - if (first_mir_insn == first_list_mir) { - before_list = nullptr; - } else { - before_list = FindPreviousMIR(first_list_mir); - if (before_list == nullptr) { - // We did not find the mir. - return false; - } - } - - // Remove the BB information and also find the after_list. - for (MIR* mir = first_list_mir; mir != last_list_mir->next; mir = mir->next) { - mir->bb = NullBasicBlockId; - } - - after_list = last_list_mir->next; - - // If there is nothing before the list, after_list is the first_mir. - if (before_list == nullptr) { - first_mir_insn = after_list; - } else { - before_list->next = after_list; - } - - // If there is nothing after the list, before_list is last_mir. - if (after_list == nullptr) { - last_mir_insn = before_list; - } - - return true; -} - -MIR* BasicBlock::GetFirstNonPhiInsn() { - MIR* mir = first_mir_insn; - while (mir != nullptr && static_cast<int>(mir->dalvikInsn.opcode) == kMirOpPhi) { - mir = mir->next; - } - return mir; -} - -MIR* BasicBlock::GetNextUnconditionalMir(MIRGraph* mir_graph, MIR* current) { - MIR* next_mir = nullptr; - - if (current != nullptr) { - next_mir = current->next; - } - - if (next_mir == nullptr) { - // Only look for next MIR that follows unconditionally. - if ((taken == NullBasicBlockId) && (fall_through != NullBasicBlockId)) { - next_mir = mir_graph->GetBasicBlock(fall_through)->first_mir_insn; - } - } - - return next_mir; -} - -static void FillTypeSizeString(uint32_t type_size, std::string* decoded_mir) { - DCHECK(decoded_mir != nullptr); - OpSize type = static_cast<OpSize>(type_size >> 16); - uint16_t vect_size = (type_size & 0xFFFF); - - // Now print the type and vector size. - std::stringstream ss; - ss << " (type:"; - ss << type; - ss << " vectsize:"; - ss << vect_size; - ss << ")"; - - decoded_mir->append(ss.str()); -} - -void MIRGraph::DisassembleExtendedInstr(const MIR* mir, std::string* decoded_mir) { - DCHECK(decoded_mir != nullptr); - int opcode = mir->dalvikInsn.opcode; - SSARepresentation* ssa_rep = mir->ssa_rep; - int defs = (ssa_rep != nullptr) ? ssa_rep->num_defs : 0; - int uses = (ssa_rep != nullptr) ? ssa_rep->num_uses : 0; - - if (opcode < kMirOpFirst) { - return; // It is not an extended instruction. - } - - decoded_mir->append(extended_mir_op_names_[opcode - kMirOpFirst]); - - switch (opcode) { - case kMirOpPhi: { - if (defs > 0 && uses > 0) { - BasicBlockId* incoming = mir->meta.phi_incoming; - decoded_mir->append(StringPrintf(" %s = (%s", - GetSSANameWithConst(ssa_rep->defs[0], true).c_str(), - GetSSANameWithConst(ssa_rep->uses[0], true).c_str())); - decoded_mir->append(StringPrintf(":%d", incoming[0])); - for (int i = 1; i < uses; i++) { - decoded_mir->append(StringPrintf(", %s:%d", GetSSANameWithConst(ssa_rep->uses[i], true).c_str(), incoming[i])); - } - decoded_mir->append(")"); - } - break; - } - case kMirOpCopy: - if (ssa_rep != nullptr) { - decoded_mir->append(" "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->defs[0], false)); - if (defs > 1) { - decoded_mir->append(", "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->defs[1], false)); - } - decoded_mir->append(" = "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->uses[0], false)); - if (uses > 1) { - decoded_mir->append(", "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->uses[1], false)); - } - } else { - decoded_mir->append(StringPrintf(" v%d = v%d", mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - } - break; - case kMirOpFusedCmplFloat: - case kMirOpFusedCmpgFloat: - case kMirOpFusedCmplDouble: - case kMirOpFusedCmpgDouble: - case kMirOpFusedCmpLong: - if (ssa_rep != nullptr) { - decoded_mir->append(" "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->uses[0], false)); - for (int i = 1; i < uses; i++) { - decoded_mir->append(", "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->uses[i], false)); - } - } else { - decoded_mir->append(StringPrintf(" v%d, v%d", mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - } - break; - case kMirOpMoveVector: - decoded_mir->append(StringPrintf(" vect%d = vect%d", mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpPackedAddition: - decoded_mir->append(StringPrintf(" vect%d = vect%d + vect%d", mir->dalvikInsn.vA, mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpPackedMultiply: - decoded_mir->append(StringPrintf(" vect%d = vect%d * vect%d", mir->dalvikInsn.vA, mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpPackedSubtract: - decoded_mir->append(StringPrintf(" vect%d = vect%d - vect%d", mir->dalvikInsn.vA, mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpPackedAnd: - decoded_mir->append(StringPrintf(" vect%d = vect%d & vect%d", mir->dalvikInsn.vA, mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpPackedOr: - decoded_mir->append(StringPrintf(" vect%d = vect%d \\| vect%d", mir->dalvikInsn.vA, mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpPackedXor: - decoded_mir->append(StringPrintf(" vect%d = vect%d ^ vect%d", mir->dalvikInsn.vA, mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpPackedShiftLeft: - decoded_mir->append(StringPrintf(" vect%d = vect%d \\<\\< %d", mir->dalvikInsn.vA, mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpPackedUnsignedShiftRight: - decoded_mir->append(StringPrintf(" vect%d = vect%d \\>\\>\\> %d", mir->dalvikInsn.vA, mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpPackedSignedShiftRight: - decoded_mir->append(StringPrintf(" vect%d = vect%d \\>\\> %d", mir->dalvikInsn.vA, mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpConstVector: - decoded_mir->append(StringPrintf(" vect%d = %x, %x, %x, %x", mir->dalvikInsn.vA, mir->dalvikInsn.arg[0], - mir->dalvikInsn.arg[1], mir->dalvikInsn.arg[2], mir->dalvikInsn.arg[3])); - break; - case kMirOpPackedSet: - if (ssa_rep != nullptr) { - decoded_mir->append(StringPrintf(" vect%d = %s", mir->dalvikInsn.vA, - GetSSANameWithConst(ssa_rep->uses[0], false).c_str())); - if (uses > 1) { - decoded_mir->append(", "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->uses[1], false)); - } - } else { - decoded_mir->append(StringPrintf(" vect%d = v%d", mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - } - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpPackedAddReduce: - if (ssa_rep != nullptr) { - decoded_mir->append(" "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->defs[0], false)); - if (defs > 1) { - decoded_mir->append(", "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->defs[1], false)); - } - decoded_mir->append(StringPrintf(" = vect%d + %s", mir->dalvikInsn.vB, - GetSSANameWithConst(ssa_rep->uses[0], false).c_str())); - if (uses > 1) { - decoded_mir->append(", "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->uses[1], false)); - } - } else { - decoded_mir->append(StringPrintf("v%d = vect%d + v%d", mir->dalvikInsn.vA, mir->dalvikInsn.vB, mir->dalvikInsn.vA)); - } - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpPackedReduce: - if (ssa_rep != nullptr) { - decoded_mir->append(" "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->defs[0], false)); - if (defs > 1) { - decoded_mir->append(", "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->defs[1], false)); - } - decoded_mir->append(StringPrintf(" = vect%d (extr_idx:%d)", mir->dalvikInsn.vB, mir->dalvikInsn.arg[0])); - } else { - decoded_mir->append(StringPrintf(" v%d = vect%d (extr_idx:%d)", mir->dalvikInsn.vA, - mir->dalvikInsn.vB, mir->dalvikInsn.arg[0])); - } - FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir); - break; - case kMirOpReserveVectorRegisters: - case kMirOpReturnVectorRegisters: - decoded_mir->append(StringPrintf(" vect%d - vect%d", mir->dalvikInsn.vA, mir->dalvikInsn.vB)); - break; - case kMirOpMemBarrier: { - decoded_mir->append(" type:"); - std::stringstream ss; - ss << static_cast<MemBarrierKind>(mir->dalvikInsn.vA); - decoded_mir->append(ss.str()); - break; - } - case kMirOpPackedArrayGet: - case kMirOpPackedArrayPut: - decoded_mir->append(StringPrintf(" vect%d", mir->dalvikInsn.vA)); - if (ssa_rep != nullptr) { - decoded_mir->append(StringPrintf(", %s[%s]", - GetSSANameWithConst(ssa_rep->uses[0], false).c_str(), - GetSSANameWithConst(ssa_rep->uses[1], false).c_str())); - } else { - decoded_mir->append(StringPrintf(", v%d[v%d]", mir->dalvikInsn.vB, mir->dalvikInsn.vC)); - } - FillTypeSizeString(mir->dalvikInsn.arg[0], decoded_mir); - break; - case kMirOpMaddInt: - case kMirOpMsubInt: - case kMirOpMaddLong: - case kMirOpMsubLong: - if (ssa_rep != nullptr) { - decoded_mir->append(" "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->defs[0], false)); - if (defs > 1) { - decoded_mir->append(", "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->defs[1], false)); - } - for (int i = 0; i < uses; i++) { - decoded_mir->append(", "); - decoded_mir->append(GetSSANameWithConst(ssa_rep->uses[i], false)); - } - } else { - decoded_mir->append(StringPrintf(" v%d, v%d, v%d, v%d", - mir->dalvikInsn.vA, mir->dalvikInsn.vB, - mir->dalvikInsn.vC, mir->dalvikInsn.arg[0])); - } - break; - default: - break; - } -} - -char* MIRGraph::GetDalvikDisassembly(const MIR* mir) { - MIR::DecodedInstruction insn = mir->dalvikInsn; - std::string str; - int flags = 0; - int opcode = insn.opcode; - char* ret; - bool nop = false; - SSARepresentation* ssa_rep = mir->ssa_rep; - Instruction::Format dalvik_format = Instruction::k10x; // Default to no-operand format. - - // Handle special cases that recover the original dalvik instruction. - if (opcode == kMirOpCheck) { - str.append(extended_mir_op_names_[opcode - kMirOpFirst]); - str.append(": "); - // Recover the original Dex instruction. - insn = mir->meta.throw_insn->dalvikInsn; - ssa_rep = mir->meta.throw_insn->ssa_rep; - opcode = insn.opcode; - } else if (opcode == kMirOpNop) { - str.append("["); - if (mir->offset < current_code_item_->insns_size_in_code_units_) { - // Recover original opcode. - insn.opcode = Instruction::At(current_code_item_->insns_ + mir->offset)->Opcode(); - opcode = insn.opcode; - } - nop = true; - } - int defs = (ssa_rep != nullptr) ? ssa_rep->num_defs : 0; - int uses = (ssa_rep != nullptr) ? ssa_rep->num_uses : 0; - - if (MIR::DecodedInstruction::IsPseudoMirOp(opcode)) { - // Note that this does not check the MIR's opcode in all cases. In cases where it - // recovered dalvik instruction, it uses opcode of that instead of the extended one. - DisassembleExtendedInstr(mir, &str); - } else { - dalvik_format = Instruction::FormatOf(insn.opcode); - flags = insn.FlagsOf(); - str.append(Instruction::Name(insn.opcode)); - - // For invokes-style formats, treat wide regs as a pair of singles. - bool show_singles = ((dalvik_format == Instruction::k35c) || - (dalvik_format == Instruction::k3rc)); - if (defs != 0) { - str.append(" "); - str.append(GetSSANameWithConst(ssa_rep->defs[0], false)); - if (defs > 1) { - str.append(", "); - str.append(GetSSANameWithConst(ssa_rep->defs[1], false)); - } - if (uses != 0) { - str.append(", "); - } - } - for (int i = 0; i < uses; i++) { - str.append(" "); - str.append(GetSSANameWithConst(ssa_rep->uses[i], show_singles)); - if (!show_singles && (reg_location_ != nullptr) && reg_location_[i].wide) { - // For the listing, skip the high sreg. - i++; - } - if (i != (uses - 1)) { - str.append(","); - } - } - - switch (dalvik_format) { - case Instruction::k11n: // Add one immediate from vB. - case Instruction::k21s: - case Instruction::k31i: - case Instruction::k21h: - str.append(StringPrintf(", #0x%x", insn.vB)); - break; - case Instruction::k51l: // Add one wide immediate. - str.append(StringPrintf(", #%" PRId64, insn.vB_wide)); - break; - case Instruction::k21c: // One register, one string/type/method index. - case Instruction::k31c: - str.append(StringPrintf(", index #0x%x", insn.vB)); - break; - case Instruction::k22c: // Two registers, one string/type/method index. - str.append(StringPrintf(", index #0x%x", insn.vC)); - break; - case Instruction::k22s: // Add one immediate from vC. - case Instruction::k22b: - str.append(StringPrintf(", #0x%x", insn.vC)); - break; - default: - // Nothing left to print. - break; - } - - if ((flags & Instruction::kBranch) != 0) { - // For branches, decode the instructions to print out the branch targets. - int offset = 0; - switch (dalvik_format) { - case Instruction::k21t: - offset = insn.vB; - break; - case Instruction::k22t: - offset = insn.vC; - break; - case Instruction::k10t: - case Instruction::k20t: - case Instruction::k30t: - offset = insn.vA; - break; - default: - LOG(FATAL) << "Unexpected branch format " << dalvik_format << " from " << insn.opcode; - break; - } - str.append(StringPrintf(", 0x%x (%c%x)", mir->offset + offset, - offset > 0 ? '+' : '-', offset > 0 ? offset : -offset)); - } - - if (nop) { - str.append("]--optimized away"); - } - } - int length = str.length() + 1; - ret = arena_->AllocArray<char>(length, kArenaAllocDFInfo); - strncpy(ret, str.c_str(), length); - return ret; -} - -/* Turn method name into a legal Linux file name */ -void MIRGraph::ReplaceSpecialChars(std::string& str) { - static const struct { const char before; const char after; } match[] = { - {'/', '-'}, {';', '#'}, {' ', '#'}, {'$', '+'}, - {'(', '@'}, {')', '@'}, {'<', '='}, {'>', '='} - }; - for (unsigned int i = 0; i < sizeof(match)/sizeof(match[0]); i++) { - std::replace(str.begin(), str.end(), match[i].before, match[i].after); - } -} - -std::string MIRGraph::GetSSAName(int ssa_reg) { - // TODO: This value is needed for debugging. Currently, we compute this and then copy to the - // arena. We should be smarter and just place straight into the arena, or compute the - // value more lazily. - int vreg = SRegToVReg(ssa_reg); - if (vreg >= static_cast<int>(GetFirstTempVR())) { - return StringPrintf("t%d_%d", SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg)); - } else { - return StringPrintf("v%d_%d", SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg)); - } -} - -// Similar to GetSSAName, but if ssa name represents an immediate show that as well. -std::string MIRGraph::GetSSANameWithConst(int ssa_reg, bool singles_only) { - if (reg_location_ == nullptr) { - // Pre-SSA - just use the standard name. - return GetSSAName(ssa_reg); - } - if (IsConst(reg_location_[ssa_reg])) { - if (!singles_only && reg_location_[ssa_reg].wide && - !reg_location_[ssa_reg].high_word) { - return StringPrintf("v%d_%d#0x%" PRIx64, SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg), - ConstantValueWide(reg_location_[ssa_reg])); - } else { - return StringPrintf("v%d_%d#0x%x", SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg), - ConstantValue(reg_location_[ssa_reg])); - } - } else { - int vreg = SRegToVReg(ssa_reg); - if (vreg >= static_cast<int>(GetFirstTempVR())) { - return StringPrintf("t%d_%d", SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg)); - } else { - return StringPrintf("v%d_%d", SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg)); - } - } -} - -void MIRGraph::GetBlockName(BasicBlock* bb, char* name) { - switch (bb->block_type) { - case kEntryBlock: - snprintf(name, BLOCK_NAME_LEN, "entry_%d", bb->id); - break; - case kExitBlock: - snprintf(name, BLOCK_NAME_LEN, "exit_%d", bb->id); - break; - case kDalvikByteCode: - snprintf(name, BLOCK_NAME_LEN, "block%04x_%d", bb->start_offset, bb->id); - break; - case kExceptionHandling: - snprintf(name, BLOCK_NAME_LEN, "exception%04x_%d", bb->start_offset, - bb->id); - break; - default: - snprintf(name, BLOCK_NAME_LEN, "_%d", bb->id); - break; - } -} - -const char* MIRGraph::GetShortyFromMethodReference(const MethodReference& target_method) { - const DexFile::MethodId& method_id = - target_method.dex_file->GetMethodId(target_method.dex_method_index); - return target_method.dex_file->GetShorty(method_id.proto_idx_); -} - -/* Debug Utility - dump a compilation unit */ -void MIRGraph::DumpMIRGraph() { - const char* block_type_names[] = { - "Null Block", - "Entry Block", - "Code Block", - "Exit Block", - "Exception Handling", - "Catch Block" - }; - - LOG(INFO) << "Compiling " << PrettyMethod(cu_->method_idx, *cu_->dex_file); - LOG(INFO) << GetInsns(0) << " insns"; - LOG(INFO) << GetNumBlocks() << " blocks in total"; - - for (BasicBlock* bb : block_list_) { - LOG(INFO) << StringPrintf("Block %d (%s) (insn %04x - %04x%s)", - bb->id, - block_type_names[bb->block_type], - bb->start_offset, - bb->last_mir_insn ? bb->last_mir_insn->offset : bb->start_offset, - bb->last_mir_insn ? "" : " empty"); - if (bb->taken != NullBasicBlockId) { - LOG(INFO) << " Taken branch: block " << bb->taken - << "(0x" << std::hex << GetBasicBlock(bb->taken)->start_offset << ")"; - } - if (bb->fall_through != NullBasicBlockId) { - LOG(INFO) << " Fallthrough : block " << bb->fall_through - << " (0x" << std::hex << GetBasicBlock(bb->fall_through)->start_offset << ")"; - } - } -} - -/* - * Build an array of location records for the incoming arguments. - * Note: one location record per word of arguments, with dummy - * high-word loc for wide arguments. Also pull up any following - * MOVE_RESULT and incorporate it into the invoke. - */ -CallInfo* MIRGraph::NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, bool is_range) { - CallInfo* info = static_cast<CallInfo*>(arena_->Alloc(sizeof(CallInfo), - kArenaAllocMisc)); - MIR* move_result_mir = FindMoveResult(bb, mir); - if (move_result_mir == nullptr) { - info->result.location = kLocInvalid; - } else { - info->result = GetRawDest(move_result_mir); - move_result_mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop); - } - info->num_arg_words = mir->ssa_rep->num_uses; - info->args = (info->num_arg_words == 0) ? nullptr : - arena_->AllocArray<RegLocation>(info->num_arg_words, kArenaAllocMisc); - for (size_t i = 0; i < info->num_arg_words; i++) { - info->args[i] = GetRawSrc(mir, i); - } - info->opt_flags = mir->optimization_flags; - info->type = type; - info->is_range = is_range; - if (IsInstructionQuickInvoke(mir->dalvikInsn.opcode)) { - const auto& method_info = GetMethodLoweringInfo(mir); - info->method_ref = method_info.GetTargetMethod(); - } else { - info->method_ref = MethodReference(GetCurrentDexCompilationUnit()->GetDexFile(), - mir->dalvikInsn.vB); - } - info->index = mir->dalvikInsn.vB; - info->offset = mir->offset; - info->mir = mir; - return info; -} - -// Allocate a new MIR. -MIR* MIRGraph::NewMIR() { - MIR* mir = new (arena_) MIR(); - return mir; -} - -// Allocate a new basic block. -BasicBlock* MIRGraph::NewMemBB(BBType block_type, int block_id) { - BasicBlock* bb = new (arena_) BasicBlock(block_id, block_type, arena_); - - // TUNING: better estimate of the exit block predecessors? - bb->predecessors.reserve((block_type == kExitBlock) ? 2048 : 2); - block_id_map_.Put(block_id, block_id); - return bb; -} - -void MIRGraph::InitializeConstantPropagation() { - is_constant_v_ = new (arena_) ArenaBitVector(arena_, GetNumSSARegs(), false); - constant_values_ = arena_->AllocArray<int>(GetNumSSARegs(), kArenaAllocDFInfo); -} - -void MIRGraph::InitializeMethodUses() { - // The gate starts by initializing the use counts. - int num_ssa_regs = GetNumSSARegs(); - use_counts_.clear(); - use_counts_.reserve(num_ssa_regs + 32); - use_counts_.resize(num_ssa_regs, 0u); - raw_use_counts_.clear(); - raw_use_counts_.reserve(num_ssa_regs + 32); - raw_use_counts_.resize(num_ssa_regs, 0u); -} - -void MIRGraph::SSATransformationStart() { - DCHECK(temp_scoped_alloc_.get() == nullptr); - temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack)); - temp_.ssa.num_vregs = GetNumOfCodeAndTempVRs(); - temp_.ssa.work_live_vregs = new (temp_scoped_alloc_.get()) ArenaBitVector( - temp_scoped_alloc_.get(), temp_.ssa.num_vregs, false); -} - -void MIRGraph::SSATransformationEnd() { - // Verify the dataflow information after the pass. - if (cu_->enable_debug & (1 << kDebugVerifyDataflow)) { - VerifyDataflow(); - } - - temp_.ssa.num_vregs = 0u; - temp_.ssa.work_live_vregs = nullptr; - DCHECK(temp_.ssa.def_block_matrix == nullptr); - temp_.ssa.phi_node_blocks = nullptr; - DCHECK(temp_scoped_alloc_.get() != nullptr); - temp_scoped_alloc_.reset(); - - // Update the maximum number of reachable blocks. - max_num_reachable_blocks_ = num_reachable_blocks_; - - // Mark MIR SSA representations as up to date. - mir_ssa_rep_up_to_date_ = true; -} - -size_t MIRGraph::GetNumDalvikInsns() const { - size_t cumulative_size = 0u; - bool counted_current_item = false; - const uint8_t size_for_null_code_item = 2u; - - for (auto it : m_units_) { - const DexFile::CodeItem* code_item = it->GetCodeItem(); - // Even if the code item is null, we still count non-zero value so that - // each m_unit is counted as having impact. - cumulative_size += (code_item == nullptr ? - size_for_null_code_item : code_item->insns_size_in_code_units_); - if (code_item == current_code_item_) { - counted_current_item = true; - } - } - - // If the current code item was not counted yet, count it now. - // This can happen for example in unit tests where some fields like m_units_ - // are not initialized. - if (counted_current_item == false) { - cumulative_size += (current_code_item_ == nullptr ? - size_for_null_code_item : current_code_item_->insns_size_in_code_units_); - } - - return cumulative_size; -} - -static BasicBlock* SelectTopologicalSortOrderFallBack( - MIRGraph* mir_graph, const ArenaBitVector* current_loop, - const ScopedArenaVector<size_t>* visited_cnt_values, ScopedArenaAllocator* allocator, - ScopedArenaVector<BasicBlockId>* tmp_stack) { - // No true loop head has been found but there may be true loop heads after the mess we need - // to resolve. To avoid taking one of those, pick the candidate with the highest number of - // reachable unvisited nodes. That candidate will surely be a part of a loop. - BasicBlock* fall_back = nullptr; - size_t fall_back_num_reachable = 0u; - // Reuse the same bit vector for each candidate to mark reachable unvisited blocks. - ArenaBitVector candidate_reachable(allocator, mir_graph->GetNumBlocks(), false); - AllNodesIterator iter(mir_graph); - for (BasicBlock* candidate = iter.Next(); candidate != nullptr; candidate = iter.Next()) { - if (candidate->hidden || // Hidden, or - candidate->visited || // already processed, or - (*visited_cnt_values)[candidate->id] == 0u || // no processed predecessors, or - (current_loop != nullptr && // outside current loop. - !current_loop->IsBitSet(candidate->id))) { - continue; - } - DCHECK(tmp_stack->empty()); - tmp_stack->push_back(candidate->id); - candidate_reachable.ClearAllBits(); - size_t num_reachable = 0u; - while (!tmp_stack->empty()) { - BasicBlockId current_id = tmp_stack->back(); - tmp_stack->pop_back(); - BasicBlock* current_bb = mir_graph->GetBasicBlock(current_id); - DCHECK(current_bb != nullptr); - ChildBlockIterator child_iter(current_bb, mir_graph); - BasicBlock* child_bb = child_iter.Next(); - for ( ; child_bb != nullptr; child_bb = child_iter.Next()) { - DCHECK(!child_bb->hidden); - if (child_bb->visited || // Already processed, or - (current_loop != nullptr && // outside current loop. - !current_loop->IsBitSet(child_bb->id))) { - continue; - } - if (!candidate_reachable.IsBitSet(child_bb->id)) { - candidate_reachable.SetBit(child_bb->id); - tmp_stack->push_back(child_bb->id); - num_reachable += 1u; - } - } - } - if (fall_back_num_reachable < num_reachable) { - fall_back_num_reachable = num_reachable; - fall_back = candidate; - } - } - return fall_back; -} - -// Compute from which unvisited blocks is bb_id reachable through unvisited blocks. -static void ComputeUnvisitedReachableFrom(MIRGraph* mir_graph, BasicBlockId bb_id, - ArenaBitVector* reachable, - ScopedArenaVector<BasicBlockId>* tmp_stack) { - // NOTE: Loop heads indicated by the "visited" flag. - DCHECK(tmp_stack->empty()); - reachable->ClearAllBits(); - tmp_stack->push_back(bb_id); - while (!tmp_stack->empty()) { - BasicBlockId current_id = tmp_stack->back(); - tmp_stack->pop_back(); - BasicBlock* current_bb = mir_graph->GetBasicBlock(current_id); - DCHECK(current_bb != nullptr); - for (BasicBlockId pred_id : current_bb->predecessors) { - BasicBlock* pred_bb = mir_graph->GetBasicBlock(pred_id); - DCHECK(pred_bb != nullptr); - if (!pred_bb->visited && !reachable->IsBitSet(pred_bb->id)) { - reachable->SetBit(pred_bb->id); - tmp_stack->push_back(pred_bb->id); - } - } - } -} - -void MIRGraph::ComputeTopologicalSortOrder() { - ScopedArenaAllocator allocator(&cu_->arena_stack); - unsigned int num_blocks = GetNumBlocks(); - - ScopedArenaQueue<BasicBlock*> q(allocator.Adapter()); - ScopedArenaVector<size_t> visited_cnt_values(num_blocks, 0u, allocator.Adapter()); - ScopedArenaVector<BasicBlockId> loop_head_stack(allocator.Adapter()); - size_t max_nested_loops = 0u; - ArenaBitVector loop_exit_blocks(&allocator, num_blocks, false); - loop_exit_blocks.ClearAllBits(); - - // Count the number of blocks to process and add the entry block(s). - unsigned int num_blocks_to_process = 0u; - for (BasicBlock* bb : block_list_) { - if (bb->hidden == true) { - continue; - } - - num_blocks_to_process += 1u; - - if (bb->predecessors.size() == 0u) { - // Add entry block to the queue. - q.push(bb); - } - } - - // Clear the topological order arrays. - topological_order_.clear(); - topological_order_.reserve(num_blocks); - topological_order_loop_ends_.clear(); - topological_order_loop_ends_.resize(num_blocks, 0u); - topological_order_indexes_.clear(); - topological_order_indexes_.resize(num_blocks, static_cast<uint16_t>(-1)); - - // Mark all blocks as unvisited. - ClearAllVisitedFlags(); - - // For loop heads, keep track from which blocks they are reachable not going through other - // loop heads. Other loop heads are excluded to detect the heads of nested loops. The children - // in this set go into the loop body, the other children are jumping over the loop. - ScopedArenaVector<ArenaBitVector*> loop_head_reachable_from(allocator.Adapter()); - loop_head_reachable_from.resize(num_blocks, nullptr); - // Reuse the same temp stack whenever calculating a loop_head_reachable_from[loop_head_id]. - ScopedArenaVector<BasicBlockId> tmp_stack(allocator.Adapter()); - - while (num_blocks_to_process != 0u) { - BasicBlock* bb = nullptr; - if (!q.empty()) { - num_blocks_to_process -= 1u; - // Get top. - bb = q.front(); - q.pop(); - if (bb->visited) { - // Loop head: it was already processed, mark end and copy exit blocks to the queue. - DCHECK(q.empty()) << PrettyMethod(cu_->method_idx, *cu_->dex_file); - uint16_t idx = static_cast<uint16_t>(topological_order_.size()); - topological_order_loop_ends_[topological_order_indexes_[bb->id]] = idx; - DCHECK_EQ(loop_head_stack.back(), bb->id); - loop_head_stack.pop_back(); - ArenaBitVector* reachable = - loop_head_stack.empty() ? nullptr : loop_head_reachable_from[loop_head_stack.back()]; - for (BasicBlockId candidate_id : loop_exit_blocks.Indexes()) { - if (reachable == nullptr || reachable->IsBitSet(candidate_id)) { - q.push(GetBasicBlock(candidate_id)); - // NOTE: The BitVectorSet::IndexIterator will not check the pointed-to bit again, - // so clearing the bit has no effect on the iterator. - loop_exit_blocks.ClearBit(candidate_id); - } - } - continue; - } - } else { - // Find the new loop head. - AllNodesIterator iter(this); - while (true) { - BasicBlock* candidate = iter.Next(); - if (candidate == nullptr) { - // We did not find a true loop head, fall back to a reachable block in any loop. - ArenaBitVector* current_loop = - loop_head_stack.empty() ? nullptr : loop_head_reachable_from[loop_head_stack.back()]; - bb = SelectTopologicalSortOrderFallBack(this, current_loop, &visited_cnt_values, - &allocator, &tmp_stack); - DCHECK(bb != nullptr) << PrettyMethod(cu_->method_idx, *cu_->dex_file); - if (kIsDebugBuild && cu_->dex_file != nullptr) { - LOG(INFO) << "Topological sort order: Using fall-back in " - << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " BB #" << bb->id - << " @0x" << std::hex << bb->start_offset - << ", num_blocks = " << std::dec << num_blocks; - } - break; - } - if (candidate->hidden || // Hidden, or - candidate->visited || // already processed, or - visited_cnt_values[candidate->id] == 0u || // no processed predecessors, or - (!loop_head_stack.empty() && // outside current loop. - !loop_head_reachable_from[loop_head_stack.back()]->IsBitSet(candidate->id))) { - continue; - } - - for (BasicBlockId pred_id : candidate->predecessors) { - BasicBlock* pred_bb = GetBasicBlock(pred_id); - DCHECK(pred_bb != nullptr); - if (pred_bb != candidate && !pred_bb->visited && - !pred_bb->dominators->IsBitSet(candidate->id)) { - candidate = nullptr; // Set candidate to null to indicate failure. - break; - } - } - if (candidate != nullptr) { - bb = candidate; - break; - } - } - // Compute blocks from which the loop head is reachable and process those blocks first. - ArenaBitVector* reachable = - new (&allocator) ArenaBitVector(&allocator, num_blocks, false); - loop_head_reachable_from[bb->id] = reachable; - ComputeUnvisitedReachableFrom(this, bb->id, reachable, &tmp_stack); - // Now mark as loop head. (Even if it's only a fall back when we don't find a true loop.) - loop_head_stack.push_back(bb->id); - max_nested_loops = std::max(max_nested_loops, loop_head_stack.size()); - } - - DCHECK_EQ(bb->hidden, false); - DCHECK_EQ(bb->visited, false); - bb->visited = true; - bb->nesting_depth = loop_head_stack.size(); - - // Now add the basic block. - uint16_t idx = static_cast<uint16_t>(topological_order_.size()); - topological_order_indexes_[bb->id] = idx; - topological_order_.push_back(bb->id); - - // Update visited_cnt_values for children. - ChildBlockIterator succIter(bb, this); - BasicBlock* successor = succIter.Next(); - for ( ; successor != nullptr; successor = succIter.Next()) { - if (successor->hidden) { - continue; - } - - // One more predecessor was visited. - visited_cnt_values[successor->id] += 1u; - if (visited_cnt_values[successor->id] == successor->predecessors.size()) { - if (loop_head_stack.empty() || - loop_head_reachable_from[loop_head_stack.back()]->IsBitSet(successor->id)) { - q.push(successor); - } else { - DCHECK(!loop_exit_blocks.IsBitSet(successor->id)); - loop_exit_blocks.SetBit(successor->id); - } - } - } - } - - // Prepare the loop head stack for iteration. - topological_order_loop_head_stack_.clear(); - topological_order_loop_head_stack_.reserve(max_nested_loops); - max_nested_loops_ = max_nested_loops; - topological_order_up_to_date_ = true; -} - -bool BasicBlock::IsExceptionBlock() const { - if (block_type == kExceptionHandling) { - return true; - } - return false; -} - -ChildBlockIterator::ChildBlockIterator(BasicBlock* bb, MIRGraph* mir_graph) - : basic_block_(bb), mir_graph_(mir_graph), visited_fallthrough_(false), - visited_taken_(false), have_successors_(false) { - // Check if we actually do have successors. - if (basic_block_ != 0 && basic_block_->successor_block_list_type != kNotUsed) { - have_successors_ = true; - successor_iter_ = basic_block_->successor_blocks.cbegin(); - } -} - -BasicBlock* ChildBlockIterator::Next() { - // We check if we have a basic block. If we don't we cannot get next child. - if (basic_block_ == nullptr) { - return nullptr; - } - - // If we haven't visited fallthrough, return that. - if (visited_fallthrough_ == false) { - visited_fallthrough_ = true; - - BasicBlock* result = mir_graph_->GetBasicBlock(basic_block_->fall_through); - if (result != nullptr) { - return result; - } - } - - // If we haven't visited taken, return that. - if (visited_taken_ == false) { - visited_taken_ = true; - - BasicBlock* result = mir_graph_->GetBasicBlock(basic_block_->taken); - if (result != nullptr) { - return result; - } - } - - // We visited both taken and fallthrough. Now check if we have successors we need to visit. - if (have_successors_ == true) { - // Get information about next successor block. - auto end = basic_block_->successor_blocks.cend(); - while (successor_iter_ != end) { - SuccessorBlockInfo* successor_block_info = *successor_iter_; - ++successor_iter_; - // If block was replaced by zero block, take next one. - if (successor_block_info->block != NullBasicBlockId) { - return mir_graph_->GetBasicBlock(successor_block_info->block); - } - } - } - - // We do not have anything. - return nullptr; -} - -BasicBlock* BasicBlock::Copy(CompilationUnit* c_unit) { - MIRGraph* mir_graph = c_unit->mir_graph.get(); - return Copy(mir_graph); -} - -BasicBlock* BasicBlock::Copy(MIRGraph* mir_graph) { - BasicBlock* result_bb = mir_graph->CreateNewBB(block_type); - - // We don't do a memcpy style copy here because it would lead to a lot of things - // to clean up. Let us do it by hand instead. - // Copy in taken and fallthrough. - result_bb->fall_through = fall_through; - result_bb->taken = taken; - - // Copy successor links if needed. - ArenaAllocator* arena = mir_graph->GetArena(); - - result_bb->successor_block_list_type = successor_block_list_type; - if (result_bb->successor_block_list_type != kNotUsed) { - result_bb->successor_blocks.reserve(successor_blocks.size()); - for (SuccessorBlockInfo* sbi_old : successor_blocks) { - SuccessorBlockInfo* sbi_new = static_cast<SuccessorBlockInfo*>( - arena->Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessors)); - memcpy(sbi_new, sbi_old, sizeof(SuccessorBlockInfo)); - result_bb->successor_blocks.push_back(sbi_new); - } - } - - // Copy offset, method. - result_bb->start_offset = start_offset; - - // Now copy instructions. - for (MIR* mir = first_mir_insn; mir != 0; mir = mir->next) { - // Get a copy first. - MIR* copy = mir->Copy(mir_graph); - - // Append it. - result_bb->AppendMIR(copy); - } - - return result_bb; -} - -MIR* MIR::Copy(MIRGraph* mir_graph) { - MIR* res = mir_graph->NewMIR(); - *res = *this; - - // Remove links - res->next = nullptr; - res->bb = NullBasicBlockId; - res->ssa_rep = nullptr; - - return res; -} - -MIR* MIR::Copy(CompilationUnit* c_unit) { - return Copy(c_unit->mir_graph.get()); -} - -uint32_t SSARepresentation::GetStartUseIndex(Instruction::Code opcode) { - // Default result. - int res = 0; - - // We are basically setting the iputs to their igets counterparts. - switch (opcode) { - case Instruction::IPUT: - case Instruction::IPUT_OBJECT: - case Instruction::IPUT_BOOLEAN: - case Instruction::IPUT_BYTE: - case Instruction::IPUT_CHAR: - case Instruction::IPUT_SHORT: - case Instruction::IPUT_QUICK: - case Instruction::IPUT_OBJECT_QUICK: - case Instruction::IPUT_BOOLEAN_QUICK: - case Instruction::IPUT_BYTE_QUICK: - case Instruction::IPUT_CHAR_QUICK: - case Instruction::IPUT_SHORT_QUICK: - case Instruction::APUT: - case Instruction::APUT_OBJECT: - case Instruction::APUT_BOOLEAN: - case Instruction::APUT_BYTE: - case Instruction::APUT_CHAR: - case Instruction::APUT_SHORT: - case Instruction::SPUT: - case Instruction::SPUT_OBJECT: - case Instruction::SPUT_BOOLEAN: - case Instruction::SPUT_BYTE: - case Instruction::SPUT_CHAR: - case Instruction::SPUT_SHORT: - // Skip the VR containing what to store. - res = 1; - break; - case Instruction::IPUT_WIDE: - case Instruction::IPUT_WIDE_QUICK: - case Instruction::APUT_WIDE: - case Instruction::SPUT_WIDE: - // Skip the two VRs containing what to store. - res = 2; - break; - default: - // Do nothing in the general case. - break; - } - - return res; -} - -/** - * @brief Given a decoded instruction, it checks whether the instruction - * sets a constant and if it does, more information is provided about the - * constant being set. - * @param ptr_value pointer to a 64-bit holder for the constant. - * @param wide Updated by function whether a wide constant is being set by bytecode. - * @return Returns false if the decoded instruction does not represent a constant bytecode. - */ -bool MIR::DecodedInstruction::GetConstant(int64_t* ptr_value, bool* wide) const { - bool sets_const = true; - int64_t value = vB; - - DCHECK(ptr_value != nullptr); - DCHECK(wide != nullptr); - - switch (opcode) { - case Instruction::CONST_4: - case Instruction::CONST_16: - case Instruction::CONST: - *wide = false; - value <<= 32; // In order to get the sign extend. - value >>= 32; - break; - case Instruction::CONST_HIGH16: - *wide = false; - value <<= 48; // In order to get the sign extend. - value >>= 32; - break; - case Instruction::CONST_WIDE_16: - case Instruction::CONST_WIDE_32: - *wide = true; - value <<= 32; // In order to get the sign extend. - value >>= 32; - break; - case Instruction::CONST_WIDE: - *wide = true; - value = vB_wide; - break; - case Instruction::CONST_WIDE_HIGH16: - *wide = true; - value <<= 48; // In order to get the sign extend. - break; - default: - sets_const = false; - break; - } - - if (sets_const) { - *ptr_value = value; - } - - return sets_const; -} - -void BasicBlock::ResetOptimizationFlags(uint16_t reset_flags) { - // Reset flags for all MIRs in bb. - for (MIR* mir = first_mir_insn; mir != nullptr; mir = mir->next) { - mir->optimization_flags &= (~reset_flags); - } -} - -void BasicBlock::Kill(MIRGraph* mir_graph) { - for (BasicBlockId pred_id : predecessors) { - BasicBlock* pred_bb = mir_graph->GetBasicBlock(pred_id); - DCHECK(pred_bb != nullptr); - - // Sadly we have to go through the children by hand here. - pred_bb->ReplaceChild(id, NullBasicBlockId); - } - predecessors.clear(); - - // Mark as dead and hidden. - block_type = kDead; - hidden = true; - - // Detach it from its MIRs so we don't generate code for them. Also detached MIRs - // are updated to know that they no longer have a parent. - for (MIR* mir = first_mir_insn; mir != nullptr; mir = mir->next) { - mir->bb = NullBasicBlockId; - } - first_mir_insn = nullptr; - last_mir_insn = nullptr; - - data_flow_info = nullptr; - - // Erase this bb from all children's predecessors and kill unreachable children. - ChildBlockIterator iter(this, mir_graph); - for (BasicBlock* succ_bb = iter.Next(); succ_bb != nullptr; succ_bb = iter.Next()) { - succ_bb->ErasePredecessor(id); - } - - // Remove links to children. - fall_through = NullBasicBlockId; - taken = NullBasicBlockId; - successor_block_list_type = kNotUsed; - - if (kIsDebugBuild) { - if (catch_entry) { - DCHECK_EQ(mir_graph->catches_.count(start_offset), 1u); - mir_graph->catches_.erase(start_offset); - } - } -} - -bool BasicBlock::IsSSALiveOut(const CompilationUnit* c_unit, int ssa_reg) { - // In order to determine if the ssa reg is live out, we scan all the MIRs. We remember - // the last SSA number of the same dalvik register. At the end, if it is different than ssa_reg, - // then it is not live out of this BB. - int dalvik_reg = c_unit->mir_graph->SRegToVReg(ssa_reg); - - int last_ssa_reg = -1; - - // Walk through the MIRs backwards. - for (MIR* mir = first_mir_insn; mir != nullptr; mir = mir->next) { - // Get ssa rep. - SSARepresentation *ssa_rep = mir->ssa_rep; - - // Go through the defines for this MIR. - for (int i = 0; i < ssa_rep->num_defs; i++) { - DCHECK(ssa_rep->defs != nullptr); - - // Get the ssa reg. - int def_ssa_reg = ssa_rep->defs[i]; - - // Get dalvik reg. - int def_dalvik_reg = c_unit->mir_graph->SRegToVReg(def_ssa_reg); - - // Compare dalvik regs. - if (dalvik_reg == def_dalvik_reg) { - // We found a def of the register that we are being asked about. - // Remember it. - last_ssa_reg = def_ssa_reg; - } - } - } - - if (last_ssa_reg == -1) { - // If we get to this point we couldn't find a define of register user asked about. - // Let's assume the user knows what he's doing so we can be safe and say that if we - // couldn't find a def, it is live out. - return true; - } - - // If it is not -1, we found a match, is it ssa_reg? - return (ssa_reg == last_ssa_reg); -} - -bool BasicBlock::ReplaceChild(BasicBlockId old_bb, BasicBlockId new_bb) { - // We need to check taken, fall_through, and successor_blocks to replace. - bool found = false; - if (taken == old_bb) { - taken = new_bb; - found = true; - } - - if (fall_through == old_bb) { - fall_through = new_bb; - found = true; - } - - if (successor_block_list_type != kNotUsed) { - for (SuccessorBlockInfo* successor_block_info : successor_blocks) { - if (successor_block_info->block == old_bb) { - successor_block_info->block = new_bb; - found = true; - } - } - } - - return found; -} - -void BasicBlock::ErasePredecessor(BasicBlockId old_pred) { - auto pos = std::find(predecessors.begin(), predecessors.end(), old_pred); - DCHECK(pos != predecessors.end()); - // It's faster to move the back() to *pos than erase(pos). - *pos = predecessors.back(); - predecessors.pop_back(); - size_t idx = std::distance(predecessors.begin(), pos); - for (MIR* mir = first_mir_insn; mir != nullptr; mir = mir->next) { - if (static_cast<int>(mir->dalvikInsn.opcode) != kMirOpPhi) { - break; - } - DCHECK_EQ(mir->ssa_rep->num_uses - 1u, predecessors.size()); - DCHECK_EQ(mir->meta.phi_incoming[idx], old_pred); - mir->meta.phi_incoming[idx] = mir->meta.phi_incoming[predecessors.size()]; - mir->ssa_rep->uses[idx] = mir->ssa_rep->uses[predecessors.size()]; - mir->ssa_rep->num_uses = predecessors.size(); - } -} - -void BasicBlock::UpdatePredecessor(BasicBlockId old_pred, BasicBlockId new_pred) { - DCHECK_NE(new_pred, NullBasicBlockId); - auto pos = std::find(predecessors.begin(), predecessors.end(), old_pred); - DCHECK(pos != predecessors.end()); - *pos = new_pred; - size_t idx = std::distance(predecessors.begin(), pos); - for (MIR* mir = first_mir_insn; mir != nullptr; mir = mir->next) { - if (static_cast<int>(mir->dalvikInsn.opcode) != kMirOpPhi) { - break; - } - DCHECK_EQ(mir->meta.phi_incoming[idx], old_pred); - mir->meta.phi_incoming[idx] = new_pred; - } -} - -// Create a new basic block with block_id as num_blocks_ that is -// post-incremented. -BasicBlock* MIRGraph::CreateNewBB(BBType block_type) { - BasicBlockId id = static_cast<BasicBlockId>(block_list_.size()); - BasicBlock* res = NewMemBB(block_type, id); - block_list_.push_back(res); - return res; -} - -void MIRGraph::CalculateBasicBlockInformation(const PassManager* const post_opt_pass_manager) { - /* Create the pass driver and launch it */ - PassDriverMEPostOpt driver(post_opt_pass_manager, cu_); - driver.Launch(); -} - -int MIR::DecodedInstruction::FlagsOf() const { - // Calculate new index. - int idx = static_cast<int>(opcode) - kNumPackedOpcodes; - - // Check if it is an extended or not. - if (idx < 0) { - return Instruction::FlagsOf(opcode); - } - - // For extended, we use a switch. - switch (static_cast<int>(opcode)) { - case kMirOpPhi: - return Instruction::kContinue; - case kMirOpCopy: - return Instruction::kContinue; - case kMirOpFusedCmplFloat: - return Instruction::kContinue | Instruction::kBranch; - case kMirOpFusedCmpgFloat: - return Instruction::kContinue | Instruction::kBranch; - case kMirOpFusedCmplDouble: - return Instruction::kContinue | Instruction::kBranch; - case kMirOpFusedCmpgDouble: - return Instruction::kContinue | Instruction::kBranch; - case kMirOpFusedCmpLong: - return Instruction::kContinue | Instruction::kBranch; - case kMirOpNop: - return Instruction::kContinue; - case kMirOpNullCheck: - return Instruction::kContinue | Instruction::kThrow; - case kMirOpRangeCheck: - return Instruction::kContinue | Instruction::kThrow; - case kMirOpDivZeroCheck: - return Instruction::kContinue | Instruction::kThrow; - case kMirOpCheck: - return Instruction::kContinue | Instruction::kThrow; - case kMirOpSelect: - return Instruction::kContinue; - case kMirOpConstVector: - return Instruction::kContinue; - case kMirOpMoveVector: - return Instruction::kContinue; - case kMirOpPackedMultiply: - return Instruction::kContinue; - case kMirOpPackedAddition: - return Instruction::kContinue; - case kMirOpPackedSubtract: - return Instruction::kContinue; - case kMirOpPackedShiftLeft: - return Instruction::kContinue; - case kMirOpPackedSignedShiftRight: - return Instruction::kContinue; - case kMirOpPackedUnsignedShiftRight: - return Instruction::kContinue; - case kMirOpPackedAnd: - return Instruction::kContinue; - case kMirOpPackedOr: - return Instruction::kContinue; - case kMirOpPackedXor: - return Instruction::kContinue; - case kMirOpPackedAddReduce: - return Instruction::kContinue; - case kMirOpPackedReduce: - return Instruction::kContinue; - case kMirOpPackedSet: - return Instruction::kContinue; - case kMirOpReserveVectorRegisters: - return Instruction::kContinue; - case kMirOpReturnVectorRegisters: - return Instruction::kContinue; - case kMirOpMemBarrier: - return Instruction::kContinue; - case kMirOpPackedArrayGet: - return Instruction::kContinue | Instruction::kThrow; - case kMirOpPackedArrayPut: - return Instruction::kContinue | Instruction::kThrow; - case kMirOpMaddInt: - case kMirOpMsubInt: - case kMirOpMaddLong: - case kMirOpMsubLong: - return Instruction::kContinue; - default: - LOG(WARNING) << "ExtendedFlagsOf: Unhandled case: " << static_cast<int> (opcode); - return 0; - } -} - -const uint16_t* MIRGraph::GetInsns(int m_unit_index) const { - return m_units_[m_unit_index]->GetCodeItem()->insns_; -} - -void MIRGraph::SetPuntToInterpreter(bool val) { - punt_to_interpreter_ = val; - if (val) { - // Disable all subsequent optimizations. They may not be safe to run. (For example, - // LVN/GVN assumes there are no conflicts found by the type inference pass.) - cu_->disable_opt = ~static_cast<decltype(cu_->disable_opt)>(0); - } -} - -} // namespace art |