Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d599fde authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "[view_compiler] cleanup: Use format-specific bytecode encoding functions"

parents 2583def7 1c0f3f09
Loading
Loading
Loading
Loading
+26 −31
Original line number Diff line number Diff line
@@ -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 {
+46 −0
Original line number Diff line number Diff line
@@ -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;