Implement array creation related DEX instructions.
Implement new-array, filled-new-array, and fill-array-data.
Change-Id: I405560d66777a57d881e384265322617ac5d3ce3
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 2f1a092..1188ec0 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -171,6 +171,7 @@
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;
// Setup the graph with the entry block and exit block.
graph_ = new (arena_) HGraph(arena_);
@@ -416,6 +417,7 @@
DCHECK_EQ(argument_index, number_of_arguments);
current_block_->AddInstruction(invoke);
+ latest_result_ = invoke;
return true;
}
@@ -503,6 +505,62 @@
}
}
+void HGraphBuilder::BuildFilledNewArray(uint32_t dex_offset,
+ uint32_t type_index,
+ uint32_t number_of_vreg_arguments,
+ bool is_range,
+ uint32_t* args,
+ uint32_t register_index) {
+ HInstruction* length = GetIntConstant(number_of_vreg_arguments);
+ HInstruction* object = new (arena_) HNewArray(length, dex_offset, type_index);
+ current_block_->AddInstruction(object);
+
+ const char* descriptor = dex_file_->StringByTypeIdx(type_index);
+ DCHECK_EQ(descriptor[0], '[') << descriptor;
+ char primitive = descriptor[1];
+ DCHECK(primitive == 'I'
+ || primitive == 'L'
+ || primitive == '[') << descriptor;
+ bool is_reference_array = (primitive == 'L') || (primitive == '[');
+ Primitive::Type type = is_reference_array ? Primitive::kPrimNot : Primitive::kPrimInt;
+
+ Temporaries temps(graph_, 1);
+ 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 = GetIntConstant(i);
+ current_block_->AddInstruction(
+ new (arena_) HArraySet(object, index, value, type, dex_offset));
+ }
+ latest_result_ = object;
+}
+
+template <typename T>
+void HGraphBuilder::BuildFillArrayData(HInstruction* object,
+ const T* data,
+ uint32_t element_count,
+ Primitive::Type anticipated_type,
+ uint32_t dex_offset) {
+ for (uint32_t i = 0; i < element_count; ++i) {
+ HInstruction* index = GetIntConstant(i);
+ HInstruction* value = GetIntConstant(data[i]);
+ current_block_->AddInstruction(new (arena_) HArraySet(
+ object, index, value, anticipated_type, dex_offset));
+ }
+}
+
+void HGraphBuilder::BuildFillWideArrayData(HInstruction* object,
+ const uint64_t* data,
+ uint32_t element_count,
+ uint32_t dex_offset) {
+ for (uint32_t i = 0; i < element_count; ++i) {
+ HInstruction* index = GetIntConstant(i);
+ HInstruction* value = GetLongConstant(data[i]);
+ current_block_->AddInstruction(new (arena_) HArraySet(
+ object, index, value, Primitive::kPrimLong, dex_offset));
+ }
+}
+
void HGraphBuilder::PotentiallyAddSuspendCheck(int32_t target_offset, uint32_t dex_offset) {
if (target_offset <= 0) {
// Unconditionnally add a suspend check to backward branches. We can remove
@@ -807,10 +865,88 @@
break;
}
+ case Instruction::NEW_ARRAY: {
+ HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt);
+ current_block_->AddInstruction(
+ new (arena_) HNewArray(length, dex_offset, instruction.VRegC_22c()));
+ UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction());
+ break;
+ }
+
+ case Instruction::FILLED_NEW_ARRAY: {
+ uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
+ uint32_t type_index = instruction.VRegB_35c();
+ uint32_t args[5];
+ instruction.GetVarArgs(args);
+ BuildFilledNewArray(dex_offset, type_index, number_of_vreg_arguments, false, args, 0);
+ break;
+ }
+
+ case Instruction::FILLED_NEW_ARRAY_RANGE: {
+ uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
+ uint32_t type_index = instruction.VRegB_3rc();
+ uint32_t register_index = instruction.VRegC_3rc();
+ BuildFilledNewArray(
+ dex_offset, type_index, number_of_vreg_arguments, true, nullptr, register_index);
+ break;
+ }
+
+ 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, data, element_count, Primitive::kPrimByte, dex_offset);
+ break;
+ case 2:
+ BuildFillArrayData(null_check,
+ reinterpret_cast<const uint16_t*>(data),
+ element_count,
+ Primitive::kPrimShort,
+ dex_offset);
+ break;
+ case 4:
+ BuildFillArrayData(null_check,
+ reinterpret_cast<const uint32_t*>(data),
+ element_count,
+ Primitive::kPrimInt,
+ dex_offset);
+ break;
+ case 8:
+ BuildFillWideArrayData(null_check,
+ reinterpret_cast<const uint64_t*>(data),
+ element_count,
+ dex_offset);
+ break;
+ default:
+ LOG(FATAL) << "Unknown element width for " << payload->element_width;
+ }
+ break;
+ }
+
case Instruction::MOVE_RESULT:
case Instruction::MOVE_RESULT_WIDE:
case Instruction::MOVE_RESULT_OBJECT:
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+ UpdateLocal(instruction.VRegA(), latest_result_);
+ latest_result_ = nullptr;
break;
case Instruction::CMP_LONG: {