diff options
Diffstat (limited to 'compiler/optimizing/builder.cc')
| -rw-r--r-- | compiler/optimizing/builder.cc | 1234 |
1 files changed, 698 insertions, 536 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 7b42db8a7f..8ca352f573 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -46,7 +46,7 @@ class Temporaries : public ValueObject { explicit Temporaries(HGraph* graph) : graph_(graph), index_(0) {} void Add(HInstruction* instruction) { - HInstruction* temp = new (graph_->GetArena()) HTemporary(index_); + HInstruction* temp = new (graph_->GetArena()) HTemporary(index_, instruction->GetDexPc()); instruction->GetBlock()->AddInstruction(temp); DCHECK(temp->GetPrevious() == instruction); @@ -140,11 +140,11 @@ class SwitchTable : public ValueObject { void HGraphBuilder::InitializeLocals(uint16_t count) { graph_->SetNumberOfVRegs(count); - locals_.SetSize(count); + locals_.resize(count); for (int i = 0; i < count; i++) { HLocal* local = new (arena_) HLocal(i); entry_block_->AddInstruction(local); - locals_.Put(i, local); + locals_[i] = local; } } @@ -156,28 +156,39 @@ void HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) { graph_->SetNumberOfInVRegs(number_of_parameters); const char* shorty = dex_compilation_unit_->GetShorty(); - int locals_index = locals_.Size() - number_of_parameters; + int locals_index = locals_.size() - number_of_parameters; int parameter_index = 0; + const DexFile::MethodId& referrer_method_id = + dex_file_->GetMethodId(dex_compilation_unit_->GetDexMethodIndex()); if (!dex_compilation_unit_->IsStatic()) { // Add the implicit 'this' argument, not expressed in the signature. - HParameterValue* parameter = - new (arena_) HParameterValue(parameter_index++, Primitive::kPrimNot, true); + HParameterValue* parameter = new (arena_) HParameterValue(*dex_file_, + referrer_method_id.class_idx_, + parameter_index++, + Primitive::kPrimNot, + true); entry_block_->AddInstruction(parameter); HLocal* local = GetLocalAt(locals_index++); - entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter)); + entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter, local->GetDexPc())); number_of_parameters--; } - uint32_t pos = 1; - for (int i = 0; i < number_of_parameters; i++) { - HParameterValue* parameter = - new (arena_) HParameterValue(parameter_index++, Primitive::GetType(shorty[pos++])); + const DexFile::ProtoId& proto = dex_file_->GetMethodPrototype(referrer_method_id); + const DexFile::TypeList* arg_types = dex_file_->GetProtoParameters(proto); + for (int i = 0, shorty_pos = 1; i < number_of_parameters; i++) { + HParameterValue* parameter = new (arena_) HParameterValue( + *dex_file_, + arg_types->GetTypeItem(shorty_pos - 1).type_idx_, + parameter_index++, + Primitive::GetType(shorty[shorty_pos]), + false); + ++shorty_pos; entry_block_->AddInstruction(parameter); HLocal* local = GetLocalAt(locals_index++); // Store the parameter value in the local that the dex code will use // to reference that parameter. - entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter)); + entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter, local->GetDexPc())); bool is_wide = (parameter->GetType() == Primitive::kPrimLong) || (parameter->GetType() == Primitive::kPrimDouble); if (is_wide) { @@ -196,11 +207,11 @@ void HGraphBuilder::If_22t(const Instruction& instruction, uint32_t dex_pc) { DCHECK(branch_target != nullptr); DCHECK(fallthrough_target != nullptr); PotentiallyAddSuspendCheck(branch_target, dex_pc); - HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt); - HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); - T* comparison = new (arena_) T(first, second); + HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc); + HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc); + T* comparison = new (arena_) T(first, second, dex_pc); current_block_->AddInstruction(comparison); - HInstruction* ifinst = new (arena_) HIf(comparison); + HInstruction* ifinst = new (arena_) HIf(comparison, dex_pc); current_block_->AddInstruction(ifinst); current_block_->AddSuccessor(branch_target); current_block_->AddSuccessor(fallthrough_target); @@ -215,10 +226,10 @@ void HGraphBuilder::If_21t(const Instruction& instruction, uint32_t dex_pc) { DCHECK(branch_target != nullptr); DCHECK(fallthrough_target != nullptr); PotentiallyAddSuspendCheck(branch_target, dex_pc); - HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt); - T* comparison = new (arena_) T(value, graph_->GetIntConstant(0)); + HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc); + T* comparison = new (arena_) T(value, graph_->GetIntConstant(0, dex_pc), dex_pc); current_block_->AddInstruction(comparison); - HInstruction* ifinst = new (arena_) HIf(comparison); + HInstruction* ifinst = new (arena_) HIf(comparison, dex_pc); current_block_->AddInstruction(ifinst); current_block_->AddSuccessor(branch_target); current_block_->AddSuccessor(fallthrough_target); @@ -260,22 +271,6 @@ bool HGraphBuilder::SkipCompilation(const DexFile::CodeItem& code_item, return false; } -static const DexFile::TryItem* GetTryItem(HBasicBlock* block, - const DexFile::CodeItem& code_item, - const ArenaBitVector& can_block_throw) { - DCHECK(!block->IsSingleTryBoundary()); - - // Block does not contain throwing instructions. Even if it is covered by - // a TryItem, we will consider it not in a try block. - if (!can_block_throw.IsBitSet(block->GetBlockId())) { - return nullptr; - } - - // Instructions in the block may throw. Find a TryItem covering this block. - int32_t try_item_idx = DexFile::FindTryItem(code_item, block->GetDexPc()); - return (try_item_idx == -1) ? nullptr : DexFile::GetTryItems(code_item, try_item_idx); -} - void HGraphBuilder::CreateBlocksForTryCatch(const DexFile::CodeItem& code_item) { if (code_item.tries_size_ == 0) { return; @@ -314,18 +309,18 @@ void HGraphBuilder::CreateBlocksForTryCatch(const DexFile::CodeItem& code_item) } } -void HGraphBuilder::SplitTryBoundaryEdge(HBasicBlock* predecessor, - HBasicBlock* successor, - HTryBoundary::BoundaryKind kind, - const DexFile::CodeItem& code_item, - const DexFile::TryItem& try_item) { - // Split the edge with a single TryBoundary instruction. - HTryBoundary* try_boundary = new (arena_) HTryBoundary(kind); - HBasicBlock* try_entry_block = graph_->SplitEdge(predecessor, successor); - try_entry_block->AddInstruction(try_boundary); - - // Link the TryBoundary to the handlers of `try_item`. - for (CatchHandlerIterator it(code_item, try_item); it.HasNext(); it.Next()) { +// Returns the TryItem stored for `block` or nullptr if there is no info for it. +static const DexFile::TryItem* GetTryItem( + HBasicBlock* block, + const ArenaSafeMap<uint32_t, const DexFile::TryItem*>& try_block_info) { + auto iterator = try_block_info.find(block->GetBlockId()); + return (iterator == try_block_info.end()) ? nullptr : iterator->second; +} + +void HGraphBuilder::LinkToCatchBlocks(HTryBoundary* try_boundary, + const DexFile::CodeItem& code_item, + const DexFile::TryItem* try_item) { + for (CatchHandlerIterator it(code_item, *try_item); it.HasNext(); it.Next()) { try_boundary->AddExceptionHandler(FindBlockStartingAt(it.GetHandlerAddress())); } } @@ -335,136 +330,109 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) return; } - // Bit vector stores information on which blocks contain throwing instructions. - // Must be expandable because catch blocks may be split into two. - ArenaBitVector can_block_throw(arena_, graph_->GetBlocks().Size(), /* expandable */ true); + // Keep a map of all try blocks and their respective TryItems. We do not use + // the block's pointer but rather its id to ensure deterministic iteration. + ArenaSafeMap<uint32_t, const DexFile::TryItem*> try_block_info( + std::less<uint32_t>(), arena_->Adapter(kArenaAllocGraphBuilder)); + + // Obtain TryItem information for blocks with throwing instructions, and split + // blocks which are both try & catch to simplify the graph. + // NOTE: We are appending new blocks inside the loop, so we need to use index + // because iterators can be invalidated. We remember the initial size to avoid + // iterating over the new blocks which cannot throw. + for (size_t i = 0, e = graph_->GetBlocks().size(); i < e; ++i) { + HBasicBlock* block = graph_->GetBlocks()[i]; + + // Do not bother creating exceptional edges for try blocks which have no + // throwing instructions. In that case we simply assume that the block is + // not covered by a TryItem. This prevents us from creating a throw-catch + // loop for synchronized blocks. + if (block->HasThrowingInstructions()) { + // Try to find a TryItem covering the block. + DCHECK_NE(block->GetDexPc(), kNoDexPc) << "Block must have a dec_pc to find its TryItem."; + const int32_t try_item_idx = DexFile::FindTryItem(code_item, block->GetDexPc()); + if (try_item_idx != -1) { + // Block throwing and in a TryItem. Store the try block information. + HBasicBlock* throwing_block = block; + if (block->IsCatchBlock()) { + // Simplify blocks which are both try and catch, otherwise we would + // need a strategy for splitting exceptional edges. We split the block + // after the move-exception (if present) and mark the first part not + // throwing. The normal-flow edge between them will be split later. + HInstruction* first_insn = block->GetFirstInstruction(); + if (first_insn->IsLoadException()) { + // Catch block starts with a LoadException. Split the block after + // the StoreLocal and ClearException which must come after the load. + DCHECK(first_insn->GetNext()->IsStoreLocal()); + DCHECK(first_insn->GetNext()->GetNext()->IsClearException()); + throwing_block = block->SplitBefore(first_insn->GetNext()->GetNext()->GetNext()); + } else { + // Catch block does not load the exception. Split at the beginning + // to create an empty catch block. + throwing_block = block->SplitBefore(first_insn); + } + } - // Scan blocks and mark those which contain throwing instructions. - for (size_t block_id = 0, e = graph_->GetBlocks().Size(); block_id < e; ++block_id) { - HBasicBlock* block = graph_->GetBlocks().Get(block_id); - bool can_throw = false; - for (HInstructionIterator insn(block->GetInstructions()); !insn.Done(); insn.Advance()) { - if (insn.Current()->CanThrow()) { - can_throw = true; - break; + try_block_info.Put(throwing_block->GetBlockId(), + DexFile::GetTryItems(code_item, try_item_idx)); } } + } - if (can_throw) { - if (block->IsCatchBlock()) { - // Catch blocks are always considered an entry point into the TryItem in - // order to avoid splitting exceptional edges. We split the block after - // the move-exception (if present) and mark the first part non-throwing. - // Later on, a TryBoundary will be inserted between the two blocks. - HInstruction* first_insn = block->GetFirstInstruction(); - if (first_insn->IsLoadException()) { - // Catch block starts with a LoadException. Split the block after the - // StoreLocal and ClearException which must come after the load. - DCHECK(first_insn->GetNext()->IsStoreLocal()); - DCHECK(first_insn->GetNext()->GetNext()->IsClearException()); - block = block->SplitBefore(first_insn->GetNext()->GetNext()->GetNext()); - } else { - // Catch block does not load the exception. Split at the beginning to - // create an empty catch block. - block = block->SplitBefore(first_insn); - } + // Do a pass over the try blocks and insert entering TryBoundaries where at + // least one predecessor is not covered by the same TryItem as the try block. + // We do not split each edge separately, but rather create one boundary block + // that all predecessors are relinked to. This preserves loop headers (b/23895756). + for (auto entry : try_block_info) { + HBasicBlock* try_block = graph_->GetBlocks()[entry.first]; + for (HBasicBlock* predecessor : try_block->GetPredecessors()) { + if (GetTryItem(predecessor, try_block_info) != entry.second) { + // Found a predecessor not covered by the same TryItem. Insert entering + // boundary block. + HTryBoundary* try_entry = + new (arena_) HTryBoundary(HTryBoundary::kEntry, try_block->GetDexPc()); + try_block->CreateImmediateDominator()->AddInstruction(try_entry); + LinkToCatchBlocks(try_entry, code_item, entry.second); + break; } - can_block_throw.SetBit(block->GetBlockId()); - } - } - - // Iterate over all blocks, find those covered by some TryItem and: - // (a) split edges which enter/exit the try range, - // (b) create TryBoundary instructions in the new blocks, - // (c) link the new blocks to corresponding exception handlers. - // We cannot iterate only over blocks in `branch_targets_` because switch-case - // blocks share the same dex_pc. - for (size_t block_id = 0, e = graph_->GetBlocks().Size(); block_id < e; ++block_id) { - HBasicBlock* try_block = graph_->GetBlocks().Get(block_id); - - // TryBoundary blocks are added at the end of the list and not iterated over. - DCHECK(!try_block->IsSingleTryBoundary()); - - // Find the TryItem for this block. - const DexFile::TryItem* try_item = GetTryItem(try_block, code_item, can_block_throw); - if (try_item == nullptr) { - continue; - } - - // Catch blocks were split earlier and cannot throw. - DCHECK(!try_block->IsCatchBlock()); - - // Find predecessors which are not covered by the same TryItem range. Such - // edges enter the try block and will have a TryBoundary inserted. - for (size_t i = 0; i < try_block->GetPredecessors().Size(); ++i) { - HBasicBlock* predecessor = try_block->GetPredecessors().Get(i); - if (predecessor->IsSingleTryBoundary()) { - // The edge was already split because of an exit from a neighbouring - // TryItem. We split it again and insert an entry point. - if (kIsDebugBuild) { - HTryBoundary* last_insn = predecessor->GetLastInstruction()->AsTryBoundary(); - const DexFile::TryItem* predecessor_try_item = - GetTryItem(predecessor->GetSinglePredecessor(), code_item, can_block_throw); - DCHECK(!last_insn->IsEntry()); - DCHECK_EQ(last_insn->GetNormalFlowSuccessor(), try_block); - DCHECK(try_block->IsFirstIndexOfPredecessor(predecessor, i)); - DCHECK_NE(try_item, predecessor_try_item); - } - } else if (GetTryItem(predecessor, code_item, can_block_throw) != try_item) { - // This is an entry point into the TryItem and the edge has not been - // split yet. That means that `predecessor` is not in a TryItem, or - // it is in a different TryItem and we happened to iterate over this - // block first. We split the edge and insert an entry point. - } else { - // Not an edge on the boundary of the try block. + } + } + + // Do a second pass over the try blocks and insert exit TryBoundaries where + // the successor is not in the same TryItem. + for (auto entry : try_block_info) { + HBasicBlock* try_block = graph_->GetBlocks()[entry.first]; + // NOTE: Do not use iterators because SplitEdge would invalidate them. + for (size_t i = 0, e = try_block->GetSuccessors().size(); i < e; ++i) { + HBasicBlock* successor = try_block->GetSuccessors()[i]; + + // If the successor is a try block, all of its predecessors must be + // covered by the same TryItem. Otherwise the previous pass would have + // created a non-throwing boundary block. + if (GetTryItem(successor, try_block_info) != nullptr) { + DCHECK_EQ(entry.second, GetTryItem(successor, try_block_info)); continue; } - SplitTryBoundaryEdge(predecessor, try_block, HTryBoundary::kEntry, code_item, *try_item); - } - - // Find successors which are not covered by the same TryItem range. Such - // edges exit the try block and will have a TryBoundary inserted. - for (size_t i = 0; i < try_block->GetSuccessors().Size(); ++i) { - HBasicBlock* successor = try_block->GetSuccessors().Get(i); - if (successor->IsCatchBlock()) { - // A catch block is always considered an entry point into its TryItem. - // We therefore assume this is an exit point, regardless of whether - // the catch block is in a different TryItem or not. - } else if (successor->IsSingleTryBoundary()) { - // The edge was already split because of an entry into a neighbouring - // TryItem. We split it again and insert an exit. - if (kIsDebugBuild) { - HTryBoundary* last_insn = successor->GetLastInstruction()->AsTryBoundary(); - const DexFile::TryItem* successor_try_item = - GetTryItem(last_insn->GetNormalFlowSuccessor(), code_item, can_block_throw); - DCHECK_EQ(try_block, successor->GetSinglePredecessor()); - DCHECK(last_insn->IsEntry()); - DCHECK_NE(try_item, successor_try_item); - } - } else if (GetTryItem(successor, code_item, can_block_throw) != try_item) { - // This is an exit out of the TryItem and the edge has not been split - // yet. That means that either `successor` is not in a TryItem, or it - // is in a different TryItem and we happened to iterate over this - // block first. We split the edge and insert an exit. - HInstruction* last_instruction = try_block->GetLastInstruction(); - if (last_instruction->IsReturn() || last_instruction->IsReturnVoid()) { - DCHECK_EQ(successor, exit_block_); - // Control flow exits the try block with a Return(Void). Because - // splitting the edge would invalidate the invariant that Return - // always jumps to Exit, we move the Return outside the try block. - successor = try_block->SplitBefore(last_instruction); - } - } else { - // Not an edge on the boundary of the try block. - continue; + + // Preserve the invariant that Return(Void) always jumps to Exit by moving + // it outside the try block if necessary. + HInstruction* last_instruction = try_block->GetLastInstruction(); + if (last_instruction->IsReturn() || last_instruction->IsReturnVoid()) { + DCHECK_EQ(successor, exit_block_); + successor = try_block->SplitBefore(last_instruction); } - SplitTryBoundaryEdge(try_block, successor, HTryBoundary::kExit, code_item, *try_item); + + // Insert TryBoundary and link to catch blocks. + HTryBoundary* try_exit = + new (arena_) HTryBoundary(HTryBoundary::kExit, successor->GetDexPc()); + graph_->SplitEdge(try_block, successor)->AddInstruction(try_exit); + LinkToCatchBlocks(try_exit, code_item, entry.second); } } } bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { - DCHECK(graph_->GetBlocks().IsEmpty()); + DCHECK(graph_->GetBlocks().empty()); const uint16_t* code_ptr = code_item.insns_; const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_; @@ -477,6 +445,8 @@ bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { graph_->SetEntryBlock(entry_block_); graph_->SetExitBlock(exit_block_); + graph_->SetHasTryCatch(code_item.tries_size_ != 0); + InitializeLocals(code_item.registers_size_); graph_->SetMaximumNumberOfOutVRegs(code_item.outs_size_); @@ -538,7 +508,7 @@ void HGraphBuilder::MaybeUpdateCurrentBlock(size_t dex_pc) { // Branching instructions clear current_block, so we know // the last instruction of the current block is not a branching // instruction. We add an unconditional goto to the found block. - current_block_->AddInstruction(new (arena_) HGoto()); + current_block_->AddInstruction(new (arena_) HGoto(dex_pc)); current_block_->AddSuccessor(block); } graph_->AddBlock(block); @@ -548,11 +518,11 @@ void HGraphBuilder::MaybeUpdateCurrentBlock(size_t dex_pc) { bool HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end, size_t* number_of_branches) { - branch_targets_.SetSize(code_end - code_ptr); + branch_targets_.resize(code_end - code_ptr, nullptr); // Create the first block for the dex instructions, single successor of the entry block. HBasicBlock* block = new (arena_) HBasicBlock(graph_, 0); - branch_targets_.Put(0, block); + branch_targets_[0] = block; entry_block_->AddSuccessor(block); // Iterate over all instructions and find branching instructions. Create blocks for @@ -596,7 +566,7 @@ bool HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, // Create a block for the switch-case logic. The block gets the dex_pc // of the SWITCH instruction because it is part of its semantics. block = new (arena_) HBasicBlock(graph_, dex_pc); - branch_targets_.Put(table.GetDexPcForIndex(i), block); + branch_targets_[table.GetDexPcForIndex(i)] = block; } // Fall-through. Add a block if there is more code afterwards. @@ -620,118 +590,105 @@ bool HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t dex_pc) const { DCHECK_GE(dex_pc, 0); - DCHECK_LT(static_cast<size_t>(dex_pc), branch_targets_.Size()); - return branch_targets_.Get(dex_pc); + return branch_targets_[dex_pc]; } HBasicBlock* HGraphBuilder::FindOrCreateBlockStartingAt(int32_t dex_pc) { HBasicBlock* block = FindBlockStartingAt(dex_pc); if (block == nullptr) { block = new (arena_) HBasicBlock(graph_, dex_pc); - branch_targets_.Put(dex_pc, block); + branch_targets_[dex_pc] = block; } return block; } template<typename T> -void HGraphBuilder::Unop_12x(const Instruction& instruction, Primitive::Type type) { - HInstruction* first = LoadLocal(instruction.VRegB(), type); - current_block_->AddInstruction(new (arena_) T(type, first)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +void HGraphBuilder::Unop_12x(const Instruction& instruction, + Primitive::Type type, + uint32_t dex_pc) { + HInstruction* first = LoadLocal(instruction.VRegB(), type, dex_pc); + current_block_->AddInstruction(new (arena_) T(type, first, dex_pc)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc); } void HGraphBuilder::Conversion_12x(const Instruction& instruction, Primitive::Type input_type, Primitive::Type result_type, uint32_t dex_pc) { - HInstruction* first = LoadLocal(instruction.VRegB(), input_type); + HInstruction* first = LoadLocal(instruction.VRegB(), input_type, dex_pc); current_block_->AddInstruction(new (arena_) HTypeConversion(result_type, first, dex_pc)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); -} - -template<typename T> -void HGraphBuilder::Binop_23x(const Instruction& instruction, Primitive::Type type) { - HInstruction* first = LoadLocal(instruction.VRegB(), type); - HInstruction* second = LoadLocal(instruction.VRegC(), type); - current_block_->AddInstruction(new (arena_) T(type, first, second)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc); } template<typename T> void HGraphBuilder::Binop_23x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc) { - HInstruction* first = LoadLocal(instruction.VRegB(), type); - HInstruction* second = LoadLocal(instruction.VRegC(), type); + HInstruction* first = LoadLocal(instruction.VRegB(), type, dex_pc); + HInstruction* second = LoadLocal(instruction.VRegC(), type, dex_pc); current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc); } template<typename T> void HGraphBuilder::Binop_23x_shift(const Instruction& instruction, - Primitive::Type type) { - HInstruction* first = LoadLocal(instruction.VRegB(), type); - HInstruction* second = LoadLocal(instruction.VRegC(), Primitive::kPrimInt); - current_block_->AddInstruction(new (arena_) T(type, first, second)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + Primitive::Type type, + uint32_t dex_pc) { + HInstruction* first = LoadLocal(instruction.VRegB(), type, dex_pc); + HInstruction* second = LoadLocal(instruction.VRegC(), Primitive::kPrimInt, dex_pc); + current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc); } void HGraphBuilder::Binop_23x_cmp(const Instruction& instruction, Primitive::Type type, ComparisonBias bias, uint32_t dex_pc) { - HInstruction* first = LoadLocal(instruction.VRegB(), type); - HInstruction* second = LoadLocal(instruction.VRegC(), type); + HInstruction* first = LoadLocal(instruction.VRegB(), type, dex_pc); + HInstruction* second = LoadLocal(instruction.VRegC(), type, dex_pc); current_block_->AddInstruction(new (arena_) HCompare(type, first, second, bias, dex_pc)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc); } template<typename T> -void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type type) { - HInstruction* first = LoadLocal(instruction.VRegA(), type); - HInstruction* second = LoadLocal(instruction.VRegB(), type); - current_block_->AddInstruction(new (arena_) T(type, first, second)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); -} - -template<typename T> -void HGraphBuilder::Binop_12x_shift(const Instruction& instruction, Primitive::Type type) { - HInstruction* first = LoadLocal(instruction.VRegA(), type); - HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); - current_block_->AddInstruction(new (arena_) T(type, first, second)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +void HGraphBuilder::Binop_12x_shift(const Instruction& instruction, Primitive::Type type, + uint32_t dex_pc) { + HInstruction* first = LoadLocal(instruction.VRegA(), type, dex_pc); + HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc); + current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc); } template<typename T> void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc) { - HInstruction* first = LoadLocal(instruction.VRegA(), type); - HInstruction* second = LoadLocal(instruction.VRegB(), type); + HInstruction* first = LoadLocal(instruction.VRegA(), type, dex_pc); + HInstruction* second = LoadLocal(instruction.VRegB(), type, dex_pc); current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc); } template<typename T> -void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) { - HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); - HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22s()); +void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse, uint32_t dex_pc) { + HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc); + HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22s(), dex_pc); if (reverse) { std::swap(first, second); } - current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second, dex_pc)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc); } template<typename T> -void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) { - HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); - HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22b()); +void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse, uint32_t dex_pc) { + HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc); + HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22b(), dex_pc); if (reverse) { std::swap(first, second); } - current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second, dex_pc)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc); } static bool RequiresConstructorBarrier(const DexCompilationUnit* cu, const CompilerDriver& driver) { @@ -740,7 +697,9 @@ static bool RequiresConstructorBarrier(const DexCompilationUnit* cu, const Compi && driver.RequiresConstructorBarrier(self, cu->GetDexFile(), cu->GetClassDefIndex()); } -void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type type) { +void HGraphBuilder::BuildReturn(const Instruction& instruction, + Primitive::Type type, + uint32_t dex_pc) { if (type == Primitive::kPrimVoid) { if (graph_->ShouldGenerateConstructorBarrier()) { // The compilation unit is null during testing. @@ -748,12 +707,12 @@ void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type DCHECK(RequiresConstructorBarrier(dex_compilation_unit_, *compiler_driver_)) << "Inconsistent use of ShouldGenerateConstructorBarrier. Should not generate a barrier."; } - current_block_->AddInstruction(new (arena_) HMemoryBarrier(kStoreStore)); + current_block_->AddInstruction(new (arena_) HMemoryBarrier(kStoreStore, dex_pc)); } - current_block_->AddInstruction(new (arena_) HReturnVoid()); + current_block_->AddInstruction(new (arena_) HReturnVoid(dex_pc)); } else { - HInstruction* value = LoadLocal(instruction.VRegA(), type); - current_block_->AddInstruction(new (arena_) HReturn(value)); + HInstruction* value = LoadLocal(instruction.VRegA(), type, dex_pc); + current_block_->AddInstruction(new (arena_) HReturn(value, dex_pc)); } current_block_->AddSuccessor(exit_block_); current_block_ = nullptr; @@ -804,10 +763,42 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, } MethodReference target_method(dex_file_, method_idx); - int32_t table_index; - uintptr_t direct_code; - uintptr_t direct_method; + int32_t table_index = 0; + uintptr_t direct_code = 0; + uintptr_t direct_method = 0; + // Special handling for string init. + int32_t string_init_offset = 0; + bool is_string_init = compiler_driver_->IsStringInit(method_idx, + dex_file_, + &string_init_offset); + // Replace calls to String.<init> with StringFactory. + if (is_string_init) { + HInvokeStaticOrDirect::DispatchInfo dispatch_info = ComputeDispatchInfo(is_string_init, + string_init_offset, + target_method, + direct_method, + direct_code); + HInvoke* invoke = new (arena_) HInvokeStaticOrDirect( + arena_, + number_of_arguments - 1, + Primitive::kPrimNot /*return_type */, + dex_pc, + method_idx, + target_method, + dispatch_info, + original_invoke_type, + kStatic /* optimized_invoke_type */, + HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit); + return HandleStringInit(invoke, + number_of_vreg_arguments, + args, + register_index, + is_range, + descriptor); + } + + // Handle unresolved methods. if (!compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc, true /* update_stats */, @@ -817,42 +808,39 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, &table_index, &direct_code, &direct_method)) { - VLOG(compiler) << "Did not compile " - << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_) - << " because a method call could not be resolved"; - MaybeRecordStat(MethodCompilationStat::kNotCompiledUnresolvedMethod); - return false; - } + MaybeRecordStat(MethodCompilationStat::kUnresolvedMethod); + HInvoke* invoke = new (arena_) HInvokeUnresolved(arena_, + number_of_arguments, + return_type, + dex_pc, + method_idx, + original_invoke_type); + return HandleInvoke(invoke, + number_of_vreg_arguments, + args, + register_index, + is_range, + descriptor, + nullptr /* clinit_check */); + } + + // Handle resolved methods (non string init). DCHECK(optimized_invoke_type != kSuper); - // Special handling for string init. - int32_t string_init_offset = 0; - bool is_string_init = compiler_driver_->IsStringInit(method_idx, dex_file_, - &string_init_offset); - // Potential class initialization check, in the case of a static method call. HClinitCheck* clinit_check = nullptr; HInvoke* invoke = nullptr; - if (is_string_init - || optimized_invoke_type == kDirect - || optimized_invoke_type == kStatic) { + if (optimized_invoke_type == kDirect || optimized_invoke_type == kStatic) { // By default, consider that the called method implicitly requires // an initialization check of its declaring method. HInvokeStaticOrDirect::ClinitCheckRequirement clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit; - if (optimized_invoke_type == kStatic && !is_string_init) { + if (optimized_invoke_type == kStatic) { clinit_check = ProcessClinitCheckForInvoke(dex_pc, method_idx, &clinit_check_requirement); } - // Replace calls to String.<init> with StringFactory. - if (is_string_init) { - return_type = Primitive::kPrimNot; - number_of_arguments--; - optimized_invoke_type = kStatic; - } - HInvokeStaticOrDirect::DispatchInfo dispatch_info = ComputeDispatchInfo(is_string_init, string_init_offset, target_method, @@ -885,13 +873,13 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, table_index); } - return SetupArgumentsAndAddInvoke(invoke, - number_of_vreg_arguments, - args, - register_index, - is_range, - descriptor, - clinit_check); + return HandleInvoke(invoke, + number_of_vreg_arguments, + args, + register_index, + is_range, + descriptor, + clinit_check); } HClinitCheck* HGraphBuilder::ProcessClinitCheckForInvoke( @@ -902,7 +890,7 @@ HClinitCheck* HGraphBuilder::ProcessClinitCheckForInvoke( StackHandleScope<4> hs(soa.Self()); Handle<mirror::DexCache> dex_cache(hs.NewHandle( dex_compilation_unit_->GetClassLinker()->FindDexCache( - *dex_compilation_unit_->GetDexFile()))); + soa.Self(), *dex_compilation_unit_->GetDexFile()))); Handle<mirror::ClassLoader> class_loader(hs.NewHandle( soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader()))); ArtMethod* resolved_method = compiler_driver_->ResolveMethod( @@ -912,7 +900,7 @@ HClinitCheck* HGraphBuilder::ProcessClinitCheckForInvoke( const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile(); Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle( - outer_compilation_unit_->GetClassLinker()->FindDexCache(outer_dex_file))); + outer_compilation_unit_->GetClassLinker()->FindDexCache(soa.Self(), outer_dex_file))); Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass())); // The index at which the method's class is stored in the DexCache's type array. @@ -960,7 +948,8 @@ HClinitCheck* HGraphBuilder::ProcessClinitCheckForInvoke( storage_index, *dex_compilation_unit_->GetDexFile(), is_outer_class, - dex_pc); + dex_pc, + /*needs_access_check*/ false); current_block_->AddInstruction(load_class); clinit_check = new (arena_) HClinitCheck(load_class, dex_pc); current_block_->AddInstruction(clinit_check); @@ -1040,41 +1029,23 @@ HInvokeStaticOrDirect::DispatchInfo HGraphBuilder::ComputeDispatchInfo( method_load_kind, code_ptr_location, method_load_data, direct_code_ptr }; } -bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke, - uint32_t number_of_vreg_arguments, - uint32_t* args, - uint32_t register_index, - bool is_range, - const char* descriptor, - HClinitCheck* clinit_check) { - size_t start_index = 0; - size_t argument_index = 0; +bool HGraphBuilder::SetupInvokeArguments(HInvoke* invoke, + uint32_t number_of_vreg_arguments, + uint32_t* args, + uint32_t register_index, + bool is_range, + const char* descriptor, + size_t start_index, + size_t* argument_index) { uint32_t descriptor_index = 1; // Skip the return type. - - bool is_instance_call = invoke->GetOriginalInvokeType() != InvokeType::kStatic; - bool is_string_init = invoke->IsInvokeStaticOrDirect() - && invoke->AsInvokeStaticOrDirect()->IsStringInit(); - - if (is_string_init) { - start_index = 1; - argument_index = 0; - } else if (is_instance_call) { - Temporaries temps(graph_); - HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot); - HNullCheck* null_check = new (arena_) HNullCheck(arg, invoke->GetDexPc()); - current_block_->AddInstruction(null_check); - temps.Add(null_check); - invoke->SetArgumentAt(0, null_check); - start_index = 1; - argument_index = 1; - } + uint32_t dex_pc = invoke->GetDexPc(); for (size_t i = start_index; // Make sure we don't go over the expected arguments or over the number of // dex registers given. If the instruction was seen as dead by the verifier, // it hasn't been properly checked. - (i < number_of_vreg_arguments) && (argument_index < invoke->GetNumberOfArguments()); - i++, argument_index++) { + (i < number_of_vreg_arguments) && (*argument_index < invoke->GetNumberOfArguments()); + i++, (*argument_index)++) { Primitive::Type type = Primitive::GetType(descriptor[descriptor_index++]); bool is_wide = (type == Primitive::kPrimLong) || (type == Primitive::kPrimDouble); if (!is_range @@ -1089,14 +1060,14 @@ bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke, MaybeRecordStat(MethodCompilationStat::kNotCompiledMalformedOpcode); return false; } - HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type); - invoke->SetArgumentAt(argument_index, arg); + HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type, dex_pc); + invoke->SetArgumentAt(*argument_index, arg); if (is_wide) { i++; } } - if (argument_index != invoke->GetNumberOfArguments()) { + if (*argument_index != invoke->GetNumberOfArguments()) { VLOG(compiler) << "Did not compile " << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_) << " because of wrong number of arguments in invoke instruction"; @@ -1105,13 +1076,49 @@ bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke, } if (invoke->IsInvokeStaticOrDirect()) { - invoke->SetArgumentAt(argument_index, graph_->GetCurrentMethod()); - argument_index++; + invoke->SetArgumentAt(*argument_index, graph_->GetCurrentMethod()); + (*argument_index)++; + } + + return true; +} + +bool HGraphBuilder::HandleInvoke(HInvoke* invoke, + uint32_t number_of_vreg_arguments, + uint32_t* args, + uint32_t register_index, + bool is_range, + const char* descriptor, + HClinitCheck* clinit_check) { + DCHECK(!invoke->IsInvokeStaticOrDirect() || !invoke->AsInvokeStaticOrDirect()->IsStringInit()); + + size_t start_index = 0; + size_t argument_index = 0; + if (invoke->GetOriginalInvokeType() != InvokeType::kStatic) { // Instance call. + Temporaries temps(graph_); + HInstruction* arg = LoadLocal( + is_range ? register_index : args[0], Primitive::kPrimNot, invoke->GetDexPc()); + HNullCheck* null_check = new (arena_) HNullCheck(arg, invoke->GetDexPc()); + current_block_->AddInstruction(null_check); + temps.Add(null_check); + invoke->SetArgumentAt(0, null_check); + start_index = 1; + argument_index = 1; + } + + if (!SetupInvokeArguments(invoke, + number_of_vreg_arguments, + args, + register_index, + is_range, + descriptor, + start_index, + &argument_index)) { + return false; } if (clinit_check != nullptr) { // Add the class initialization check as last input of `invoke`. - DCHECK(!is_string_init); DCHECK(invoke->IsInvokeStaticOrDirect()); DCHECK(invoke->AsInvokeStaticOrDirect()->GetClinitCheckRequirement() == HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit); @@ -1119,17 +1126,41 @@ bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke, argument_index++; } - // Add move-result for StringFactory method. - if (is_string_init) { - uint32_t orig_this_reg = is_range ? register_index : args[0]; - HInstruction* fake_string = LoadLocal(orig_this_reg, Primitive::kPrimNot); - invoke->SetArgumentAt(argument_index, fake_string); - current_block_->AddInstruction(invoke); - PotentiallySimplifyFakeString(orig_this_reg, invoke->GetDexPc(), invoke); - } else { - current_block_->AddInstruction(invoke); + current_block_->AddInstruction(invoke); + latest_result_ = invoke; + + return true; +} + +bool HGraphBuilder::HandleStringInit(HInvoke* invoke, + uint32_t number_of_vreg_arguments, + uint32_t* args, + uint32_t register_index, + bool is_range, + const char* descriptor) { + DCHECK(invoke->IsInvokeStaticOrDirect()); + DCHECK(invoke->AsInvokeStaticOrDirect()->IsStringInit()); + + size_t start_index = 1; + size_t argument_index = 0; + if (!SetupInvokeArguments(invoke, + number_of_vreg_arguments, + args, + register_index, + is_range, + descriptor, + start_index, + &argument_index)) { + return false; } + // Add move-result for StringFactory method. + uint32_t orig_this_reg = is_range ? register_index : args[0]; + HInstruction* fake_string = LoadLocal(orig_this_reg, Primitive::kPrimNot, invoke->GetDexPc()); + invoke->SetArgumentAt(argument_index, fake_string); + current_block_->AddInstruction(invoke); + PotentiallySimplifyFakeString(orig_this_reg, invoke->GetDexPc(), invoke); + latest_result_ = invoke; return true; @@ -1148,15 +1179,14 @@ void HGraphBuilder::PotentiallySimplifyFakeString(uint16_t original_dex_register const VerifiedMethod* verified_method = compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex()); if (verified_method != nullptr) { - UpdateLocal(original_dex_register, actual_string); + UpdateLocal(original_dex_register, actual_string, dex_pc); const SafeMap<uint32_t, std::set<uint32_t>>& string_init_map = verified_method->GetStringInitPcRegMap(); auto map_it = string_init_map.find(dex_pc); if (map_it != string_init_map.end()) { - std::set<uint32_t> reg_set = map_it->second; - for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) { - HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot); - UpdateLocal(*set_it, load_local); + for (uint32_t reg : map_it->second) { + HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot, dex_pc); + UpdateLocal(reg, load_local, dex_pc); } } } else { @@ -1164,6 +1194,12 @@ void HGraphBuilder::PotentiallySimplifyFakeString(uint16_t original_dex_register } } +static Primitive::Type GetFieldAccessType(const DexFile& dex_file, uint16_t field_index) { + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); + const char* type = dex_file.GetFieldTypeDescriptor(field_id); + return Primitive::GetType(type[0]); +} + bool HGraphBuilder::BuildInstanceFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put) { @@ -1183,40 +1219,65 @@ bool HGraphBuilder::BuildInstanceFieldAccess(const Instruction& instruction, ArtField* resolved_field = compiler_driver_->ComputeInstanceFieldInfo(field_index, dex_compilation_unit_, is_put, soa); - if (resolved_field == nullptr) { - MaybeRecordStat(MethodCompilationStat::kNotCompiledUnresolvedField); - return false; - } - Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType(); + HInstruction* object = LoadLocal(obj_reg, Primitive::kPrimNot, dex_pc); + HInstruction* null_check = new (arena_) HNullCheck(object, dex_pc); + current_block_->AddInstruction(null_check); - HInstruction* object = LoadLocal(obj_reg, Primitive::kPrimNot); - current_block_->AddInstruction(new (arena_) HNullCheck(object, dex_pc)); + Primitive::Type field_type = (resolved_field == nullptr) + ? GetFieldAccessType(*dex_file_, field_index) + : resolved_field->GetTypeAsPrimitiveType(); if (is_put) { Temporaries temps(graph_); - HInstruction* null_check = current_block_->GetLastInstruction(); // We need one temporary for the null check. temps.Add(null_check); - HInstruction* value = LoadLocal(source_or_dest_reg, field_type); - current_block_->AddInstruction(new (arena_) HInstanceFieldSet( - null_check, - value, - field_type, - resolved_field->GetOffset(), - resolved_field->IsVolatile(), - field_index, - *dex_file_)); + HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc); + HInstruction* field_set = nullptr; + if (resolved_field == nullptr) { + MaybeRecordStat(MethodCompilationStat::kUnresolvedField); + field_set = new (arena_) HUnresolvedInstanceFieldSet(null_check, + value, + field_type, + field_index, + dex_pc); + } else { + uint16_t class_def_index = resolved_field->GetDeclaringClass()->GetDexClassDefIndex(); + field_set = new (arena_) HInstanceFieldSet(null_check, + value, + field_type, + resolved_field->GetOffset(), + resolved_field->IsVolatile(), + field_index, + class_def_index, + *dex_file_, + dex_compilation_unit_->GetDexCache(), + dex_pc); + } + current_block_->AddInstruction(field_set); } else { - current_block_->AddInstruction(new (arena_) HInstanceFieldGet( - current_block_->GetLastInstruction(), - field_type, - resolved_field->GetOffset(), - resolved_field->IsVolatile(), - field_index, - *dex_file_)); - - UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction()); + HInstruction* field_get = nullptr; + if (resolved_field == nullptr) { + MaybeRecordStat(MethodCompilationStat::kUnresolvedField); + field_get = new (arena_) HUnresolvedInstanceFieldGet(null_check, + field_type, + field_index, + dex_pc); + } else { + uint16_t class_def_index = resolved_field->GetDeclaringClass()->GetDexClassDefIndex(); + field_get = new (arena_) HInstanceFieldGet(null_check, + field_type, + resolved_field->GetOffset(), + resolved_field->IsVolatile(), + field_index, + class_def_index, + *dex_file_, + dex_compilation_unit_->GetDexCache(), + dex_pc); + } + current_block_->AddInstruction(field_get); + UpdateLocal(source_or_dest_reg, field_get, dex_pc); } + return true; } @@ -1228,7 +1289,7 @@ static mirror::Class* GetClassFrom(CompilerDriver* driver, Handle<mirror::ClassLoader> class_loader(hs.NewHandle( soa.Decode<mirror::ClassLoader*>(compilation_unit.GetClassLoader()))); Handle<mirror::DexCache> dex_cache(hs.NewHandle( - compilation_unit.GetClassLinker()->FindDexCache(dex_file))); + compilation_unit.GetClassLinker()->FindDexCache(soa.Self(), dex_file))); return driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, &compilation_unit); } @@ -1245,16 +1306,40 @@ bool HGraphBuilder::IsOutermostCompilingClass(uint16_t type_index) const { ScopedObjectAccess soa(Thread::Current()); StackHandleScope<4> hs(soa.Self()); Handle<mirror::DexCache> dex_cache(hs.NewHandle( - dex_compilation_unit_->GetClassLinker()->FindDexCache(*dex_compilation_unit_->GetDexFile()))); + dex_compilation_unit_->GetClassLinker()->FindDexCache( + soa.Self(), *dex_compilation_unit_->GetDexFile()))); Handle<mirror::ClassLoader> class_loader(hs.NewHandle( soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader()))); Handle<mirror::Class> cls(hs.NewHandle(compiler_driver_->ResolveClass( soa, dex_cache, class_loader, type_index, dex_compilation_unit_))); Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass())); - return outer_class.Get() == cls.Get(); + // GetOutermostCompilingClass returns null when the class is unresolved + // (e.g. if it derives from an unresolved class). This is bogus knowing that + // we are compiling it. + // When this happens we cannot establish a direct relation between the current + // class and the outer class, so we return false. + // (Note that this is only used for optimizing invokes and field accesses) + return (cls.Get() != nullptr) && (outer_class.Get() == cls.Get()); } +void HGraphBuilder::BuildUnresolvedStaticFieldAccess(const Instruction& instruction, + uint32_t dex_pc, + bool is_put, + Primitive::Type field_type) { + uint32_t source_or_dest_reg = instruction.VRegA_21c(); + uint16_t field_index = instruction.VRegB_21c(); + + if (is_put) { + HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc); + current_block_->AddInstruction( + new (arena_) HUnresolvedStaticFieldSet(value, field_type, field_index, dex_pc)); + } else { + current_block_->AddInstruction( + new (arena_) HUnresolvedStaticFieldGet(field_type, field_index, dex_pc)); + UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction(), dex_pc); + } +} bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put) { @@ -1264,20 +1349,24 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, ScopedObjectAccess soa(Thread::Current()); StackHandleScope<4> hs(soa.Self()); Handle<mirror::DexCache> dex_cache(hs.NewHandle( - dex_compilation_unit_->GetClassLinker()->FindDexCache(*dex_compilation_unit_->GetDexFile()))); + dex_compilation_unit_->GetClassLinker()->FindDexCache( + soa.Self(), *dex_compilation_unit_->GetDexFile()))); Handle<mirror::ClassLoader> class_loader(hs.NewHandle( soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader()))); ArtField* resolved_field = compiler_driver_->ResolveField( soa, dex_cache, class_loader, dex_compilation_unit_, field_index, true); if (resolved_field == nullptr) { - MaybeRecordStat(MethodCompilationStat::kNotCompiledUnresolvedField); - return false; + MaybeRecordStat(MethodCompilationStat::kUnresolvedField); + Primitive::Type field_type = GetFieldAccessType(*dex_file_, field_index); + BuildUnresolvedStaticFieldAccess(instruction, dex_pc, is_put, field_type); + return true; } + Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType(); const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile(); Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle( - outer_compilation_unit_->GetClassLinker()->FindDexCache(outer_dex_file))); + outer_compilation_unit_->GetClassLinker()->FindDexCache(soa.Self(), outer_dex_file))); Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass())); // The index at which the field's class is stored in the DexCache's type array. @@ -1289,6 +1378,7 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, // The compiler driver cannot currently understand multiple dex caches involved. Just bailout. return false; } else { + // TODO: This is rather expensive. Perf it and cache the results if needed. std::pair<bool, bool> pair = compiler_driver_->IsFastStaticField( outer_dex_cache.Get(), GetCompilingClass(), @@ -1297,7 +1387,9 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, &storage_index); bool can_easily_access = is_put ? pair.second : pair.first; if (!can_easily_access) { - return false; + MaybeRecordStat(MethodCompilationStat::kUnresolvedFieldNotAFastAccess); + BuildUnresolvedStaticFieldAccess(instruction, dex_pc, is_put, field_type); + return true; } } @@ -1310,7 +1402,8 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, storage_index, *dex_compilation_unit_->GetDexFile(), is_outer_class, - dex_pc); + dex_pc, + /*needs_access_check*/ false); current_block_->AddInstruction(constant); HInstruction* cls = constant; @@ -1319,12 +1412,12 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, current_block_->AddInstruction(cls); } - Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType(); + uint16_t class_def_index = resolved_field->GetDeclaringClass()->GetDexClassDefIndex(); if (is_put) { // We need to keep the class alive before loading the value. Temporaries temps(graph_); temps.Add(cls); - HInstruction* value = LoadLocal(source_or_dest_reg, field_type); + HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc); DCHECK_EQ(value->GetType(), field_type); current_block_->AddInstruction(new (arena_) HStaticFieldSet(cls, value, @@ -1332,15 +1425,21 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, resolved_field->GetOffset(), resolved_field->IsVolatile(), field_index, - *dex_file_)); + class_def_index, + *dex_file_, + dex_cache_, + dex_pc)); } else { current_block_->AddInstruction(new (arena_) HStaticFieldGet(cls, field_type, resolved_field->GetOffset(), resolved_field->IsVolatile(), field_index, - *dex_file_)); - UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction()); + class_def_index, + *dex_file_, + dex_cache_, + dex_pc)); + UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction(), dex_pc); } return true; } @@ -1354,16 +1453,16 @@ void HGraphBuilder::BuildCheckedDivRem(uint16_t out_vreg, bool isDiv) { DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong); - HInstruction* first = LoadLocal(first_vreg, type); + HInstruction* first = LoadLocal(first_vreg, type, dex_pc); HInstruction* second = nullptr; if (second_is_constant) { if (type == Primitive::kPrimInt) { - second = graph_->GetIntConstant(second_vreg_or_constant); + second = graph_->GetIntConstant(second_vreg_or_constant, dex_pc); } else { - second = graph_->GetLongConstant(second_vreg_or_constant); + second = graph_->GetLongConstant(second_vreg_or_constant, dex_pc); } } else { - second = LoadLocal(second_vreg_or_constant, type); + second = LoadLocal(second_vreg_or_constant, type, dex_pc); } if (!second_is_constant @@ -1380,7 +1479,7 @@ void HGraphBuilder::BuildCheckedDivRem(uint16_t out_vreg, } else { current_block_->AddInstruction(new (arena_) HRem(type, first, second, dex_pc)); } - UpdateLocal(out_vreg, current_block_->GetLastInstruction()); + UpdateLocal(out_vreg, current_block_->GetLastInstruction(), dex_pc); } void HGraphBuilder::BuildArrayAccess(const Instruction& instruction, @@ -1394,26 +1493,26 @@ void HGraphBuilder::BuildArrayAccess(const Instruction& instruction, // We need one temporary for the null check, one for the index, and one for the length. Temporaries temps(graph_); - HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot); + HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot, dex_pc); object = new (arena_) HNullCheck(object, dex_pc); current_block_->AddInstruction(object); temps.Add(object); - HInstruction* length = new (arena_) HArrayLength(object); + HInstruction* length = new (arena_) HArrayLength(object, dex_pc); current_block_->AddInstruction(length); temps.Add(length); - HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt); + HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt, dex_pc); index = new (arena_) HBoundsCheck(index, length, dex_pc); current_block_->AddInstruction(index); temps.Add(index); if (is_put) { - HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type); + HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type, dex_pc); // TODO: Insert a type check node if the type is Object. current_block_->AddInstruction(new (arena_) HArraySet( object, index, value, anticipated_type, dex_pc)); } else { - current_block_->AddInstruction(new (arena_) HArrayGet(object, index, anticipated_type)); - UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction()); + current_block_->AddInstruction(new (arena_) HArrayGet(object, index, anticipated_type, dex_pc)); + UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction(), dex_pc); } graph_->SetHasBoundsChecks(true); } @@ -1424,7 +1523,7 @@ void HGraphBuilder::BuildFilledNewArray(uint32_t dex_pc, bool is_range, uint32_t* args, uint32_t register_index) { - HInstruction* length = graph_->GetIntConstant(number_of_vreg_arguments); + HInstruction* length = graph_->GetIntConstant(number_of_vreg_arguments, dex_pc); QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index) ? kQuickAllocArrayWithAccessCheck : kQuickAllocArray; @@ -1448,8 +1547,8 @@ void HGraphBuilder::BuildFilledNewArray(uint32_t dex_pc, Temporaries temps(graph_); temps.Add(object); for (size_t i = 0; i < number_of_vreg_arguments; ++i) { - HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type); - HInstruction* index = graph_->GetIntConstant(i); + HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type, dex_pc); + HInstruction* index = graph_->GetIntConstant(i, dex_pc); current_block_->AddInstruction( new (arena_) HArraySet(object, index, value, type, dex_pc)); } @@ -1463,8 +1562,8 @@ void HGraphBuilder::BuildFillArrayData(HInstruction* object, Primitive::Type anticipated_type, uint32_t dex_pc) { for (uint32_t i = 0; i < element_count; ++i) { - HInstruction* index = graph_->GetIntConstant(i); - HInstruction* value = graph_->GetIntConstant(data[i]); + HInstruction* index = graph_->GetIntConstant(i, dex_pc); + HInstruction* value = graph_->GetIntConstant(data[i], dex_pc); current_block_->AddInstruction(new (arena_) HArraySet( object, index, value, anticipated_type, dex_pc)); } @@ -1472,12 +1571,12 @@ void HGraphBuilder::BuildFillArrayData(HInstruction* object, void HGraphBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t dex_pc) { Temporaries temps(graph_); - HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot); + HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot, dex_pc); HNullCheck* null_check = new (arena_) HNullCheck(array, dex_pc); current_block_->AddInstruction(null_check); temps.Add(null_check); - HInstruction* length = new (arena_) HArrayLength(null_check); + HInstruction* length = new (arena_) HArrayLength(null_check, dex_pc); current_block_->AddInstruction(length); int32_t payload_offset = instruction.VRegB_31t() + dex_pc; @@ -1488,7 +1587,7 @@ void HGraphBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t // Implementation of this DEX instruction seems to be that the bounds check is // done before doing any stores. - HInstruction* last_index = graph_->GetIntConstant(payload->element_count - 1); + HInstruction* last_index = graph_->GetIntConstant(payload->element_count - 1, dex_pc); current_block_->AddInstruction(new (arena_) HBoundsCheck(last_index, length, dex_pc)); switch (payload->element_width) { @@ -1530,53 +1629,79 @@ void HGraphBuilder::BuildFillWideArrayData(HInstruction* object, uint32_t element_count, uint32_t dex_pc) { for (uint32_t i = 0; i < element_count; ++i) { - HInstruction* index = graph_->GetIntConstant(i); - HInstruction* value = graph_->GetLongConstant(data[i]); + HInstruction* index = graph_->GetIntConstant(i, dex_pc); + HInstruction* value = graph_->GetLongConstant(data[i], dex_pc); current_block_->AddInstruction(new (arena_) HArraySet( object, index, value, Primitive::kPrimLong, dex_pc)); } } -bool HGraphBuilder::BuildTypeCheck(const Instruction& instruction, +static TypeCheckKind ComputeTypeCheckKind(Handle<mirror::Class> cls) + SHARED_REQUIRES(Locks::mutator_lock_) { + if (cls.Get() == nullptr) { + return TypeCheckKind::kUnresolvedCheck; + } else if (cls->IsInterface()) { + return TypeCheckKind::kInterfaceCheck; + } else if (cls->IsArrayClass()) { + if (cls->GetComponentType()->IsObjectClass()) { + return TypeCheckKind::kArrayObjectCheck; + } else if (cls->CannotBeAssignedFromOtherTypes()) { + return TypeCheckKind::kExactCheck; + } else { + return TypeCheckKind::kArrayCheck; + } + } else if (cls->IsFinal()) { + return TypeCheckKind::kExactCheck; + } else if (cls->IsAbstract()) { + return TypeCheckKind::kAbstractClassCheck; + } else { + return TypeCheckKind::kClassHierarchyCheck; + } +} + +void HGraphBuilder::BuildTypeCheck(const Instruction& instruction, uint8_t destination, uint8_t reference, uint16_t type_index, uint32_t dex_pc) { - bool type_known_final; - bool type_known_abstract; - // `CanAccessTypeWithoutChecks` will tell whether the method being - // built is trying to access its own class, so that the generated - // code can optimize for this case. However, the optimization does not - // work for inlining, so we use `IsOutermostCompilingClass` instead. - bool dont_use_is_referrers_class; + bool type_known_final, type_known_abstract, use_declaring_class; bool can_access = compiler_driver_->CanAccessTypeWithoutChecks( - dex_compilation_unit_->GetDexMethodIndex(), *dex_file_, type_index, - &type_known_final, &type_known_abstract, &dont_use_is_referrers_class); - if (!can_access) { - MaybeRecordStat(MethodCompilationStat::kNotCompiledCantAccesType); - return false; - } - HInstruction* object = LoadLocal(reference, Primitive::kPrimNot); + dex_compilation_unit_->GetDexMethodIndex(), + *dex_compilation_unit_->GetDexFile(), + type_index, + &type_known_final, + &type_known_abstract, + &use_declaring_class); + + ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<2> hs(soa.Self()); + Handle<mirror::DexCache> dex_cache(hs.NewHandle( + dex_compilation_unit_->GetClassLinker()->FindDexCache( + soa.Self(), *dex_compilation_unit_->GetDexFile()))); + Handle<mirror::Class> resolved_class(hs.NewHandle(dex_cache->GetResolvedType(type_index))); + + HInstruction* object = LoadLocal(reference, Primitive::kPrimNot, dex_pc); HLoadClass* cls = new (arena_) HLoadClass( graph_->GetCurrentMethod(), type_index, *dex_compilation_unit_->GetDexFile(), IsOutermostCompilingClass(type_index), - dex_pc); + dex_pc, + !can_access); current_block_->AddInstruction(cls); + // The class needs a temporary before being used by the type check. Temporaries temps(graph_); temps.Add(cls); + + TypeCheckKind check_kind = ComputeTypeCheckKind(resolved_class); if (instruction.Opcode() == Instruction::INSTANCE_OF) { - current_block_->AddInstruction( - new (arena_) HInstanceOf(object, cls, type_known_final, dex_pc)); - UpdateLocal(destination, current_block_->GetLastInstruction()); + current_block_->AddInstruction(new (arena_) HInstanceOf(object, cls, check_kind, dex_pc)); + UpdateLocal(destination, current_block_->GetLastInstruction(), dex_pc); } else { DCHECK_EQ(instruction.Opcode(), Instruction::CHECK_CAST); - current_block_->AddInstruction( - new (arena_) HCheckCast(object, cls, type_known_final, dex_pc)); + current_block_->AddInstruction(new (arena_) HCheckCast(object, cls, check_kind, dex_pc)); } - return true; } bool HGraphBuilder::NeedsAccessCheck(uint32_t type_index) const { @@ -1584,6 +1709,34 @@ bool HGraphBuilder::NeedsAccessCheck(uint32_t type_index) const { dex_compilation_unit_->GetDexMethodIndex(), *dex_file_, type_index); } +void HGraphBuilder::BuildSwitchJumpTable(const SwitchTable& table, + const Instruction& instruction, + HInstruction* value, + uint32_t dex_pc) { + // Add the successor blocks to the current block. + uint16_t num_entries = table.GetNumEntries(); + for (size_t i = 1; i <= num_entries; i++) { + int32_t target_offset = table.GetEntryAt(i); + HBasicBlock* case_target = FindBlockStartingAt(dex_pc + target_offset); + DCHECK(case_target != nullptr); + + // Add the target block as a successor. + current_block_->AddSuccessor(case_target); + } + + // Add the default target block as the last successor. + HBasicBlock* default_target = FindBlockStartingAt(dex_pc + instruction.SizeInCodeUnits()); + DCHECK(default_target != nullptr); + current_block_->AddSuccessor(default_target); + + // Now add the Switch instruction. + int32_t starting_key = table.GetEntryAt(0); + current_block_->AddInstruction( + new (arena_) HPackedSwitch(starting_key, num_entries, value, dex_pc)); + // This block ends with control flow. + current_block_ = nullptr; +} + void HGraphBuilder::BuildPackedSwitch(const Instruction& instruction, uint32_t dex_pc) { // Verifier guarantees that the payload for PackedSwitch contains: // (a) number of entries (may be zero) @@ -1592,7 +1745,10 @@ void HGraphBuilder::BuildPackedSwitch(const Instruction& instruction, uint32_t d SwitchTable table(instruction, dex_pc, false); // Value to test against. - HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt); + HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc); + + // Starting key value. + int32_t starting_key = table.GetEntryAt(0); // Retrieve number of entries. uint16_t num_entries = table.GetNumEntries(); @@ -1600,12 +1756,21 @@ void HGraphBuilder::BuildPackedSwitch(const Instruction& instruction, uint32_t d return; } - // Chained cmp-and-branch, starting from starting_key. - int32_t starting_key = table.GetEntryAt(0); - - for (size_t i = 1; i <= num_entries; i++) { - BuildSwitchCaseHelper(instruction, i, i == num_entries, table, value, starting_key + i - 1, - table.GetEntryAt(i), dex_pc); + // Don't use a packed switch if there are very few entries. + if (num_entries > kSmallSwitchThreshold) { + BuildSwitchJumpTable(table, instruction, value, dex_pc); + } else { + // Chained cmp-and-branch, starting from starting_key. + for (size_t i = 1; i <= num_entries; i++) { + BuildSwitchCaseHelper(instruction, + i, + i == num_entries, + table, + value, + starting_key + i - 1, + table.GetEntryAt(i), + dex_pc); + } } } @@ -1617,7 +1782,7 @@ void HGraphBuilder::BuildSparseSwitch(const Instruction& instruction, uint32_t d SwitchTable table(instruction, dex_pc, true); // Value to test against. - HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt); + HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc); uint16_t num_entries = table.GetNumEntries(); @@ -1636,12 +1801,12 @@ void HGraphBuilder::BuildSwitchCaseHelper(const Instruction& instruction, size_t PotentiallyAddSuspendCheck(case_target, dex_pc); // The current case's value. - HInstruction* this_case_value = graph_->GetIntConstant(case_value_int); + HInstruction* this_case_value = graph_->GetIntConstant(case_value_int, dex_pc); // Compare value and this_case_value. - HEqual* comparison = new (arena_) HEqual(value, this_case_value); + HEqual* comparison = new (arena_) HEqual(value, this_case_value, dex_pc); current_block_->AddInstruction(comparison); - HInstruction* ifinst = new (arena_) HIf(comparison); + HInstruction* ifinst = new (arena_) HIf(comparison, dex_pc); current_block_->AddInstruction(ifinst); // Case hit: use the target offset to determine where to go. @@ -1705,29 +1870,29 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 switch (instruction.Opcode()) { case Instruction::CONST_4: { int32_t register_index = instruction.VRegA(); - HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_11n()); - UpdateLocal(register_index, constant); + HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_11n(), dex_pc); + UpdateLocal(register_index, constant, dex_pc); break; } case Instruction::CONST_16: { int32_t register_index = instruction.VRegA(); - HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21s()); - UpdateLocal(register_index, constant); + HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21s(), dex_pc); + UpdateLocal(register_index, constant, dex_pc); break; } case Instruction::CONST: { int32_t register_index = instruction.VRegA(); - HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_31i()); - UpdateLocal(register_index, constant); + HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_31i(), dex_pc); + UpdateLocal(register_index, constant, dex_pc); break; } case Instruction::CONST_HIGH16: { int32_t register_index = instruction.VRegA(); - HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21h() << 16); - UpdateLocal(register_index, constant); + HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21h() << 16, dex_pc); + UpdateLocal(register_index, constant, dex_pc); break; } @@ -1737,8 +1902,8 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 int64_t value = instruction.VRegB_21s(); value <<= 48; value >>= 48; - HLongConstant* constant = graph_->GetLongConstant(value); - UpdateLocal(register_index, constant); + HLongConstant* constant = graph_->GetLongConstant(value, dex_pc); + UpdateLocal(register_index, constant, dex_pc); break; } @@ -1748,23 +1913,23 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 int64_t value = instruction.VRegB_31i(); value <<= 32; value >>= 32; - HLongConstant* constant = graph_->GetLongConstant(value); - UpdateLocal(register_index, constant); + HLongConstant* constant = graph_->GetLongConstant(value, dex_pc); + UpdateLocal(register_index, constant, dex_pc); break; } case Instruction::CONST_WIDE: { int32_t register_index = instruction.VRegA(); - HLongConstant* constant = graph_->GetLongConstant(instruction.VRegB_51l()); - UpdateLocal(register_index, constant); + HLongConstant* constant = graph_->GetLongConstant(instruction.VRegB_51l(), dex_pc); + UpdateLocal(register_index, constant, dex_pc); break; } case Instruction::CONST_WIDE_HIGH16: { int32_t register_index = instruction.VRegA(); int64_t value = static_cast<int64_t>(instruction.VRegB_21h()) << 48; - HLongConstant* constant = graph_->GetLongConstant(value); - UpdateLocal(register_index, constant); + HLongConstant* constant = graph_->GetLongConstant(value, dex_pc); + UpdateLocal(register_index, constant, dex_pc); break; } @@ -1772,8 +1937,8 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 case Instruction::MOVE: case Instruction::MOVE_FROM16: case Instruction::MOVE_16: { - HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); - UpdateLocal(instruction.VRegA(), value); + HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc); + UpdateLocal(instruction.VRegA(), value, dex_pc); break; } @@ -1781,22 +1946,22 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 case Instruction::MOVE_WIDE: case Instruction::MOVE_WIDE_FROM16: case Instruction::MOVE_WIDE_16: { - HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimLong); - UpdateLocal(instruction.VRegA(), value); + HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimLong, dex_pc); + UpdateLocal(instruction.VRegA(), value, dex_pc); break; } case Instruction::MOVE_OBJECT: case Instruction::MOVE_OBJECT_16: case Instruction::MOVE_OBJECT_FROM16: { - HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimNot); - UpdateLocal(instruction.VRegA(), value); + HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimNot, dex_pc); + UpdateLocal(instruction.VRegA(), value, dex_pc); break; } case Instruction::RETURN_VOID_NO_BARRIER: case Instruction::RETURN_VOID: { - BuildReturn(instruction, Primitive::kPrimVoid); + BuildReturn(instruction, Primitive::kPrimVoid, dex_pc); break; } @@ -1818,24 +1983,24 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 HBasicBlock* target = FindBlockStartingAt(offset + dex_pc); DCHECK(target != nullptr); PotentiallyAddSuspendCheck(target, dex_pc); - current_block_->AddInstruction(new (arena_) HGoto()); + current_block_->AddInstruction(new (arena_) HGoto(dex_pc)); current_block_->AddSuccessor(target); current_block_ = nullptr; break; } case Instruction::RETURN: { - BuildReturn(instruction, return_type_); + BuildReturn(instruction, return_type_, dex_pc); break; } case Instruction::RETURN_OBJECT: { - BuildReturn(instruction, return_type_); + BuildReturn(instruction, return_type_, dex_pc); break; } case Instruction::RETURN_WIDE: { - BuildReturn(instruction, return_type_); + BuildReturn(instruction, return_type_, dex_pc); break; } @@ -1889,32 +2054,32 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::NEG_INT: { - Unop_12x<HNeg>(instruction, Primitive::kPrimInt); + Unop_12x<HNeg>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::NEG_LONG: { - Unop_12x<HNeg>(instruction, Primitive::kPrimLong); + Unop_12x<HNeg>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::NEG_FLOAT: { - Unop_12x<HNeg>(instruction, Primitive::kPrimFloat); + Unop_12x<HNeg>(instruction, Primitive::kPrimFloat, dex_pc); break; } case Instruction::NEG_DOUBLE: { - Unop_12x<HNeg>(instruction, Primitive::kPrimDouble); + Unop_12x<HNeg>(instruction, Primitive::kPrimDouble, dex_pc); break; } case Instruction::NOT_INT: { - Unop_12x<HNot>(instruction, Primitive::kPrimInt); + Unop_12x<HNot>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::NOT_LONG: { - Unop_12x<HNot>(instruction, Primitive::kPrimLong); + Unop_12x<HNot>(instruction, Primitive::kPrimLong, dex_pc); break; } @@ -1994,67 +2159,67 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::ADD_INT: { - Binop_23x<HAdd>(instruction, Primitive::kPrimInt); + Binop_23x<HAdd>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::ADD_LONG: { - Binop_23x<HAdd>(instruction, Primitive::kPrimLong); + Binop_23x<HAdd>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::ADD_DOUBLE: { - Binop_23x<HAdd>(instruction, Primitive::kPrimDouble); + Binop_23x<HAdd>(instruction, Primitive::kPrimDouble, dex_pc); break; } case Instruction::ADD_FLOAT: { - Binop_23x<HAdd>(instruction, Primitive::kPrimFloat); + Binop_23x<HAdd>(instruction, Primitive::kPrimFloat, dex_pc); break; } case Instruction::SUB_INT: { - Binop_23x<HSub>(instruction, Primitive::kPrimInt); + Binop_23x<HSub>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::SUB_LONG: { - Binop_23x<HSub>(instruction, Primitive::kPrimLong); + Binop_23x<HSub>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::SUB_FLOAT: { - Binop_23x<HSub>(instruction, Primitive::kPrimFloat); + Binop_23x<HSub>(instruction, Primitive::kPrimFloat, dex_pc); break; } case Instruction::SUB_DOUBLE: { - Binop_23x<HSub>(instruction, Primitive::kPrimDouble); + Binop_23x<HSub>(instruction, Primitive::kPrimDouble, dex_pc); break; } case Instruction::ADD_INT_2ADDR: { - Binop_12x<HAdd>(instruction, Primitive::kPrimInt); + Binop_12x<HAdd>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::MUL_INT: { - Binop_23x<HMul>(instruction, Primitive::kPrimInt); + Binop_23x<HMul>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::MUL_LONG: { - Binop_23x<HMul>(instruction, Primitive::kPrimLong); + Binop_23x<HMul>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::MUL_FLOAT: { - Binop_23x<HMul>(instruction, Primitive::kPrimFloat); + Binop_23x<HMul>(instruction, Primitive::kPrimFloat, dex_pc); break; } case Instruction::MUL_DOUBLE: { - Binop_23x<HMul>(instruction, Primitive::kPrimDouble); + Binop_23x<HMul>(instruction, Primitive::kPrimDouble, dex_pc); break; } @@ -2103,117 +2268,117 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::AND_INT: { - Binop_23x<HAnd>(instruction, Primitive::kPrimInt); + Binop_23x<HAnd>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::AND_LONG: { - Binop_23x<HAnd>(instruction, Primitive::kPrimLong); + Binop_23x<HAnd>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::SHL_INT: { - Binop_23x_shift<HShl>(instruction, Primitive::kPrimInt); + Binop_23x_shift<HShl>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::SHL_LONG: { - Binop_23x_shift<HShl>(instruction, Primitive::kPrimLong); + Binop_23x_shift<HShl>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::SHR_INT: { - Binop_23x_shift<HShr>(instruction, Primitive::kPrimInt); + Binop_23x_shift<HShr>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::SHR_LONG: { - Binop_23x_shift<HShr>(instruction, Primitive::kPrimLong); + Binop_23x_shift<HShr>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::USHR_INT: { - Binop_23x_shift<HUShr>(instruction, Primitive::kPrimInt); + Binop_23x_shift<HUShr>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::USHR_LONG: { - Binop_23x_shift<HUShr>(instruction, Primitive::kPrimLong); + Binop_23x_shift<HUShr>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::OR_INT: { - Binop_23x<HOr>(instruction, Primitive::kPrimInt); + Binop_23x<HOr>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::OR_LONG: { - Binop_23x<HOr>(instruction, Primitive::kPrimLong); + Binop_23x<HOr>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::XOR_INT: { - Binop_23x<HXor>(instruction, Primitive::kPrimInt); + Binop_23x<HXor>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::XOR_LONG: { - Binop_23x<HXor>(instruction, Primitive::kPrimLong); + Binop_23x<HXor>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::ADD_LONG_2ADDR: { - Binop_12x<HAdd>(instruction, Primitive::kPrimLong); + Binop_12x<HAdd>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::ADD_DOUBLE_2ADDR: { - Binop_12x<HAdd>(instruction, Primitive::kPrimDouble); + Binop_12x<HAdd>(instruction, Primitive::kPrimDouble, dex_pc); break; } case Instruction::ADD_FLOAT_2ADDR: { - Binop_12x<HAdd>(instruction, Primitive::kPrimFloat); + Binop_12x<HAdd>(instruction, Primitive::kPrimFloat, dex_pc); break; } case Instruction::SUB_INT_2ADDR: { - Binop_12x<HSub>(instruction, Primitive::kPrimInt); + Binop_12x<HSub>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::SUB_LONG_2ADDR: { - Binop_12x<HSub>(instruction, Primitive::kPrimLong); + Binop_12x<HSub>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::SUB_FLOAT_2ADDR: { - Binop_12x<HSub>(instruction, Primitive::kPrimFloat); + Binop_12x<HSub>(instruction, Primitive::kPrimFloat, dex_pc); break; } case Instruction::SUB_DOUBLE_2ADDR: { - Binop_12x<HSub>(instruction, Primitive::kPrimDouble); + Binop_12x<HSub>(instruction, Primitive::kPrimDouble, dex_pc); break; } case Instruction::MUL_INT_2ADDR: { - Binop_12x<HMul>(instruction, Primitive::kPrimInt); + Binop_12x<HMul>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::MUL_LONG_2ADDR: { - Binop_12x<HMul>(instruction, Primitive::kPrimLong); + Binop_12x<HMul>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::MUL_FLOAT_2ADDR: { - Binop_12x<HMul>(instruction, Primitive::kPrimFloat); + Binop_12x<HMul>(instruction, Primitive::kPrimFloat, dex_pc); break; } case Instruction::MUL_DOUBLE_2ADDR: { - Binop_12x<HMul>(instruction, Primitive::kPrimDouble); + Binop_12x<HMul>(instruction, Primitive::kPrimDouble, dex_pc); break; } @@ -2252,32 +2417,32 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::SHL_INT_2ADDR: { - Binop_12x_shift<HShl>(instruction, Primitive::kPrimInt); + Binop_12x_shift<HShl>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::SHL_LONG_2ADDR: { - Binop_12x_shift<HShl>(instruction, Primitive::kPrimLong); + Binop_12x_shift<HShl>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::SHR_INT_2ADDR: { - Binop_12x_shift<HShr>(instruction, Primitive::kPrimInt); + Binop_12x_shift<HShr>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::SHR_LONG_2ADDR: { - Binop_12x_shift<HShr>(instruction, Primitive::kPrimLong); + Binop_12x_shift<HShr>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::USHR_INT_2ADDR: { - Binop_12x_shift<HUShr>(instruction, Primitive::kPrimInt); + Binop_12x_shift<HUShr>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::USHR_LONG_2ADDR: { - Binop_12x_shift<HUShr>(instruction, Primitive::kPrimLong); + Binop_12x_shift<HUShr>(instruction, Primitive::kPrimLong, dex_pc); break; } @@ -2292,92 +2457,92 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::AND_INT_2ADDR: { - Binop_12x<HAnd>(instruction, Primitive::kPrimInt); + Binop_12x<HAnd>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::AND_LONG_2ADDR: { - Binop_12x<HAnd>(instruction, Primitive::kPrimLong); + Binop_12x<HAnd>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::OR_INT_2ADDR: { - Binop_12x<HOr>(instruction, Primitive::kPrimInt); + Binop_12x<HOr>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::OR_LONG_2ADDR: { - Binop_12x<HOr>(instruction, Primitive::kPrimLong); + Binop_12x<HOr>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::XOR_INT_2ADDR: { - Binop_12x<HXor>(instruction, Primitive::kPrimInt); + Binop_12x<HXor>(instruction, Primitive::kPrimInt, dex_pc); break; } case Instruction::XOR_LONG_2ADDR: { - Binop_12x<HXor>(instruction, Primitive::kPrimLong); + Binop_12x<HXor>(instruction, Primitive::kPrimLong, dex_pc); break; } case Instruction::ADD_INT_LIT16: { - Binop_22s<HAdd>(instruction, false); + Binop_22s<HAdd>(instruction, false, dex_pc); break; } case Instruction::AND_INT_LIT16: { - Binop_22s<HAnd>(instruction, false); + Binop_22s<HAnd>(instruction, false, dex_pc); break; } case Instruction::OR_INT_LIT16: { - Binop_22s<HOr>(instruction, false); + Binop_22s<HOr>(instruction, false, dex_pc); break; } case Instruction::XOR_INT_LIT16: { - Binop_22s<HXor>(instruction, false); + Binop_22s<HXor>(instruction, false, dex_pc); break; } case Instruction::RSUB_INT: { - Binop_22s<HSub>(instruction, true); + Binop_22s<HSub>(instruction, true, dex_pc); break; } case Instruction::MUL_INT_LIT16: { - Binop_22s<HMul>(instruction, false); + Binop_22s<HMul>(instruction, false, dex_pc); break; } case Instruction::ADD_INT_LIT8: { - Binop_22b<HAdd>(instruction, false); + Binop_22b<HAdd>(instruction, false, dex_pc); break; } case Instruction::AND_INT_LIT8: { - Binop_22b<HAnd>(instruction, false); + Binop_22b<HAnd>(instruction, false, dex_pc); break; } case Instruction::OR_INT_LIT8: { - Binop_22b<HOr>(instruction, false); + Binop_22b<HOr>(instruction, false, dex_pc); break; } case Instruction::XOR_INT_LIT8: { - Binop_22b<HXor>(instruction, false); + Binop_22b<HXor>(instruction, false, dex_pc); break; } case Instruction::RSUB_INT_LIT8: { - Binop_22b<HSub>(instruction, true); + Binop_22b<HSub>(instruction, true, dex_pc); break; } case Instruction::MUL_INT_LIT8: { - Binop_22b<HMul>(instruction, false); + Binop_22b<HMul>(instruction, false, dex_pc); break; } @@ -2396,17 +2561,17 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::SHL_INT_LIT8: { - Binop_22b<HShl>(instruction, false); + Binop_22b<HShl>(instruction, false, dex_pc); break; } case Instruction::SHR_INT_LIT8: { - Binop_22b<HShr>(instruction, false); + Binop_22b<HShr>(instruction, false, dex_pc); break; } case Instruction::USHR_INT_LIT8: { - Binop_22b<HUShr>(instruction, false); + Binop_22b<HUShr>(instruction, false, dex_pc); break; } @@ -2414,9 +2579,9 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 uint16_t type_index = instruction.VRegB_21c(); if (compiler_driver_->IsStringTypeIndex(type_index, dex_file_)) { int32_t register_index = instruction.VRegA(); - HFakeString* fake_string = new (arena_) HFakeString(); + HFakeString* fake_string = new (arena_) HFakeString(dex_pc); current_block_->AddInstruction(fake_string); - UpdateLocal(register_index, fake_string); + UpdateLocal(register_index, fake_string, dex_pc); } else { QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index) ? kQuickAllocObjectWithAccessCheck @@ -2428,14 +2593,14 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 type_index, *dex_compilation_unit_->GetDexFile(), entrypoint)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc); } break; } case Instruction::NEW_ARRAY: { uint16_t type_index = instruction.VRegC_22c(); - HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt); + HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt, dex_pc); QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index) ? kQuickAllocArrayWithAccessCheck : kQuickAllocArray; @@ -2445,7 +2610,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 type_index, *dex_compilation_unit_->GetDexFile(), entrypoint)); - UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction()); + UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction(), dex_pc); break; } @@ -2485,7 +2650,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 // FilledNewArray, the local needs to be updated after the array was // filled, otherwise we might overwrite an input vreg. HStoreLocal* update_local = - new (arena_) HStoreLocal(GetLocalAt(instruction.VRegA()), latest_result_); + new (arena_) HStoreLocal(GetLocalAt(instruction.VRegA()), latest_result_, dex_pc); HBasicBlock* block = latest_result_->GetBlock(); if (block == current_block_) { // MoveResult and the previous instruction are in the same block. @@ -2615,27 +2780,27 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 ARRAY_XX(_SHORT, Primitive::kPrimShort); case Instruction::ARRAY_LENGTH: { - HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot); + HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot, dex_pc); // No need for a temporary for the null check, it is the only input of the following // instruction. object = new (arena_) HNullCheck(object, dex_pc); current_block_->AddInstruction(object); - current_block_->AddInstruction(new (arena_) HArrayLength(object)); - UpdateLocal(instruction.VRegA_12x(), current_block_->GetLastInstruction()); + current_block_->AddInstruction(new (arena_) HArrayLength(object, dex_pc)); + UpdateLocal(instruction.VRegA_12x(), current_block_->GetLastInstruction(), dex_pc); break; } case Instruction::CONST_STRING: { current_block_->AddInstruction( new (arena_) HLoadString(graph_->GetCurrentMethod(), instruction.VRegB_21c(), dex_pc)); - UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction()); + UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction(), dex_pc); break; } case Instruction::CONST_STRING_JUMBO: { current_block_->AddInstruction( new (arena_) HLoadString(graph_->GetCurrentMethod(), instruction.VRegB_31c(), dex_pc)); - UpdateLocal(instruction.VRegA_31c(), current_block_->GetLastInstruction()); + UpdateLocal(instruction.VRegA_31c(), current_block_->GetLastInstruction(), dex_pc); break; } @@ -2651,29 +2816,26 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 bool can_access = compiler_driver_->CanAccessTypeWithoutChecks( dex_compilation_unit_->GetDexMethodIndex(), *dex_file_, type_index, &type_known_final, &type_known_abstract, &dont_use_is_referrers_class); - if (!can_access) { - MaybeRecordStat(MethodCompilationStat::kNotCompiledCantAccesType); - return false; - } current_block_->AddInstruction(new (arena_) HLoadClass( graph_->GetCurrentMethod(), type_index, *dex_compilation_unit_->GetDexFile(), IsOutermostCompilingClass(type_index), - dex_pc)); - UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction()); + dex_pc, + !can_access)); + UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction(), dex_pc); break; } case Instruction::MOVE_EXCEPTION: { - current_block_->AddInstruction(new (arena_) HLoadException()); - UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction()); - current_block_->AddInstruction(new (arena_) HClearException()); + current_block_->AddInstruction(new (arena_) HLoadException(dex_pc)); + UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction(), dex_pc); + current_block_->AddInstruction(new (arena_) HClearException(dex_pc)); break; } case Instruction::THROW: { - HInstruction* exception = LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot); + HInstruction* exception = LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot, dex_pc); current_block_->AddInstruction(new (arena_) HThrow(exception, dex_pc)); // A throw instruction must branch to the exit block. current_block_->AddSuccessor(exit_block_); @@ -2687,24 +2849,20 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 uint8_t destination = instruction.VRegA_22c(); uint8_t reference = instruction.VRegB_22c(); uint16_t type_index = instruction.VRegC_22c(); - if (!BuildTypeCheck(instruction, destination, reference, type_index, dex_pc)) { - return false; - } + BuildTypeCheck(instruction, destination, reference, type_index, dex_pc); break; } case Instruction::CHECK_CAST: { uint8_t reference = instruction.VRegA_21c(); uint16_t type_index = instruction.VRegB_21c(); - if (!BuildTypeCheck(instruction, -1, reference, type_index, dex_pc)) { - return false; - } + BuildTypeCheck(instruction, -1, reference, type_index, dex_pc); break; } case Instruction::MONITOR_ENTER: { current_block_->AddInstruction(new (arena_) HMonitorOperation( - LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot), + LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot, dex_pc), HMonitorOperation::kEnter, dex_pc)); break; @@ -2712,7 +2870,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 case Instruction::MONITOR_EXIT: { current_block_->AddInstruction(new (arena_) HMonitorOperation( - LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot), + LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot, dex_pc), HMonitorOperation::kExit, dex_pc)); break; @@ -2739,18 +2897,22 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 return true; } // NOLINT(readability/fn_size) -HLocal* HGraphBuilder::GetLocalAt(int register_index) const { - return locals_.Get(register_index); +HLocal* HGraphBuilder::GetLocalAt(uint32_t register_index) const { + return locals_[register_index]; } -void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const { +void HGraphBuilder::UpdateLocal(uint32_t register_index, + HInstruction* instruction, + uint32_t dex_pc) const { HLocal* local = GetLocalAt(register_index); - current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction)); + current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction, dex_pc)); } -HInstruction* HGraphBuilder::LoadLocal(int register_index, Primitive::Type type) const { +HInstruction* HGraphBuilder::LoadLocal(uint32_t register_index, + Primitive::Type type, + uint32_t dex_pc) const { HLocal* local = GetLocalAt(register_index); - current_block_->AddInstruction(new (arena_) HLoadLocal(local, type)); + current_block_->AddInstruction(new (arena_) HLoadLocal(local, type, dex_pc)); return current_block_->GetLastInstruction(); } |