Merge "[view_compiler] cleanup: Use format-specific bytecode encoding functions" am: 9d599fde8e am: 6eeb8bef8d

am: decaa96ae1

Change-Id: Id65479b53822303bfb26fe1f220e9881a97f1cfc
This commit is contained in:
Eric Holk
2018-11-15 10:37:17 -08:00
committed by android-build-merger
2 changed files with 70 additions and 29 deletions

View File

@@ -301,11 +301,11 @@ void MethodBuilder::EncodeInstruction(const Instruction& instruction) {
void MethodBuilder::EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode) {
DCHECK(!instruction.dest().has_value());
if (instruction.args().size() == 0) {
buffer_.push_back(art::Instruction::RETURN_VOID);
Encode10x(art::Instruction::RETURN_VOID);
} else {
DCHECK_EQ(1, instruction.args().size());
size_t source = RegisterValue(instruction.args()[0]);
buffer_.push_back(opcode | source << 8);
Encode11x(opcode, source);
}
}
@@ -320,44 +320,40 @@ void MethodBuilder::EncodeMove(const Instruction& instruction) {
if (source.is_immediate()) {
// TODO: support more registers
DCHECK_LT(RegisterValue(*instruction.dest()), 16);
DCHECK_LT(source.value(), 16);
buffer_.push_back(art::Instruction::CONST_4 | (source.value() << 12) |
(RegisterValue(*instruction.dest()) << 8));
Encode11n(art::Instruction::CONST_4, RegisterValue(*instruction.dest()), source.value());
} else if (source.is_string()) {
constexpr size_t kMaxRegisters = 256;
DCHECK_LT(RegisterValue(*instruction.dest()), kMaxRegisters);
DCHECK_LT(source.value(), 65536); // make sure we don't need a jumbo string
buffer_.push_back(::art::Instruction::CONST_STRING | (RegisterValue(*instruction.dest()) << 8));
buffer_.push_back(source.value());
Encode21c(::art::Instruction::CONST_STRING, RegisterValue(*instruction.dest()), source.value());
} else {
UNIMPLEMENTED(FATAL);
}
}
void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode) {
// TODO: support more than one argument (i.e. the this argument) and change this to DCHECK_GE
DCHECK_LE(4, instruction.args().size());
// So far we only support the 4-bit length field, so we support at most 15 arguments, even if we
// remove the earlier limits.
DCHECK_LT(16, instruction.args().size());
constexpr size_t kMaxArgs = 5;
buffer_.push_back(instruction.args().size() << 12 | opcode);
buffer_.push_back(instruction.method_id());
CHECK_LE(instruction.args().size(), kMaxArgs);
// Encode up to four arguments
::dex::u2 args = 0;
size_t arg_shift = 0;
for (const auto& arg : instruction.args()) {
DCHECK(arg.is_variable());
args |= (0xf & RegisterValue(arg)) << arg_shift;
arg_shift += 4;
uint8_t arguments[kMaxArgs]{};
for (size_t i = 0; i < instruction.args().size(); ++i) {
CHECK(instruction.args()[i].is_variable());
arguments[i] = RegisterValue(instruction.args()[i]);
}
buffer_.push_back(args);
Encode35c(opcode,
instruction.args().size(),
instruction.method_id(),
arguments[0],
arguments[1],
arguments[2],
arguments[3],
arguments[4]);
// If there is a return value, add a move-result instruction
if (instruction.dest().has_value()) {
size_t real_reg = RegisterValue(*instruction.dest());
buffer_.push_back(real_reg << 8 | art::Instruction::MOVE_RESULT);
Encode11x(art::Instruction::MOVE_RESULT, RegisterValue(*instruction.dest()));
}
max_args_ = std::max(max_args_, instruction.args().size());
@@ -373,9 +369,9 @@ void MethodBuilder::EncodeBranch(art::Instruction::Code op, const Instruction& i
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 field_offset = buffer_.size() + 1;
Encode21c(
op, RegisterValue(test_value), LabelValue(branch_target, instruction_offset, field_offset));
}
void MethodBuilder::EncodeNew(const Instruction& instruction) {
@@ -387,8 +383,7 @@ void MethodBuilder::EncodeNew(const Instruction& instruction) {
const Value& type = instruction.args()[0];
DCHECK_LT(RegisterValue(*instruction.dest()), 256);
DCHECK(type.is_type());
buffer_.push_back(::art::Instruction::NEW_INSTANCE | (RegisterValue(*instruction.dest()) << 8));
buffer_.push_back(type.value());
Encode21c(::art::Instruction::NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value());
}
size_t MethodBuilder::RegisterValue(const Value& value) const {

View File

@@ -258,6 +258,52 @@ class MethodBuilder {
void EncodeBranch(art::Instruction::Code op, const Instruction& instruction);
void EncodeNew(const Instruction& instruction);
// Low-level instruction format encoding. See
// https://source.android.com/devices/tech/dalvik/instruction-formats for documentation of
// formats.
inline void Encode10x(art::Instruction::Code opcode) {
// 00|op
buffer_.push_back(opcode);
}
inline void Encode11x(art::Instruction::Code opcode, uint8_t a) {
// aa|op
buffer_.push_back((a << 8) | opcode);
}
inline void Encode11n(art::Instruction::Code opcode, uint8_t a, int8_t b) {
// b|a|op
// Make sure the fields are in bounds (4 bits for a, 4 bits for b).
CHECK_LT(a, 16);
CHECK_LE(-8, b);
CHECK_LT(b, 8);
buffer_.push_back(((b & 0xf) << 12) | (a << 8) | opcode);
}
inline void Encode21c(art::Instruction::Code opcode, uint8_t a, uint16_t b) {
// aa|op|bbbb
buffer_.push_back((a << 8) | opcode);
buffer_.push_back(b);
}
inline void Encode35c(art::Instruction::Code opcode, size_t a, uint16_t b, uint8_t c, uint8_t d,
uint8_t e, uint8_t f, uint8_t g) {
// a|g|op|bbbb|f|e|d|c
CHECK_LE(a, 5);
CHECK_LT(c, 16);
CHECK_LT(d, 16);
CHECK_LT(e, 16);
CHECK_LT(f, 16);
CHECK_LT(g, 16);
buffer_.push_back((a << 12) | (g << 8) | opcode);
buffer_.push_back(b);
buffer_.push_back((f << 12) | (e << 8) | (d << 4) | c);
}
// Converts a register or parameter to its DEX register number.
size_t RegisterValue(const Value& value) const;