summaryrefslogtreecommitdiff
path: root/compiler/optimizing/builder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/builder.cc')
-rw-r--r--compiler/optimizing/builder.cc220
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;
}