Loading startop/view_compiler/dex_builder.cc +26 −31 Original line number Diff line number Diff line Loading @@ -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); } } Loading @@ -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()); Loading @@ -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) { Loading @@ -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 { Loading startop/view_compiler/dex_builder.h +46 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading
startop/view_compiler/dex_builder.cc +26 −31 Original line number Diff line number Diff line Loading @@ -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); } } Loading @@ -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()); Loading @@ -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) { Loading @@ -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 { Loading
startop/view_compiler/dex_builder.h +46 −0 Original line number Diff line number Diff line Loading @@ -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; Loading