diff options
Diffstat (limited to 'compiler/optimizing/builder.cc')
| -rw-r--r-- | compiler/optimizing/builder.cc | 220 |
1 files changed, 158 insertions, 62 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index d168fc80f1..64fb764937 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -119,13 +119,6 @@ bool HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) { return true; } -static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) { - if (code_item.tries_size_ > 0) { - return false; - } - return true; -} - template<typename T> void HGraphBuilder::If_22t(const Instruction& instruction, uint32_t dex_offset) { int32_t target_offset = instruction.GetTargetOffset(); @@ -164,10 +157,6 @@ void HGraphBuilder::If_21t(const Instruction& instruction, uint32_t dex_offset) } HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { - if (!CanHandleCodeItem(code_item)) { - return nullptr; - } - const uint16_t* code_ptr = code_item.insns_; const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_; code_start_ = code_ptr; @@ -187,6 +176,25 @@ HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { // start a new block, and create these blocks. ComputeBranchTargets(code_ptr, code_end); + // Also create blocks for catch handlers. + if (code_item.tries_size_ != 0) { + const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(code_item, 0); + uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr); + for (uint32_t idx = 0; idx < handlers_size; ++idx) { + CatchHandlerIterator iterator(handlers_ptr); + for (; iterator.HasNext(); iterator.Next()) { + uint32_t address = iterator.GetHandlerAddress(); + HBasicBlock* block = FindBlockStartingAt(address); + if (block == nullptr) { + block = new (arena_) HBasicBlock(graph_, address); + branch_targets_.Put(address, block); + } + block->SetIsCatchBlock(); + } + handlers_ptr = iterator.EndDataPointer(); + } + } + if (!InitializeParameters(code_item.ins_size_)) { return nullptr; } @@ -273,6 +281,14 @@ void HGraphBuilder::Unop_12x(const Instruction& instruction, Primitive::Type typ UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); } +void HGraphBuilder::Conversion_12x(const Instruction& instruction, + Primitive::Type input_type, + Primitive::Type result_type) { + HInstruction* first = LoadLocal(instruction.VRegB(), input_type); + current_block_->AddInstruction(new (arena_) HTypeConversion(result_type, first)); + 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); @@ -529,6 +545,27 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, return true; } +void HGraphBuilder::BuildCheckedDiv(uint16_t out_reg, + uint16_t first_reg, + int32_t second_reg, + uint32_t dex_offset, + Primitive::Type type, + bool second_is_lit) { + DCHECK(type == Primitive::kPrimInt); + + HInstruction* first = LoadLocal(first_reg, type); + HInstruction* second = second_is_lit ? GetIntConstant(second_reg) : LoadLocal(second_reg, type); + if (!second->IsIntConstant() || (second->AsIntConstant()->GetValue() == 0)) { + second = new (arena_) HDivZeroCheck(second, dex_offset); + Temporaries temps(graph_, 1); + current_block_->AddInstruction(second); + temps.Add(current_block_->GetLastInstruction()); + } + + current_block_->AddInstruction(new (arena_) HDiv(type, first, second)); + UpdateLocal(out_reg, current_block_->GetLastInstruction()); +} + void HGraphBuilder::BuildArrayAccess(const Instruction& instruction, uint32_t dex_offset, bool is_put, @@ -609,6 +646,60 @@ void HGraphBuilder::BuildFillArrayData(HInstruction* object, } } +void HGraphBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t dex_offset) { + Temporaries temps(graph_, 1); + HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot); + HNullCheck* null_check = new (arena_) HNullCheck(array, dex_offset); + current_block_->AddInstruction(null_check); + temps.Add(null_check); + + HInstruction* length = new (arena_) HArrayLength(null_check); + current_block_->AddInstruction(length); + + int32_t payload_offset = instruction.VRegB_31t() + dex_offset; + const Instruction::ArrayDataPayload* payload = + reinterpret_cast<const Instruction::ArrayDataPayload*>(code_start_ + payload_offset); + const uint8_t* data = payload->data; + uint32_t element_count = payload->element_count; + + // Implementation of this DEX instruction seems to be that the bounds check is + // done before doing any stores. + HInstruction* last_index = GetIntConstant(payload->element_count - 1); + current_block_->AddInstruction(new (arena_) HBoundsCheck(last_index, length, dex_offset)); + + switch (payload->element_width) { + case 1: + BuildFillArrayData(null_check, + reinterpret_cast<const int8_t*>(data), + element_count, + Primitive::kPrimByte, + dex_offset); + break; + case 2: + BuildFillArrayData(null_check, + reinterpret_cast<const int16_t*>(data), + element_count, + Primitive::kPrimShort, + dex_offset); + break; + case 4: + BuildFillArrayData(null_check, + reinterpret_cast<const int32_t*>(data), + element_count, + Primitive::kPrimInt, + dex_offset); + break; + case 8: + BuildFillWideArrayData(null_check, + reinterpret_cast<const int64_t*>(data), + element_count, + dex_offset); + break; + default: + LOG(FATAL) << "Unknown element width for " << payload->element_width; + } +} + void HGraphBuilder::BuildFillWideArrayData(HInstruction* object, const int64_t* data, uint32_t element_count, @@ -813,6 +904,16 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::NEG_FLOAT: { + Unop_12x<HNeg>(instruction, Primitive::kPrimFloat); + break; + } + + case Instruction::NEG_DOUBLE: { + Unop_12x<HNeg>(instruction, Primitive::kPrimDouble); + break; + } + case Instruction::NOT_INT: { Unop_12x<HNot>(instruction, Primitive::kPrimInt); break; @@ -823,6 +924,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::INT_TO_LONG: { + Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimLong); + break; + } + case Instruction::ADD_INT: { Binop_23x<HAdd>(instruction, Primitive::kPrimInt); break; @@ -888,6 +994,12 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::DIV_INT: { + BuildCheckedDiv(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_offset, Primitive::kPrimInt, false); + break; + } + case Instruction::DIV_FLOAT: { Binop_23x<HDiv>(instruction, Primitive::kPrimFloat); break; @@ -953,6 +1065,12 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::DIV_INT_2ADDR: { + BuildCheckedDiv(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), + dex_offset, Primitive::kPrimInt, false); + break; + } + case Instruction::DIV_FLOAT_2ADDR: { Binop_12x<HDiv>(instruction, Primitive::kPrimFloat); break; @@ -993,6 +1111,13 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::DIV_INT_LIT16: + case Instruction::DIV_INT_LIT8: { + BuildCheckedDiv(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_offset, Primitive::kPrimInt, true); + break; + } + case Instruction::NEW_INSTANCE: { current_block_->AddInstruction( new (arena_) HNewInstance(dex_offset, instruction.VRegB_21c())); @@ -1027,57 +1152,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::FILL_ARRAY_DATA: { - Temporaries temps(graph_, 1); - HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot); - HNullCheck* null_check = new (arena_) HNullCheck(array, dex_offset); - current_block_->AddInstruction(null_check); - temps.Add(null_check); - - HInstruction* length = new (arena_) HArrayLength(null_check); - current_block_->AddInstruction(length); - - int32_t payload_offset = instruction.VRegB_31t() + dex_offset; - const Instruction::ArrayDataPayload* payload = - reinterpret_cast<const Instruction::ArrayDataPayload*>(code_start_ + payload_offset); - const uint8_t* data = payload->data; - uint32_t element_count = payload->element_count; - - // Implementation of this DEX instruction seems to be that the bounds check is - // done before doing any stores. - HInstruction* last_index = GetIntConstant(payload->element_count - 1); - current_block_->AddInstruction(new (arena_) HBoundsCheck(last_index, length, dex_offset)); - - switch (payload->element_width) { - case 1: - BuildFillArrayData(null_check, - reinterpret_cast<const int8_t*>(data), - element_count, - Primitive::kPrimByte, - dex_offset); - break; - case 2: - BuildFillArrayData(null_check, - reinterpret_cast<const int16_t*>(data), - element_count, - Primitive::kPrimShort, - dex_offset); - break; - case 4: - BuildFillArrayData(null_check, - reinterpret_cast<const int32_t*>(data), - element_count, - Primitive::kPrimInt, - dex_offset); - break; - case 8: - BuildFillWideArrayData(null_check, - reinterpret_cast<const int64_t*>(data), - element_count, - dex_offset); - break; - default: - LOG(FATAL) << "Unknown element width for " << payload->element_width; - } + BuildFillArrayData(instruction, dex_offset); break; } @@ -1168,6 +1243,10 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 case Instruction::ARRAY_LENGTH: { HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot); + // No need for a temporary for the null check, it is the only input of the following + // instruction. + object = new (arena_) HNullCheck(object, dex_offset); + current_block_->AddInstruction(object); current_block_->AddInstruction(new (arena_) HArrayLength(object)); UpdateLocal(instruction.VRegA_12x(), current_block_->GetLastInstruction()); break; @@ -1202,6 +1281,23 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::MOVE_EXCEPTION: { + current_block_->AddInstruction(new (arena_) HLoadException()); + UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction()); + break; + } + + case Instruction::THROW: { + HInstruction* exception = LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot); + current_block_->AddInstruction(new (arena_) HThrow(exception, dex_offset)); + // A throw instruction must branch to the exit block. + current_block_->AddSuccessor(exit_block_); + // We finished building this block. Set the current block to null to avoid + // adding dead instructions to it. + current_block_ = nullptr; + break; + } + default: return false; } |