diff options
| -rw-r--r-- | startop/view_compiler/dex_builder.cc | 57 | ||||
| -rw-r--r-- | startop/view_compiler/dex_builder.h | 46 | 
2 files changed, 72 insertions, 31 deletions
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc index 1fde692451f1..906d64c1f619 100644 --- a/startop/view_compiler/dex_builder.cc +++ b/startop/view_compiler/dex_builder.cc @@ -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()); - -  buffer_.push_back(instruction.args().size() << 12 | opcode); -  buffer_.push_back(instruction.method_id()); - -  // 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; +  constexpr size_t kMaxArgs = 5; + +  CHECK_LE(instruction.args().size(), kMaxArgs); + +  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 { diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h index 181d1db0082a..adf82bf9a01a 100644 --- a/startop/view_compiler/dex_builder.h +++ b/startop/view_compiler/dex_builder.h @@ -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;  |