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

Commit c2348fa9 authored by Orion Hodson's avatar Orion Hodson Committed by Gerrit Code Review
Browse files

Merge "Switch to slicer DEX opcode definitions"

parents efa3cc41 59d07201
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

cc_defaults {
    name: "viewcompiler_defaults",
    defaults: ["libdexfile_static_defaults"],
    header_libs: [
        "libbase_headers",
    ],
@@ -30,6 +29,7 @@ cc_defaults {
        "liblog",
        "libutils",
        "libziparchive",
        "libz",
    ],
    cppflags: ["-std=c++17"],
    target: {
+49 −44
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

#include "dex_builder.h"

#include "dex/descriptors_names.h"

#include <fstream>
#include <memory>

@@ -30,8 +28,6 @@ using std::string;
using ::dex::kAccPublic;
using Op = Instruction::Op;

using Opcode = ::art::Instruction::Code;

const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; };
const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; };

@@ -43,20 +39,29 @@ constexpr uint8_t kDexFileMagic[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x38, 0x00
constexpr size_t kMaxEncodedStringLength{5};

// Converts invoke-* to invoke-*/range
constexpr Opcode InvokeToInvokeRange(Opcode opcode) {
constexpr ::dex::Opcode InvokeToInvokeRange(::dex::Opcode opcode) {
  switch (opcode) {
    case ::art::Instruction::INVOKE_VIRTUAL:
      return ::art::Instruction::INVOKE_VIRTUAL_RANGE;
    case ::art::Instruction::INVOKE_DIRECT:
      return ::art::Instruction::INVOKE_DIRECT_RANGE;
    case ::art::Instruction::INVOKE_STATIC:
      return ::art::Instruction::INVOKE_STATIC_RANGE;
    case ::art::Instruction::INVOKE_INTERFACE:
      return ::art::Instruction::INVOKE_INTERFACE_RANGE;
    case ::dex::Opcode::OP_INVOKE_VIRTUAL:
      return ::dex::Opcode::OP_INVOKE_VIRTUAL_RANGE;
    case ::dex::Opcode::OP_INVOKE_DIRECT:
      return ::dex::Opcode::OP_INVOKE_DIRECT_RANGE;
    case ::dex::Opcode::OP_INVOKE_STATIC:
      return ::dex::Opcode::OP_INVOKE_STATIC_RANGE;
    case ::dex::Opcode::OP_INVOKE_INTERFACE:
      return ::dex::Opcode::OP_INVOKE_INTERFACE_RANGE;
    default:
      LOG(FATAL) << opcode << " is not a recognized invoke opcode.";
      UNREACHABLE();
      __builtin_unreachable();
  }
}

std::string DotToDescriptor(const char* class_name) {
  std::string descriptor(class_name);
  std::replace(descriptor.begin(), descriptor.end(), '.', '/');
  if (descriptor.length() > 0 && descriptor[0] != '[') {
    descriptor = "L" + descriptor + ";";
  }
  return descriptor;
}

}  // namespace
@@ -178,7 +183,7 @@ void WriteTestDexFile(const string& filename) {
}

TypeDescriptor TypeDescriptor::FromClassname(const std::string& name) {
  return TypeDescriptor{art::DotToDescriptor(name.c_str())};
  return TypeDescriptor{DotToDescriptor(name.c_str())};
}

DexBuilder::DexBuilder() : dex_file_{std::make_shared<ir::DexFile>()} {
@@ -219,11 +224,11 @@ ir::String* DexBuilder::GetOrAddString(const std::string& string) {

ClassBuilder DexBuilder::MakeClass(const std::string& name) {
  auto* class_def = Alloc<ir::Class>();
  ir::Type* type_def = GetOrAddType(art::DotToDescriptor(name.c_str()));
  ir::Type* type_def = GetOrAddType(DotToDescriptor(name.c_str()));
  type_def->class_def = class_def;

  class_def->type = type_def;
  class_def->super_class = GetOrAddType(art::DotToDescriptor("java.lang.Object"));
  class_def->super_class = GetOrAddType(DotToDescriptor("java.lang.Object"));
  class_def->access_flags = kAccPublic;
  return ClassBuilder{this, name, class_def};
}
@@ -378,26 +383,26 @@ void MethodBuilder::EncodeInstructions() {
void MethodBuilder::EncodeInstruction(const Instruction& instruction) {
  switch (instruction.opcode()) {
    case Instruction::Op::kReturn:
      return EncodeReturn(instruction, ::art::Instruction::RETURN);
      return EncodeReturn(instruction, ::dex::Opcode::OP_RETURN);
    case Instruction::Op::kReturnObject:
      return EncodeReturn(instruction, ::art::Instruction::RETURN_OBJECT);
      return EncodeReturn(instruction, ::dex::Opcode::OP_RETURN_OBJECT);
    case Instruction::Op::kMove:
    case Instruction::Op::kMoveObject:
      return EncodeMove(instruction);
    case Instruction::Op::kInvokeVirtual:
      return EncodeInvoke(instruction, art::Instruction::INVOKE_VIRTUAL);
      return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_VIRTUAL);
    case Instruction::Op::kInvokeDirect:
      return EncodeInvoke(instruction, art::Instruction::INVOKE_DIRECT);
      return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_DIRECT);
    case Instruction::Op::kInvokeStatic:
      return EncodeInvoke(instruction, art::Instruction::INVOKE_STATIC);
      return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_STATIC);
    case Instruction::Op::kInvokeInterface:
      return EncodeInvoke(instruction, art::Instruction::INVOKE_INTERFACE);
      return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_INTERFACE);
    case Instruction::Op::kBindLabel:
      return BindLabel(instruction.args()[0]);
    case Instruction::Op::kBranchEqz:
      return EncodeBranch(art::Instruction::IF_EQZ, instruction);
      return EncodeBranch(::dex::Opcode::OP_IF_EQZ, instruction);
    case Instruction::Op::kBranchNEqz:
      return EncodeBranch(art::Instruction::IF_NEZ, instruction);
      return EncodeBranch(::dex::Opcode::OP_IF_NEZ, instruction);
    case Instruction::Op::kNew:
      return EncodeNew(instruction);
    case Instruction::Op::kCheckCast:
@@ -410,10 +415,10 @@ void MethodBuilder::EncodeInstruction(const Instruction& instruction) {
  }
}

void MethodBuilder::EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode) {
void MethodBuilder::EncodeReturn(const Instruction& instruction, ::dex::Opcode opcode) {
  CHECK(!instruction.dest().has_value());
  if (instruction.args().size() == 0) {
    Encode10x(art::Instruction::RETURN_VOID);
    Encode10x(::dex::Opcode::OP_RETURN_VOID);
  } else {
    CHECK_EQ(1, instruction.args().size());
    size_t source = RegisterValue(instruction.args()[0]);
@@ -433,27 +438,27 @@ void MethodBuilder::EncodeMove(const Instruction& instruction) {
  if (source.is_immediate()) {
    // TODO: support more registers
    CHECK_LT(RegisterValue(*instruction.dest()), 16);
    Encode11n(art::Instruction::CONST_4, RegisterValue(*instruction.dest()), source.value());
    Encode11n(::dex::Opcode::OP_CONST_4, RegisterValue(*instruction.dest()), source.value());
  } else if (source.is_string()) {
    constexpr size_t kMaxRegisters = 256;
    CHECK_LT(RegisterValue(*instruction.dest()), kMaxRegisters);
    CHECK_LT(source.value(), 65536);  // make sure we don't need a jumbo string
    Encode21c(::art::Instruction::CONST_STRING, RegisterValue(*instruction.dest()), source.value());
    Encode21c(::dex::Opcode::OP_CONST_STRING, RegisterValue(*instruction.dest()), source.value());
  } else if (source.is_variable()) {
    // For the moment, we only use this when we need to reshuffle registers for
    // an invoke instruction, meaning we are too big for the 4-bit version.
    // We'll err on the side of caution and always generate the 16-bit form of
    // the instruction.
    Opcode opcode = instruction.opcode() == Instruction::Op::kMove
                        ? ::art::Instruction::MOVE_16
                        : ::art::Instruction::MOVE_OBJECT_16;
    auto opcode = instruction.opcode() == Instruction::Op::kMove
                        ? ::dex::Opcode::OP_MOVE_16
                        : ::dex::Opcode::OP_MOVE_OBJECT_16;
    Encode32x(opcode, RegisterValue(*instruction.dest()), RegisterValue(source));
  } else {
    UNIMPLEMENTED(FATAL);
  }
}

void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode) {
void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::dex::Opcode opcode) {
  constexpr size_t kMaxArgs = 5;

  // Currently, we only support up to 5 arguments.
@@ -480,8 +485,8 @@ void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruct

    for (size_t i = 0; i < instruction.args().size(); ++i) {
      Instruction::Op move_op;
      if (opcode == ::art::Instruction::INVOKE_VIRTUAL ||
          opcode == ::art::Instruction::INVOKE_DIRECT) {
      if (opcode == ::dex::Opcode::OP_INVOKE_VIRTUAL ||
          opcode == ::dex::Opcode::OP_INVOKE_DIRECT) {
        // In this case, there is an implicit `this` argument, which is always an object.
        if (i == 0) {
          move_op = Instruction::Op::kMoveObject;
@@ -514,8 +519,8 @@ void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruct

  // If there is a return value, add a move-result instruction
  if (instruction.dest().has_value()) {
    Encode11x(instruction.result_is_object() ? art::Instruction::MOVE_RESULT_OBJECT
                                             : art::Instruction::MOVE_RESULT,
    Encode11x(instruction.result_is_object() ? ::dex::Opcode::OP_MOVE_RESULT_OBJECT
                                             : ::dex::Opcode::OP_MOVE_RESULT,
              RegisterValue(*instruction.dest()));
  }

@@ -523,7 +528,7 @@ void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruct
}

// Encodes a conditional branch that tests a single argument.
void MethodBuilder::EncodeBranch(art::Instruction::Code op, const Instruction& instruction) {
void MethodBuilder::EncodeBranch(::dex::Opcode op, const Instruction& instruction) {
  const auto& args = instruction.args();
  const auto& test_value = args[0];
  const auto& branch_target = args[1];
@@ -546,7 +551,7 @@ void MethodBuilder::EncodeNew(const Instruction& instruction) {
  const Value& type = instruction.args()[0];
  CHECK_LT(RegisterValue(*instruction.dest()), 256);
  CHECK(type.is_type());
  Encode21c(::art::Instruction::NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value());
  Encode21c(::dex::Opcode::OP_NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value());
}

void MethodBuilder::EncodeCast(const Instruction& instruction) {
@@ -558,7 +563,7 @@ void MethodBuilder::EncodeCast(const Instruction& instruction) {
  const Value& type = instruction.args()[0];
  CHECK_LT(RegisterValue(*instruction.dest()), 256);
  CHECK(type.is_type());
  Encode21c(::art::Instruction::CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
  Encode21c(::dex::Opcode::OP_CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
}

void MethodBuilder::EncodeFieldOp(const Instruction& instruction) {
@@ -569,7 +574,7 @@ void MethodBuilder::EncodeFieldOp(const Instruction& instruction) {
      CHECK(instruction.dest()->is_variable());
      CHECK_EQ(0, instruction.args().size());

      Encode21c(::art::Instruction::SGET,
      Encode21c(::dex::Opcode::OP_SGET,
                RegisterValue(*instruction.dest()),
                instruction.index_argument());
      break;
@@ -579,7 +584,7 @@ void MethodBuilder::EncodeFieldOp(const Instruction& instruction) {
      CHECK_EQ(1, args.size());
      CHECK(args[0].is_variable());

      Encode21c(::art::Instruction::SPUT, RegisterValue(args[0]), instruction.index_argument());
      Encode21c(::dex::Opcode::OP_SPUT, RegisterValue(args[0]), instruction.index_argument());
      break;
    }
    case Instruction::Op::kGetInstanceField: {
@@ -587,7 +592,7 @@ void MethodBuilder::EncodeFieldOp(const Instruction& instruction) {
      CHECK(instruction.dest()->is_variable());
      CHECK_EQ(1, instruction.args().size());

      Encode22c(::art::Instruction::IGET,
      Encode22c(::dex::Opcode::OP_IGET,
                RegisterValue(*instruction.dest()),
                RegisterValue(args[0]),
                instruction.index_argument());
@@ -599,7 +604,7 @@ void MethodBuilder::EncodeFieldOp(const Instruction& instruction) {
      CHECK(args[0].is_variable());
      CHECK(args[1].is_variable());

      Encode22c(::art::Instruction::IPUT,
      Encode22c(::dex::Opcode::OP_IPUT,
                RegisterValue(args[1]),
                RegisterValue(args[0]),
                instruction.index_argument());
+16 −13
Original line number Diff line number Diff line
@@ -24,7 +24,9 @@
#include <unordered_map>
#include <vector>

#include "dex/dex_instruction.h"
#include "android-base/logging.h"

#include "slicer/dex_bytecode.h"
#include "slicer/dex_ir.h"
#include "slicer/writer.h"

@@ -364,11 +366,11 @@ class MethodBuilder {
  // Encodes a return instruction. For instructions with no return value, the opcode field is
  // ignored. Otherwise, this specifies which return instruction will be used (return,
  // return-object, etc.)
  void EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode);
  void EncodeReturn(const Instruction& instruction, ::dex::Opcode opcode);

  void EncodeMove(const Instruction& instruction);
  void EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode);
  void EncodeBranch(art::Instruction::Code op, const Instruction& instruction);
  void EncodeInvoke(const Instruction& instruction, ::dex::Opcode opcode);
  void EncodeBranch(::dex::Opcode op, const Instruction& instruction);
  void EncodeNew(const Instruction& instruction);
  void EncodeCast(const Instruction& instruction);
  void EncodeFieldOp(const Instruction& instruction);
@@ -377,17 +379,18 @@ class MethodBuilder {
  // https://source.android.com/devices/tech/dalvik/instruction-formats for documentation of
  // formats.

  inline void Encode10x(art::Instruction::Code opcode) {
  inline void Encode10x(::dex::Opcode opcode) {
    // 00|op
    buffer_.push_back(opcode);
    static_assert(sizeof(uint8_t) == sizeof(::dex::Opcode));
    buffer_.push_back(static_cast<uint8_t>(opcode));
  }

  inline void Encode11x(art::Instruction::Code opcode, uint8_t a) {
  inline void Encode11x(::dex::Opcode 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) {
  inline void Encode11n(::dex::Opcode 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).
@@ -398,13 +401,13 @@ class MethodBuilder {
    buffer_.push_back(((b & 0xf) << 12) | (a << 8) | opcode);
  }

  inline void Encode21c(art::Instruction::Code opcode, uint8_t a, uint16_t b) {
  inline void Encode21c(::dex::Opcode opcode, uint8_t a, uint16_t b) {
    // aa|op|bbbb
    buffer_.push_back((a << 8) | opcode);
    buffer_.push_back(b);
  }

  inline void Encode22c(art::Instruction::Code opcode, uint8_t a, uint8_t b, uint16_t c) {
  inline void Encode22c(::dex::Opcode opcode, uint8_t a, uint8_t b, uint16_t c) {
    // b|a|op|bbbb
    CHECK(IsShortRegister(a));
    CHECK(IsShortRegister(b));
@@ -412,13 +415,13 @@ class MethodBuilder {
    buffer_.push_back(c);
  }

  inline void Encode32x(art::Instruction::Code opcode, uint16_t a, uint16_t b) {
  inline void Encode32x(::dex::Opcode opcode, uint16_t a, uint16_t b) {
    buffer_.push_back(opcode);
    buffer_.push_back(a);
    buffer_.push_back(b);
  }

  inline void Encode35c(art::Instruction::Code opcode, size_t a, uint16_t b, uint8_t c, uint8_t d,
  inline void Encode35c(::dex::Opcode 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

@@ -433,7 +436,7 @@ class MethodBuilder {
    buffer_.push_back((f << 12) | (e << 8) | (d << 4) | c);
  }

  inline void Encode3rc(art::Instruction::Code opcode, size_t a, uint16_t b, uint16_t c) {
  inline void Encode3rc(::dex::Opcode opcode, size_t a, uint16_t b, uint16_t c) {
    CHECK_LE(a, 255);
    buffer_.push_back((a << 8) | opcode);
    buffer_.push_back(b);