summaryrefslogtreecommitdiff
path: root/startop/view_compiler/dex_builder.cc
diff options
context:
space:
mode:
authorEric Holk <eholk@google.com>2018-11-01 15:50:24 -0700
committerEric Holk <eholk@google.com>2018-11-10 00:46:07 +0000
commitd62c5aa954dd6c995f24353dbfd13c2b0bfb112a (patch)
tree494c9b360001b979dbc88e89f7d88beba7383bff /startop/view_compiler/dex_builder.cc
parentb8740842e0da907c208ae3f1a1281c8985fcbcb9 (diff)
[view compiler] Add conditional branch instruction
This CL adds support for the if-eqz instruction. It should be easy to add additional comparisons as needed. This also introduces a new kind of Value called a Label. Labels may be created any time and then must be bound to a location in code at some point. References to labels are tracked, and when a label is bound all references are patched to refer to the concrete address. Bug: 111895153 Change-Id: I15424aec75425004f0f1f4bbc6e760bac3a6c7de
Diffstat (limited to 'startop/view_compiler/dex_builder.cc')
-rw-r--r--startop/view_compiler/dex_builder.cc64
1 files changed, 62 insertions, 2 deletions
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index 13e7f73e6713..33df6f9c37d7 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -17,7 +17,6 @@
#include "dex_builder.h"
#include "dex/descriptors_names.h"
-#include "dex/dex_instruction.h"
#include <fstream>
#include <memory>
@@ -56,6 +55,12 @@ std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) {
case Instruction::Op::kInvokeVirtual:
out << "kInvokeVirtual";
return out;
+ case Instruction::Op::kBindLabel:
+ out << "kBindLabel";
+ return out;
+ case Instruction::Op::kBranchEqz:
+ out << "kBranchEqz";
+ return out;
}
}
@@ -224,6 +229,11 @@ ir::EncodedMethod* MethodBuilder::Encode() {
Value MethodBuilder::MakeRegister() { return Value::Local(num_registers_++); }
+Value MethodBuilder::MakeLabel() {
+ labels_.push_back({});
+ return Value::Label(labels_.size() - 1);
+}
+
void MethodBuilder::AddInstruction(Instruction instruction) {
instructions_.push_back(instruction);
}
@@ -254,6 +264,10 @@ void MethodBuilder::EncodeInstruction(const Instruction& instruction) {
return EncodeMove(instruction);
case Instruction::Op::kInvokeVirtual:
return EncodeInvokeVirtual(instruction);
+ case Instruction::Op::kBindLabel:
+ return BindLabel(instruction.args()[0]);
+ case Instruction::Op::kBranchEqz:
+ return EncodeBranch(art::Instruction::IF_EQZ, instruction);
}
}
@@ -307,7 +321,22 @@ void MethodBuilder::EncodeInvokeVirtual(const Instruction& instruction) {
}
}
-size_t MethodBuilder::RegisterValue(Value value) const {
+// Encodes a conditional branch that tests a single argument.
+void MethodBuilder::EncodeBranch(art::Instruction::Code op, const Instruction& instruction) {
+ const auto& args = instruction.args();
+ const auto& test_value = args[0];
+ const auto& branch_target = args[1];
+ CHECK_EQ(2, args.size());
+ CHECK(test_value.is_variable());
+ CHECK(branch_target.is_label());
+
+ size_t instruction_offset = buffer_.size();
+ buffer_.push_back(op | (RegisterValue(test_value) << 8));
+ size_t field_offset = buffer_.size();
+ buffer_.push_back(LabelValue(branch_target, instruction_offset, field_offset));
+}
+
+size_t MethodBuilder::RegisterValue(const Value& value) const {
if (value.is_register()) {
return value.value();
} else if (value.is_parameter()) {
@@ -317,6 +346,37 @@ size_t MethodBuilder::RegisterValue(Value value) const {
return 0;
}
+void MethodBuilder::BindLabel(const Value& label_id) {
+ CHECK(label_id.is_label());
+
+ LabelData& label = labels_[label_id.value()];
+ CHECK(!label.bound_address.has_value());
+
+ label.bound_address = buffer_.size();
+
+ // patch any forward references to this label.
+ for (const auto& ref : label.references) {
+ buffer_[ref.field_offset] = *label.bound_address - ref.instruction_offset;
+ }
+ // No point keeping these around anymore.
+ label.references.clear();
+}
+
+::dex::u2 MethodBuilder::LabelValue(const Value& label_id, size_t instruction_offset,
+ size_t field_offset) {
+ CHECK(label_id.is_label());
+ LabelData& label = labels_[label_id.value()];
+
+ // Short-circuit if the label is already bound.
+ if (label.bound_address.has_value()) {
+ return *label.bound_address - instruction_offset;
+ }
+
+ // Otherwise, save a reference to where we need to back-patch later.
+ label.references.push_front(LabelReference{instruction_offset, field_offset});
+ return 0;
+}
+
const MethodDeclData& DexBuilder::GetOrDeclareMethod(TypeDescriptor type, const std::string& name,
Prototype prototype) {
MethodDeclData& entry = method_id_map_[{type, name, prototype}];