Merge "Switch to slicer DEX opcode definitions"
This commit is contained in:
@@ -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: {
|
||||
|
||||
@@ -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,22 +39,31 @@ 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
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) {
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user