libredex/IROpcode.cpp (1,637 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "IROpcode.h"
#include "Debug.h"
#include "DexClass.h"
#include "DexInstruction.h"
#include "DexOpcode.h"
#include "DexUtil.h"
#include "Show.h"
std::ostream& operator<<(std::ostream& os, const IROpcode& op) {
os << show(op);
return os;
}
namespace opcode {
// clang-format off
Ref ref(IROpcode opcode) {
switch (opcode) {
#define OP(uc, lc, ref, ...) \
case OPCODE_##uc: \
return ref;
#define IOP(uc, lc, ref, ...) \
case IOPCODE_##uc: \
return ref;
#define OPRANGE(...)
#include "IROpcodes.def"
}
not_reached_log("Unexpected opcode 0x%x", opcode);
}
// clang-format on
IROpcode from_dex_opcode(DexOpcode op) {
switch (op) {
case DOPCODE_NOP:
return OPCODE_NOP;
case DOPCODE_MOVE:
return OPCODE_MOVE;
case DOPCODE_MOVE_WIDE:
return OPCODE_MOVE_WIDE;
case DOPCODE_MOVE_OBJECT:
return OPCODE_MOVE_OBJECT;
case DOPCODE_MOVE_RESULT:
return OPCODE_MOVE_RESULT;
case DOPCODE_MOVE_RESULT_WIDE:
return OPCODE_MOVE_RESULT_WIDE;
case DOPCODE_MOVE_RESULT_OBJECT:
return OPCODE_MOVE_RESULT_OBJECT;
case DOPCODE_MOVE_EXCEPTION:
return OPCODE_MOVE_EXCEPTION;
case DOPCODE_RETURN_VOID:
return OPCODE_RETURN_VOID;
case DOPCODE_RETURN:
return OPCODE_RETURN;
case DOPCODE_RETURN_WIDE:
return OPCODE_RETURN_WIDE;
case DOPCODE_RETURN_OBJECT:
return OPCODE_RETURN_OBJECT;
case DOPCODE_CONST_4:
return OPCODE_CONST;
case DOPCODE_MONITOR_ENTER:
return OPCODE_MONITOR_ENTER;
case DOPCODE_MONITOR_EXIT:
return OPCODE_MONITOR_EXIT;
case DOPCODE_THROW:
return OPCODE_THROW;
case DOPCODE_GOTO:
return OPCODE_GOTO;
case DOPCODE_NEG_INT:
return OPCODE_NEG_INT;
case DOPCODE_NOT_INT:
return OPCODE_NOT_INT;
case DOPCODE_NEG_LONG:
return OPCODE_NEG_LONG;
case DOPCODE_NOT_LONG:
return OPCODE_NOT_LONG;
case DOPCODE_NEG_FLOAT:
return OPCODE_NEG_FLOAT;
case DOPCODE_NEG_DOUBLE:
return OPCODE_NEG_DOUBLE;
case DOPCODE_INT_TO_LONG:
return OPCODE_INT_TO_LONG;
case DOPCODE_INT_TO_FLOAT:
return OPCODE_INT_TO_FLOAT;
case DOPCODE_INT_TO_DOUBLE:
return OPCODE_INT_TO_DOUBLE;
case DOPCODE_LONG_TO_INT:
return OPCODE_LONG_TO_INT;
case DOPCODE_LONG_TO_FLOAT:
return OPCODE_LONG_TO_FLOAT;
case DOPCODE_LONG_TO_DOUBLE:
return OPCODE_LONG_TO_DOUBLE;
case DOPCODE_FLOAT_TO_INT:
return OPCODE_FLOAT_TO_INT;
case DOPCODE_FLOAT_TO_LONG:
return OPCODE_FLOAT_TO_LONG;
case DOPCODE_FLOAT_TO_DOUBLE:
return OPCODE_FLOAT_TO_DOUBLE;
case DOPCODE_DOUBLE_TO_INT:
return OPCODE_DOUBLE_TO_INT;
case DOPCODE_DOUBLE_TO_LONG:
return OPCODE_DOUBLE_TO_LONG;
case DOPCODE_DOUBLE_TO_FLOAT:
return OPCODE_DOUBLE_TO_FLOAT;
case DOPCODE_INT_TO_BYTE:
return OPCODE_INT_TO_BYTE;
case DOPCODE_INT_TO_CHAR:
return OPCODE_INT_TO_CHAR;
case DOPCODE_INT_TO_SHORT:
return OPCODE_INT_TO_SHORT;
case DOPCODE_ADD_INT_2ADDR:
return OPCODE_ADD_INT;
case DOPCODE_SUB_INT_2ADDR:
return OPCODE_SUB_INT;
case DOPCODE_MUL_INT_2ADDR:
return OPCODE_MUL_INT;
case DOPCODE_DIV_INT_2ADDR:
return OPCODE_DIV_INT;
case DOPCODE_REM_INT_2ADDR:
return OPCODE_REM_INT;
case DOPCODE_AND_INT_2ADDR:
return OPCODE_AND_INT;
case DOPCODE_OR_INT_2ADDR:
return OPCODE_OR_INT;
case DOPCODE_XOR_INT_2ADDR:
return OPCODE_XOR_INT;
case DOPCODE_SHL_INT_2ADDR:
return OPCODE_SHL_INT;
case DOPCODE_SHR_INT_2ADDR:
return OPCODE_SHR_INT;
case DOPCODE_USHR_INT_2ADDR:
return OPCODE_USHR_INT;
case DOPCODE_ADD_LONG_2ADDR:
return OPCODE_ADD_LONG;
case DOPCODE_SUB_LONG_2ADDR:
return OPCODE_SUB_LONG;
case DOPCODE_MUL_LONG_2ADDR:
return OPCODE_MUL_LONG;
case DOPCODE_DIV_LONG_2ADDR:
return OPCODE_DIV_LONG;
case DOPCODE_REM_LONG_2ADDR:
return OPCODE_REM_LONG;
case DOPCODE_AND_LONG_2ADDR:
return OPCODE_AND_LONG;
case DOPCODE_OR_LONG_2ADDR:
return OPCODE_OR_LONG;
case DOPCODE_XOR_LONG_2ADDR:
return OPCODE_XOR_LONG;
case DOPCODE_SHL_LONG_2ADDR:
return OPCODE_SHL_LONG;
case DOPCODE_SHR_LONG_2ADDR:
return OPCODE_SHR_LONG;
case DOPCODE_USHR_LONG_2ADDR:
return OPCODE_USHR_LONG;
case DOPCODE_ADD_FLOAT_2ADDR:
return OPCODE_ADD_FLOAT;
case DOPCODE_SUB_FLOAT_2ADDR:
return OPCODE_SUB_FLOAT;
case DOPCODE_MUL_FLOAT_2ADDR:
return OPCODE_MUL_FLOAT;
case DOPCODE_DIV_FLOAT_2ADDR:
return OPCODE_DIV_FLOAT;
case DOPCODE_REM_FLOAT_2ADDR:
return OPCODE_REM_FLOAT;
case DOPCODE_ADD_DOUBLE_2ADDR:
return OPCODE_ADD_DOUBLE;
case DOPCODE_SUB_DOUBLE_2ADDR:
return OPCODE_SUB_DOUBLE;
case DOPCODE_MUL_DOUBLE_2ADDR:
return OPCODE_MUL_DOUBLE;
case DOPCODE_DIV_DOUBLE_2ADDR:
return OPCODE_DIV_DOUBLE;
case DOPCODE_REM_DOUBLE_2ADDR:
return OPCODE_REM_DOUBLE;
case DOPCODE_ARRAY_LENGTH:
return OPCODE_ARRAY_LENGTH;
case DOPCODE_MOVE_FROM16:
return OPCODE_MOVE;
case DOPCODE_MOVE_WIDE_FROM16:
return OPCODE_MOVE_WIDE;
case DOPCODE_MOVE_OBJECT_FROM16:
return OPCODE_MOVE_OBJECT;
case DOPCODE_CONST_16:
return OPCODE_CONST;
case DOPCODE_CONST_HIGH16:
return OPCODE_CONST;
case DOPCODE_CONST_WIDE_16:
return OPCODE_CONST_WIDE;
case DOPCODE_CONST_WIDE_HIGH16:
return OPCODE_CONST_WIDE;
case DOPCODE_GOTO_16:
return OPCODE_GOTO;
case DOPCODE_CMPL_FLOAT:
return OPCODE_CMPL_FLOAT;
case DOPCODE_CMPG_FLOAT:
return OPCODE_CMPG_FLOAT;
case DOPCODE_CMPL_DOUBLE:
return OPCODE_CMPL_DOUBLE;
case DOPCODE_CMPG_DOUBLE:
return OPCODE_CMPG_DOUBLE;
case DOPCODE_CMP_LONG:
return OPCODE_CMP_LONG;
case DOPCODE_IF_EQ:
return OPCODE_IF_EQ;
case DOPCODE_IF_NE:
return OPCODE_IF_NE;
case DOPCODE_IF_LT:
return OPCODE_IF_LT;
case DOPCODE_IF_GE:
return OPCODE_IF_GE;
case DOPCODE_IF_GT:
return OPCODE_IF_GT;
case DOPCODE_IF_LE:
return OPCODE_IF_LE;
case DOPCODE_IF_EQZ:
return OPCODE_IF_EQZ;
case DOPCODE_IF_NEZ:
return OPCODE_IF_NEZ;
case DOPCODE_IF_LTZ:
return OPCODE_IF_LTZ;
case DOPCODE_IF_GEZ:
return OPCODE_IF_GEZ;
case DOPCODE_IF_GTZ:
return OPCODE_IF_GTZ;
case DOPCODE_IF_LEZ:
return OPCODE_IF_LEZ;
case DOPCODE_AGET:
return OPCODE_AGET;
case DOPCODE_AGET_WIDE:
return OPCODE_AGET_WIDE;
case DOPCODE_AGET_OBJECT:
return OPCODE_AGET_OBJECT;
case DOPCODE_AGET_BOOLEAN:
return OPCODE_AGET_BOOLEAN;
case DOPCODE_AGET_BYTE:
return OPCODE_AGET_BYTE;
case DOPCODE_AGET_CHAR:
return OPCODE_AGET_CHAR;
case DOPCODE_AGET_SHORT:
return OPCODE_AGET_SHORT;
case DOPCODE_APUT:
return OPCODE_APUT;
case DOPCODE_APUT_WIDE:
return OPCODE_APUT_WIDE;
case DOPCODE_APUT_OBJECT:
return OPCODE_APUT_OBJECT;
case DOPCODE_APUT_BOOLEAN:
return OPCODE_APUT_BOOLEAN;
case DOPCODE_APUT_BYTE:
return OPCODE_APUT_BYTE;
case DOPCODE_APUT_CHAR:
return OPCODE_APUT_CHAR;
case DOPCODE_APUT_SHORT:
return OPCODE_APUT_SHORT;
case DOPCODE_ADD_INT:
return OPCODE_ADD_INT;
case DOPCODE_SUB_INT:
return OPCODE_SUB_INT;
case DOPCODE_MUL_INT:
return OPCODE_MUL_INT;
case DOPCODE_DIV_INT:
return OPCODE_DIV_INT;
case DOPCODE_REM_INT:
return OPCODE_REM_INT;
case DOPCODE_AND_INT:
return OPCODE_AND_INT;
case DOPCODE_OR_INT:
return OPCODE_OR_INT;
case DOPCODE_XOR_INT:
return OPCODE_XOR_INT;
case DOPCODE_SHL_INT:
return OPCODE_SHL_INT;
case DOPCODE_SHR_INT:
return OPCODE_SHR_INT;
case DOPCODE_USHR_INT:
return OPCODE_USHR_INT;
case DOPCODE_ADD_LONG:
return OPCODE_ADD_LONG;
case DOPCODE_SUB_LONG:
return OPCODE_SUB_LONG;
case DOPCODE_MUL_LONG:
return OPCODE_MUL_LONG;
case DOPCODE_DIV_LONG:
return OPCODE_DIV_LONG;
case DOPCODE_REM_LONG:
return OPCODE_REM_LONG;
case DOPCODE_AND_LONG:
return OPCODE_AND_LONG;
case DOPCODE_OR_LONG:
return OPCODE_OR_LONG;
case DOPCODE_XOR_LONG:
return OPCODE_XOR_LONG;
case DOPCODE_SHL_LONG:
return OPCODE_SHL_LONG;
case DOPCODE_SHR_LONG:
return OPCODE_SHR_LONG;
case DOPCODE_USHR_LONG:
return OPCODE_USHR_LONG;
case DOPCODE_ADD_FLOAT:
return OPCODE_ADD_FLOAT;
case DOPCODE_SUB_FLOAT:
return OPCODE_SUB_FLOAT;
case DOPCODE_MUL_FLOAT:
return OPCODE_MUL_FLOAT;
case DOPCODE_DIV_FLOAT:
return OPCODE_DIV_FLOAT;
case DOPCODE_REM_FLOAT:
return OPCODE_REM_FLOAT;
case DOPCODE_ADD_DOUBLE:
return OPCODE_ADD_DOUBLE;
case DOPCODE_SUB_DOUBLE:
return OPCODE_SUB_DOUBLE;
case DOPCODE_MUL_DOUBLE:
return OPCODE_MUL_DOUBLE;
case DOPCODE_DIV_DOUBLE:
return OPCODE_DIV_DOUBLE;
case DOPCODE_REM_DOUBLE:
return OPCODE_REM_DOUBLE;
case DOPCODE_ADD_INT_LIT16:
return OPCODE_ADD_INT_LIT16;
case DOPCODE_RSUB_INT:
return OPCODE_RSUB_INT;
case DOPCODE_MUL_INT_LIT16:
return OPCODE_MUL_INT_LIT16;
case DOPCODE_DIV_INT_LIT16:
return OPCODE_DIV_INT_LIT16;
case DOPCODE_REM_INT_LIT16:
return OPCODE_REM_INT_LIT16;
case DOPCODE_AND_INT_LIT16:
return OPCODE_AND_INT_LIT16;
case DOPCODE_OR_INT_LIT16:
return OPCODE_OR_INT_LIT16;
case DOPCODE_XOR_INT_LIT16:
return OPCODE_XOR_INT_LIT16;
case DOPCODE_ADD_INT_LIT8:
return OPCODE_ADD_INT_LIT8;
case DOPCODE_RSUB_INT_LIT8:
return OPCODE_RSUB_INT_LIT8;
case DOPCODE_MUL_INT_LIT8:
return OPCODE_MUL_INT_LIT8;
case DOPCODE_DIV_INT_LIT8:
return OPCODE_DIV_INT_LIT8;
case DOPCODE_REM_INT_LIT8:
return OPCODE_REM_INT_LIT8;
case DOPCODE_AND_INT_LIT8:
return OPCODE_AND_INT_LIT8;
case DOPCODE_OR_INT_LIT8:
return OPCODE_OR_INT_LIT8;
case DOPCODE_XOR_INT_LIT8:
return OPCODE_XOR_INT_LIT8;
case DOPCODE_SHL_INT_LIT8:
return OPCODE_SHL_INT_LIT8;
case DOPCODE_SHR_INT_LIT8:
return OPCODE_SHR_INT_LIT8;
case DOPCODE_USHR_INT_LIT8:
return OPCODE_USHR_INT_LIT8;
case DOPCODE_MOVE_16:
return OPCODE_MOVE;
case DOPCODE_MOVE_WIDE_16:
return OPCODE_MOVE_WIDE;
case DOPCODE_MOVE_OBJECT_16:
return OPCODE_MOVE_OBJECT;
case DOPCODE_CONST:
return OPCODE_CONST;
case DOPCODE_CONST_WIDE_32:
return OPCODE_CONST_WIDE;
case DOPCODE_FILL_ARRAY_DATA:
return OPCODE_FILL_ARRAY_DATA;
case DOPCODE_GOTO_32:
return OPCODE_GOTO;
case DOPCODE_PACKED_SWITCH:
case DOPCODE_SPARSE_SWITCH:
return OPCODE_SWITCH;
case DOPCODE_CONST_WIDE:
return OPCODE_CONST_WIDE;
case DOPCODE_IGET:
return OPCODE_IGET;
case DOPCODE_IGET_WIDE:
return OPCODE_IGET_WIDE;
case DOPCODE_IGET_OBJECT:
return OPCODE_IGET_OBJECT;
case DOPCODE_IGET_BOOLEAN:
return OPCODE_IGET_BOOLEAN;
case DOPCODE_IGET_BYTE:
return OPCODE_IGET_BYTE;
case DOPCODE_IGET_CHAR:
return OPCODE_IGET_CHAR;
case DOPCODE_IGET_SHORT:
return OPCODE_IGET_SHORT;
case DOPCODE_IPUT:
return OPCODE_IPUT;
case DOPCODE_IPUT_WIDE:
return OPCODE_IPUT_WIDE;
case DOPCODE_IPUT_OBJECT:
return OPCODE_IPUT_OBJECT;
case DOPCODE_IPUT_BOOLEAN:
return OPCODE_IPUT_BOOLEAN;
case DOPCODE_IPUT_BYTE:
return OPCODE_IPUT_BYTE;
case DOPCODE_IPUT_CHAR:
return OPCODE_IPUT_CHAR;
case DOPCODE_IPUT_SHORT:
return OPCODE_IPUT_SHORT;
case DOPCODE_SGET:
return OPCODE_SGET;
case DOPCODE_SGET_WIDE:
return OPCODE_SGET_WIDE;
case DOPCODE_SGET_OBJECT:
return OPCODE_SGET_OBJECT;
case DOPCODE_SGET_BOOLEAN:
return OPCODE_SGET_BOOLEAN;
case DOPCODE_SGET_BYTE:
return OPCODE_SGET_BYTE;
case DOPCODE_SGET_CHAR:
return OPCODE_SGET_CHAR;
case DOPCODE_SGET_SHORT:
return OPCODE_SGET_SHORT;
case DOPCODE_SPUT:
return OPCODE_SPUT;
case DOPCODE_SPUT_WIDE:
return OPCODE_SPUT_WIDE;
case DOPCODE_SPUT_OBJECT:
return OPCODE_SPUT_OBJECT;
case DOPCODE_SPUT_BOOLEAN:
return OPCODE_SPUT_BOOLEAN;
case DOPCODE_SPUT_BYTE:
return OPCODE_SPUT_BYTE;
case DOPCODE_SPUT_CHAR:
return OPCODE_SPUT_CHAR;
case DOPCODE_SPUT_SHORT:
return OPCODE_SPUT_SHORT;
case DOPCODE_INVOKE_VIRTUAL:
return OPCODE_INVOKE_VIRTUAL;
case DOPCODE_INVOKE_SUPER:
return OPCODE_INVOKE_SUPER;
case DOPCODE_INVOKE_DIRECT:
return OPCODE_INVOKE_DIRECT;
case DOPCODE_INVOKE_STATIC:
return OPCODE_INVOKE_STATIC;
case DOPCODE_INVOKE_INTERFACE:
return OPCODE_INVOKE_INTERFACE;
case DOPCODE_INVOKE_POLYMORPHIC:
return OPCODE_INVOKE_POLYMORPHIC;
case DOPCODE_INVOKE_CUSTOM:
return OPCODE_INVOKE_CUSTOM;
case DOPCODE_INVOKE_VIRTUAL_RANGE:
return OPCODE_INVOKE_VIRTUAL;
case DOPCODE_INVOKE_SUPER_RANGE:
return OPCODE_INVOKE_SUPER;
case DOPCODE_INVOKE_DIRECT_RANGE:
return OPCODE_INVOKE_DIRECT;
case DOPCODE_INVOKE_STATIC_RANGE:
return OPCODE_INVOKE_STATIC;
case DOPCODE_INVOKE_INTERFACE_RANGE:
return OPCODE_INVOKE_INTERFACE;
case DOPCODE_INVOKE_CUSTOM_RANGE:
return OPCODE_INVOKE_CUSTOM;
case DOPCODE_INVOKE_POLYMORPHIC_RANGE:
return OPCODE_INVOKE_POLYMORPHIC;
case DOPCODE_CONST_STRING:
case DOPCODE_CONST_STRING_JUMBO:
return OPCODE_CONST_STRING;
case DOPCODE_CONST_CLASS:
return OPCODE_CONST_CLASS;
case DOPCODE_CHECK_CAST:
return OPCODE_CHECK_CAST;
case DOPCODE_INSTANCE_OF:
return OPCODE_INSTANCE_OF;
case DOPCODE_NEW_INSTANCE:
return OPCODE_NEW_INSTANCE;
case DOPCODE_NEW_ARRAY:
return OPCODE_NEW_ARRAY;
case DOPCODE_FILLED_NEW_ARRAY:
return OPCODE_FILLED_NEW_ARRAY;
case DOPCODE_FILLED_NEW_ARRAY_RANGE:
return OPCODE_FILLED_NEW_ARRAY;
case FOPCODE_PACKED_SWITCH:
case FOPCODE_SPARSE_SWITCH:
case FOPCODE_FILLED_ARRAY:
not_reached_log("Cannot create IROpcode from %s", SHOW(op));
// clang-format off
SWITCH_FORMAT_QUICK_FIELD_REF {
not_reached_log("Invalid use of a quick ref opcode %02x\n", op);
}
SWITCH_FORMAT_QUICK_METHOD_REF {
not_reached_log("Invalid use of a quick method opcode %02x\n", op);
}
SWITCH_FORMAT_RETURN_VOID_NO_BARRIER {
not_reached_log("Invalid use of return-void-no-barrier opcode %02x\n", op);
}
// clang-format on
}
not_reached_log("Unknown opcode %02x\n", op);
}
DexOpcode to_dex_opcode(IROpcode op) {
switch (op) {
case OPCODE_NOP:
return DOPCODE_NOP;
case OPCODE_MOVE:
return DOPCODE_MOVE;
case OPCODE_MOVE_WIDE:
return DOPCODE_MOVE_WIDE;
case OPCODE_MOVE_OBJECT:
return DOPCODE_MOVE_OBJECT;
case OPCODE_MOVE_RESULT:
return DOPCODE_MOVE_RESULT;
case OPCODE_MOVE_RESULT_WIDE:
return DOPCODE_MOVE_RESULT_WIDE;
case OPCODE_MOVE_RESULT_OBJECT:
return DOPCODE_MOVE_RESULT_OBJECT;
case OPCODE_MOVE_EXCEPTION:
return DOPCODE_MOVE_EXCEPTION;
case OPCODE_RETURN_VOID:
return DOPCODE_RETURN_VOID;
case OPCODE_RETURN:
return DOPCODE_RETURN;
case OPCODE_RETURN_WIDE:
return DOPCODE_RETURN_WIDE;
case OPCODE_RETURN_OBJECT:
return DOPCODE_RETURN_OBJECT;
case OPCODE_MONITOR_ENTER:
return DOPCODE_MONITOR_ENTER;
case OPCODE_MONITOR_EXIT:
return DOPCODE_MONITOR_EXIT;
case OPCODE_THROW:
return DOPCODE_THROW;
case OPCODE_GOTO:
return DOPCODE_GOTO;
case OPCODE_NEG_INT:
return DOPCODE_NEG_INT;
case OPCODE_NOT_INT:
return DOPCODE_NOT_INT;
case OPCODE_NEG_LONG:
return DOPCODE_NEG_LONG;
case OPCODE_NOT_LONG:
return DOPCODE_NOT_LONG;
case OPCODE_NEG_FLOAT:
return DOPCODE_NEG_FLOAT;
case OPCODE_NEG_DOUBLE:
return DOPCODE_NEG_DOUBLE;
case OPCODE_INT_TO_LONG:
return DOPCODE_INT_TO_LONG;
case OPCODE_INT_TO_FLOAT:
return DOPCODE_INT_TO_FLOAT;
case OPCODE_INT_TO_DOUBLE:
return DOPCODE_INT_TO_DOUBLE;
case OPCODE_LONG_TO_INT:
return DOPCODE_LONG_TO_INT;
case OPCODE_LONG_TO_FLOAT:
return DOPCODE_LONG_TO_FLOAT;
case OPCODE_LONG_TO_DOUBLE:
return DOPCODE_LONG_TO_DOUBLE;
case OPCODE_FLOAT_TO_INT:
return DOPCODE_FLOAT_TO_INT;
case OPCODE_FLOAT_TO_LONG:
return DOPCODE_FLOAT_TO_LONG;
case OPCODE_FLOAT_TO_DOUBLE:
return DOPCODE_FLOAT_TO_DOUBLE;
case OPCODE_DOUBLE_TO_INT:
return DOPCODE_DOUBLE_TO_INT;
case OPCODE_DOUBLE_TO_LONG:
return DOPCODE_DOUBLE_TO_LONG;
case OPCODE_DOUBLE_TO_FLOAT:
return DOPCODE_DOUBLE_TO_FLOAT;
case OPCODE_INT_TO_BYTE:
return DOPCODE_INT_TO_BYTE;
case OPCODE_INT_TO_CHAR:
return DOPCODE_INT_TO_CHAR;
case OPCODE_INT_TO_SHORT:
return DOPCODE_INT_TO_SHORT;
case OPCODE_ARRAY_LENGTH:
return DOPCODE_ARRAY_LENGTH;
case OPCODE_CMPL_FLOAT:
return DOPCODE_CMPL_FLOAT;
case OPCODE_CMPG_FLOAT:
return DOPCODE_CMPG_FLOAT;
case OPCODE_CMPL_DOUBLE:
return DOPCODE_CMPL_DOUBLE;
case OPCODE_CMPG_DOUBLE:
return DOPCODE_CMPG_DOUBLE;
case OPCODE_CMP_LONG:
return DOPCODE_CMP_LONG;
case OPCODE_IF_EQ:
return DOPCODE_IF_EQ;
case OPCODE_IF_NE:
return DOPCODE_IF_NE;
case OPCODE_IF_LT:
return DOPCODE_IF_LT;
case OPCODE_IF_GE:
return DOPCODE_IF_GE;
case OPCODE_IF_GT:
return DOPCODE_IF_GT;
case OPCODE_IF_LE:
return DOPCODE_IF_LE;
case OPCODE_IF_EQZ:
return DOPCODE_IF_EQZ;
case OPCODE_IF_NEZ:
return DOPCODE_IF_NEZ;
case OPCODE_IF_LTZ:
return DOPCODE_IF_LTZ;
case OPCODE_IF_GEZ:
return DOPCODE_IF_GEZ;
case OPCODE_IF_GTZ:
return DOPCODE_IF_GTZ;
case OPCODE_IF_LEZ:
return DOPCODE_IF_LEZ;
case OPCODE_AGET:
return DOPCODE_AGET;
case OPCODE_AGET_WIDE:
return DOPCODE_AGET_WIDE;
case OPCODE_AGET_OBJECT:
return DOPCODE_AGET_OBJECT;
case OPCODE_AGET_BOOLEAN:
return DOPCODE_AGET_BOOLEAN;
case OPCODE_AGET_BYTE:
return DOPCODE_AGET_BYTE;
case OPCODE_AGET_CHAR:
return DOPCODE_AGET_CHAR;
case OPCODE_AGET_SHORT:
return DOPCODE_AGET_SHORT;
case OPCODE_APUT:
return DOPCODE_APUT;
case OPCODE_APUT_WIDE:
return DOPCODE_APUT_WIDE;
case OPCODE_APUT_OBJECT:
return DOPCODE_APUT_OBJECT;
case OPCODE_APUT_BOOLEAN:
return DOPCODE_APUT_BOOLEAN;
case OPCODE_APUT_BYTE:
return DOPCODE_APUT_BYTE;
case OPCODE_APUT_CHAR:
return DOPCODE_APUT_CHAR;
case OPCODE_APUT_SHORT:
return DOPCODE_APUT_SHORT;
case OPCODE_ADD_INT:
return DOPCODE_ADD_INT;
case OPCODE_SUB_INT:
return DOPCODE_SUB_INT;
case OPCODE_MUL_INT:
return DOPCODE_MUL_INT;
case OPCODE_DIV_INT:
return DOPCODE_DIV_INT;
case OPCODE_REM_INT:
return DOPCODE_REM_INT;
case OPCODE_AND_INT:
return DOPCODE_AND_INT;
case OPCODE_OR_INT:
return DOPCODE_OR_INT;
case OPCODE_XOR_INT:
return DOPCODE_XOR_INT;
case OPCODE_SHL_INT:
return DOPCODE_SHL_INT;
case OPCODE_SHR_INT:
return DOPCODE_SHR_INT;
case OPCODE_USHR_INT:
return DOPCODE_USHR_INT;
case OPCODE_ADD_LONG:
return DOPCODE_ADD_LONG;
case OPCODE_SUB_LONG:
return DOPCODE_SUB_LONG;
case OPCODE_MUL_LONG:
return DOPCODE_MUL_LONG;
case OPCODE_DIV_LONG:
return DOPCODE_DIV_LONG;
case OPCODE_REM_LONG:
return DOPCODE_REM_LONG;
case OPCODE_AND_LONG:
return DOPCODE_AND_LONG;
case OPCODE_OR_LONG:
return DOPCODE_OR_LONG;
case OPCODE_XOR_LONG:
return DOPCODE_XOR_LONG;
case OPCODE_SHL_LONG:
return DOPCODE_SHL_LONG;
case OPCODE_SHR_LONG:
return DOPCODE_SHR_LONG;
case OPCODE_USHR_LONG:
return DOPCODE_USHR_LONG;
case OPCODE_ADD_FLOAT:
return DOPCODE_ADD_FLOAT;
case OPCODE_SUB_FLOAT:
return DOPCODE_SUB_FLOAT;
case OPCODE_MUL_FLOAT:
return DOPCODE_MUL_FLOAT;
case OPCODE_DIV_FLOAT:
return DOPCODE_DIV_FLOAT;
case OPCODE_REM_FLOAT:
return DOPCODE_REM_FLOAT;
case OPCODE_ADD_DOUBLE:
return DOPCODE_ADD_DOUBLE;
case OPCODE_SUB_DOUBLE:
return DOPCODE_SUB_DOUBLE;
case OPCODE_MUL_DOUBLE:
return DOPCODE_MUL_DOUBLE;
case OPCODE_DIV_DOUBLE:
return DOPCODE_DIV_DOUBLE;
case OPCODE_REM_DOUBLE:
return DOPCODE_REM_DOUBLE;
case OPCODE_ADD_INT_LIT16:
return DOPCODE_ADD_INT_LIT16;
case OPCODE_RSUB_INT:
return DOPCODE_RSUB_INT;
case OPCODE_MUL_INT_LIT16:
return DOPCODE_MUL_INT_LIT16;
case OPCODE_DIV_INT_LIT16:
return DOPCODE_DIV_INT_LIT16;
case OPCODE_REM_INT_LIT16:
return DOPCODE_REM_INT_LIT16;
case OPCODE_AND_INT_LIT16:
return DOPCODE_AND_INT_LIT16;
case OPCODE_OR_INT_LIT16:
return DOPCODE_OR_INT_LIT16;
case OPCODE_XOR_INT_LIT16:
return DOPCODE_XOR_INT_LIT16;
case OPCODE_ADD_INT_LIT8:
return DOPCODE_ADD_INT_LIT8;
case OPCODE_RSUB_INT_LIT8:
return DOPCODE_RSUB_INT_LIT8;
case OPCODE_MUL_INT_LIT8:
return DOPCODE_MUL_INT_LIT8;
case OPCODE_DIV_INT_LIT8:
return DOPCODE_DIV_INT_LIT8;
case OPCODE_REM_INT_LIT8:
return DOPCODE_REM_INT_LIT8;
case OPCODE_AND_INT_LIT8:
return DOPCODE_AND_INT_LIT8;
case OPCODE_OR_INT_LIT8:
return DOPCODE_OR_INT_LIT8;
case OPCODE_XOR_INT_LIT8:
return DOPCODE_XOR_INT_LIT8;
case OPCODE_SHL_INT_LIT8:
return DOPCODE_SHL_INT_LIT8;
case OPCODE_SHR_INT_LIT8:
return DOPCODE_SHR_INT_LIT8;
case OPCODE_USHR_INT_LIT8:
return DOPCODE_USHR_INT_LIT8;
case OPCODE_CONST:
return DOPCODE_CONST;
case OPCODE_FILL_ARRAY_DATA:
return DOPCODE_FILL_ARRAY_DATA;
case OPCODE_SWITCH:
return DOPCODE_SPARSE_SWITCH;
case OPCODE_CONST_WIDE:
return DOPCODE_CONST_WIDE;
case OPCODE_IGET:
return DOPCODE_IGET;
case OPCODE_IGET_WIDE:
return DOPCODE_IGET_WIDE;
case OPCODE_IGET_OBJECT:
return DOPCODE_IGET_OBJECT;
case OPCODE_IGET_BOOLEAN:
return DOPCODE_IGET_BOOLEAN;
case OPCODE_IGET_BYTE:
return DOPCODE_IGET_BYTE;
case OPCODE_IGET_CHAR:
return DOPCODE_IGET_CHAR;
case OPCODE_IGET_SHORT:
return DOPCODE_IGET_SHORT;
case OPCODE_IPUT:
return DOPCODE_IPUT;
case OPCODE_IPUT_WIDE:
return DOPCODE_IPUT_WIDE;
case OPCODE_IPUT_OBJECT:
return DOPCODE_IPUT_OBJECT;
case OPCODE_IPUT_BOOLEAN:
return DOPCODE_IPUT_BOOLEAN;
case OPCODE_IPUT_BYTE:
return DOPCODE_IPUT_BYTE;
case OPCODE_IPUT_CHAR:
return DOPCODE_IPUT_CHAR;
case OPCODE_IPUT_SHORT:
return DOPCODE_IPUT_SHORT;
case OPCODE_SGET:
return DOPCODE_SGET;
case OPCODE_SGET_WIDE:
return DOPCODE_SGET_WIDE;
case OPCODE_SGET_OBJECT:
return DOPCODE_SGET_OBJECT;
case OPCODE_SGET_BOOLEAN:
return DOPCODE_SGET_BOOLEAN;
case OPCODE_SGET_BYTE:
return DOPCODE_SGET_BYTE;
case OPCODE_SGET_CHAR:
return DOPCODE_SGET_CHAR;
case OPCODE_SGET_SHORT:
return DOPCODE_SGET_SHORT;
case OPCODE_SPUT:
return DOPCODE_SPUT;
case OPCODE_SPUT_WIDE:
return DOPCODE_SPUT_WIDE;
case OPCODE_SPUT_OBJECT:
return DOPCODE_SPUT_OBJECT;
case OPCODE_SPUT_BOOLEAN:
return DOPCODE_SPUT_BOOLEAN;
case OPCODE_SPUT_BYTE:
return DOPCODE_SPUT_BYTE;
case OPCODE_SPUT_CHAR:
return DOPCODE_SPUT_CHAR;
case OPCODE_SPUT_SHORT:
return DOPCODE_SPUT_SHORT;
case OPCODE_INVOKE_VIRTUAL:
return DOPCODE_INVOKE_VIRTUAL;
case OPCODE_INVOKE_SUPER:
return DOPCODE_INVOKE_SUPER;
case OPCODE_INVOKE_DIRECT:
return DOPCODE_INVOKE_DIRECT;
case OPCODE_INVOKE_STATIC:
return DOPCODE_INVOKE_STATIC;
case OPCODE_INVOKE_INTERFACE:
return DOPCODE_INVOKE_INTERFACE;
case OPCODE_INVOKE_CUSTOM:
return DOPCODE_INVOKE_CUSTOM;
case OPCODE_INVOKE_POLYMORPHIC:
return DOPCODE_INVOKE_POLYMORPHIC;
case OPCODE_CONST_STRING:
return DOPCODE_CONST_STRING;
case OPCODE_CONST_CLASS:
return DOPCODE_CONST_CLASS;
case OPCODE_CHECK_CAST:
return DOPCODE_CHECK_CAST;
case OPCODE_INSTANCE_OF:
return DOPCODE_INSTANCE_OF;
case OPCODE_NEW_INSTANCE:
return DOPCODE_NEW_INSTANCE;
case OPCODE_NEW_ARRAY:
return DOPCODE_NEW_ARRAY;
case OPCODE_FILLED_NEW_ARRAY:
return DOPCODE_FILLED_NEW_ARRAY;
default:
not_reached_log("Cannot create DexOpcode from %s", SHOW(op));
}
}
DexOpcode range_version(IROpcode op) {
switch (op) {
case OPCODE_INVOKE_DIRECT:
return DOPCODE_INVOKE_DIRECT_RANGE;
case OPCODE_INVOKE_STATIC:
return DOPCODE_INVOKE_STATIC_RANGE;
case OPCODE_INVOKE_SUPER:
return DOPCODE_INVOKE_SUPER_RANGE;
case OPCODE_INVOKE_VIRTUAL:
return DOPCODE_INVOKE_VIRTUAL_RANGE;
case OPCODE_INVOKE_INTERFACE:
return DOPCODE_INVOKE_INTERFACE_RANGE;
case OPCODE_INVOKE_CUSTOM:
return DOPCODE_INVOKE_CUSTOM_RANGE;
case OPCODE_INVOKE_POLYMORPHIC:
return DOPCODE_INVOKE_POLYMORPHIC_RANGE;
case OPCODE_FILLED_NEW_ARRAY:
return DOPCODE_FILLED_NEW_ARRAY_RANGE;
default:
not_reached();
}
}
bool has_variable_srcs_size(IROpcode op) {
switch (op) {
case OPCODE_INVOKE_VIRTUAL:
case OPCODE_INVOKE_DIRECT:
case OPCODE_INVOKE_SUPER:
case OPCODE_INVOKE_STATIC:
case OPCODE_INVOKE_INTERFACE:
case OPCODE_INVOKE_CUSTOM:
case OPCODE_INVOKE_POLYMORPHIC:
case OPCODE_FILLED_NEW_ARRAY:
return true;
default:
return false;
}
}
bool may_throw(IROpcode op) {
switch (op) {
case OPCODE_CONST_STRING:
case OPCODE_CONST_CLASS:
case IOPCODE_INIT_CLASS:
case OPCODE_MONITOR_ENTER:
case OPCODE_MONITOR_EXIT:
case OPCODE_CHECK_CAST:
case OPCODE_INSTANCE_OF:
case OPCODE_ARRAY_LENGTH:
case OPCODE_NEW_INSTANCE:
case OPCODE_NEW_ARRAY:
case OPCODE_FILLED_NEW_ARRAY:
case OPCODE_AGET:
case OPCODE_AGET_WIDE:
case OPCODE_AGET_OBJECT:
case OPCODE_AGET_BOOLEAN:
case OPCODE_AGET_BYTE:
case OPCODE_AGET_CHAR:
case OPCODE_AGET_SHORT:
case OPCODE_APUT:
case OPCODE_APUT_WIDE:
case OPCODE_APUT_OBJECT:
case OPCODE_APUT_BOOLEAN:
case OPCODE_APUT_BYTE:
case OPCODE_APUT_CHAR:
case OPCODE_APUT_SHORT:
case OPCODE_IGET:
case OPCODE_IGET_WIDE:
case OPCODE_IGET_OBJECT:
case OPCODE_IGET_BOOLEAN:
case OPCODE_IGET_BYTE:
case OPCODE_IGET_CHAR:
case OPCODE_IGET_SHORT:
case OPCODE_IPUT:
case OPCODE_IPUT_WIDE:
case OPCODE_IPUT_OBJECT:
case OPCODE_IPUT_BOOLEAN:
case OPCODE_IPUT_BYTE:
case OPCODE_IPUT_CHAR:
case OPCODE_IPUT_SHORT:
case OPCODE_SGET:
case OPCODE_SGET_WIDE:
case OPCODE_SGET_OBJECT:
case OPCODE_SGET_BOOLEAN:
case OPCODE_SGET_BYTE:
case OPCODE_SGET_CHAR:
case OPCODE_SGET_SHORT:
case OPCODE_SPUT:
case OPCODE_SPUT_WIDE:
case OPCODE_SPUT_OBJECT:
case OPCODE_SPUT_BOOLEAN:
case OPCODE_SPUT_BYTE:
case OPCODE_SPUT_CHAR:
case OPCODE_SPUT_SHORT:
case OPCODE_INVOKE_VIRTUAL:
case OPCODE_INVOKE_SUPER:
case OPCODE_INVOKE_DIRECT:
case OPCODE_INVOKE_STATIC:
case OPCODE_INVOKE_INTERFACE:
case OPCODE_INVOKE_CUSTOM:
case OPCODE_INVOKE_POLYMORPHIC:
case OPCODE_DIV_INT:
case OPCODE_REM_INT:
case OPCODE_DIV_LONG:
case OPCODE_REM_LONG:
case OPCODE_DIV_INT_LIT16:
case OPCODE_REM_INT_LIT16:
case OPCODE_DIV_INT_LIT8:
case OPCODE_REM_INT_LIT8:
return true;
default:
return false;
}
}
Branchingness branchingness(IROpcode op) {
if (may_throw(op)) {
return BRANCH_THROW;
}
switch (op) {
case OPCODE_RETURN_VOID:
case OPCODE_RETURN:
case OPCODE_RETURN_WIDE:
case OPCODE_RETURN_OBJECT:
return BRANCH_RETURN;
case OPCODE_THROW:
return BRANCH_THROW;
case OPCODE_GOTO:
return BRANCH_GOTO;
case OPCODE_SWITCH:
return BRANCH_SWITCH;
case OPCODE_IF_EQ:
case OPCODE_IF_NE:
case OPCODE_IF_LT:
case OPCODE_IF_GE:
case OPCODE_IF_GT:
case OPCODE_IF_LE:
case OPCODE_IF_EQZ:
case OPCODE_IF_NEZ:
case OPCODE_IF_LTZ:
case OPCODE_IF_GEZ:
case OPCODE_IF_GTZ:
case OPCODE_IF_LEZ:
return BRANCH_IF;
default:
return BRANCH_NONE;
}
}
bool has_range_form(IROpcode op) {
switch (op) {
case OPCODE_INVOKE_DIRECT:
case OPCODE_INVOKE_STATIC:
case OPCODE_INVOKE_SUPER:
case OPCODE_INVOKE_VIRTUAL:
case OPCODE_INVOKE_INTERFACE:
case OPCODE_INVOKE_CUSTOM:
case OPCODE_INVOKE_POLYMORPHIC:
case OPCODE_FILLED_NEW_ARRAY:
return true;
default:
return false;
}
}
bool is_move_result_any(IROpcode op) {
return is_a_move_result(op) || is_a_move_result_pseudo(op);
}
bool is_commutative(IROpcode opcode) {
switch (opcode) {
case OPCODE_AND_INT:
case OPCODE_AND_LONG:
case OPCODE_OR_INT:
case OPCODE_OR_LONG:
case OPCODE_XOR_INT:
case OPCODE_XOR_LONG:
case OPCODE_ADD_INT:
case OPCODE_ADD_LONG:
case OPCODE_ADD_FLOAT:
case OPCODE_ADD_DOUBLE:
case OPCODE_MUL_INT:
case OPCODE_MUL_LONG:
case OPCODE_MUL_FLOAT:
case OPCODE_MUL_DOUBLE:
return true;
default:
return false;
}
}
bool is_binop64(IROpcode op) {
switch (op) {
case OPCODE_ADD_INT:
case OPCODE_SUB_INT:
case OPCODE_MUL_INT:
case OPCODE_DIV_INT:
case OPCODE_REM_INT:
case OPCODE_AND_INT:
case OPCODE_OR_INT:
case OPCODE_XOR_INT:
case OPCODE_SHL_INT:
case OPCODE_SHR_INT:
case OPCODE_USHR_INT:
case OPCODE_ADD_FLOAT:
case OPCODE_SUB_FLOAT:
case OPCODE_MUL_FLOAT:
case OPCODE_DIV_FLOAT:
case OPCODE_REM_FLOAT: {
return false;
}
case OPCODE_ADD_LONG:
case OPCODE_SUB_LONG:
case OPCODE_MUL_LONG:
case OPCODE_DIV_LONG:
case OPCODE_REM_LONG:
case OPCODE_AND_LONG:
case OPCODE_OR_LONG:
case OPCODE_XOR_LONG:
case OPCODE_SHL_LONG:
case OPCODE_SHR_LONG:
case OPCODE_USHR_LONG:
case OPCODE_ADD_DOUBLE:
case OPCODE_SUB_DOUBLE:
case OPCODE_MUL_DOUBLE:
case OPCODE_DIV_DOUBLE:
case OPCODE_REM_DOUBLE: {
return true;
}
default: {
not_reached_log("Unexpected opcode: %s\n", SHOW(op));
}
}
}
IROpcode load_param_to_move(IROpcode op) {
switch (op) {
case IOPCODE_LOAD_PARAM:
return OPCODE_MOVE;
case IOPCODE_LOAD_PARAM_OBJECT:
return OPCODE_MOVE_OBJECT;
case IOPCODE_LOAD_PARAM_WIDE:
return OPCODE_MOVE_WIDE;
default:
not_reached_log("Expected param op, got %s", SHOW(op));
}
}
IROpcode iput_to_move(IROpcode op) {
switch (op) {
case OPCODE_IPUT:
case OPCODE_IPUT_BOOLEAN:
case OPCODE_IPUT_BYTE:
case OPCODE_IPUT_CHAR:
case OPCODE_IPUT_SHORT:
return OPCODE_MOVE;
case OPCODE_IPUT_OBJECT:
return OPCODE_MOVE_OBJECT;
case OPCODE_IPUT_WIDE:
return OPCODE_MOVE_WIDE;
default:
not_reached_log("Expected iput, got %s", SHOW(op));
}
}
IROpcode iget_to_move(IROpcode op) {
switch (op) {
case OPCODE_IGET:
case OPCODE_IGET_BOOLEAN:
case OPCODE_IGET_BYTE:
case OPCODE_IGET_CHAR:
case OPCODE_IGET_SHORT:
return OPCODE_MOVE;
case OPCODE_IGET_OBJECT:
return OPCODE_MOVE_OBJECT;
case OPCODE_IGET_WIDE:
return OPCODE_MOVE_WIDE;
default:
not_reached_log("Expected iget, got %s", SHOW(op));
}
}
IROpcode move_result_pseudo_for_iget(IROpcode op) {
switch (op) {
case OPCODE_IGET_BOOLEAN:
case OPCODE_IGET_BYTE:
case OPCODE_IGET_SHORT:
case OPCODE_IGET_CHAR:
case OPCODE_IGET:
return IOPCODE_MOVE_RESULT_PSEUDO;
case OPCODE_IGET_OBJECT:
return IOPCODE_MOVE_RESULT_PSEUDO_OBJECT;
case OPCODE_IGET_WIDE:
return IOPCODE_MOVE_RESULT_PSEUDO_WIDE;
default:
not_reached_log("Unexpected opcode %s", SHOW(op));
}
}
IROpcode move_result_pseudo_for_sget(IROpcode op) {
switch (op) {
case OPCODE_SGET_BOOLEAN:
case OPCODE_SGET_BYTE:
case OPCODE_SGET_SHORT:
case OPCODE_SGET_CHAR:
case OPCODE_SGET:
return IOPCODE_MOVE_RESULT_PSEUDO;
case OPCODE_SGET_OBJECT:
return IOPCODE_MOVE_RESULT_PSEUDO_OBJECT;
case OPCODE_SGET_WIDE:
return IOPCODE_MOVE_RESULT_PSEUDO_WIDE;
default:
not_reached_log("Unexpected opcode %s", SHOW(op));
}
}
IROpcode move_result_for_invoke(const DexMethodRef* method) {
auto rtype = method->get_proto()->get_rtype();
return type::is_wide_type(rtype) ? OPCODE_MOVE_RESULT_WIDE
: type::is_object(rtype) ? OPCODE_MOVE_RESULT_OBJECT
: OPCODE_MOVE_RESULT;
}
IROpcode invoke_for_method(const DexMethod* method) {
always_assert(method->is_def());
if (is_static(method)) {
return OPCODE_INVOKE_STATIC;
} else if (is_private(method) || is_constructor(method)) {
return OPCODE_INVOKE_DIRECT;
} else {
always_assert(method->is_virtual());
return is_interface(type_class(method->get_class()))
? OPCODE_INVOKE_INTERFACE
: OPCODE_INVOKE_VIRTUAL;
}
}
IROpcode return_opcode(const DexType* type) {
return type::is_wide_type(type) ? OPCODE_RETURN_WIDE
: type::is_object(type) ? OPCODE_RETURN_OBJECT
: OPCODE_RETURN;
}
IROpcode load_opcode(const DexType* type) {
return type::is_wide_type(type) ? IOPCODE_LOAD_PARAM_WIDE
: type::is_object(type) ? IOPCODE_LOAD_PARAM_OBJECT
: IOPCODE_LOAD_PARAM;
}
IROpcode move_opcode(const DexType* type) {
return type::is_wide_type(type) ? OPCODE_MOVE_WIDE
: type::is_object(type) ? OPCODE_MOVE_OBJECT
: OPCODE_MOVE;
}
IROpcode move_result_to_move(IROpcode op) {
switch (op) {
case OPCODE_MOVE_RESULT:
return OPCODE_MOVE;
case OPCODE_MOVE_RESULT_OBJECT:
return OPCODE_MOVE_OBJECT;
case OPCODE_MOVE_RESULT_WIDE:
return OPCODE_MOVE_WIDE;
default:
not_reached();
}
}
IROpcode return_to_move(IROpcode op) {
switch (op) {
case OPCODE_RETURN:
return OPCODE_MOVE;
case OPCODE_RETURN_WIDE:
return OPCODE_MOVE_WIDE;
case OPCODE_RETURN_OBJECT:
return OPCODE_MOVE_OBJECT;
default:
not_reached();
}
}
IROpcode move_result_to_pseudo(IROpcode op) {
switch (op) {
case OPCODE_MOVE_RESULT:
return IOPCODE_MOVE_RESULT_PSEUDO;
case OPCODE_MOVE_RESULT_OBJECT:
return IOPCODE_MOVE_RESULT_PSEUDO_OBJECT;
case OPCODE_MOVE_RESULT_WIDE:
return IOPCODE_MOVE_RESULT_PSEUDO_WIDE;
default:
not_reached();
}
}
IROpcode pseudo_to_move_result(IROpcode op) {
switch (op) {
case IOPCODE_MOVE_RESULT_PSEUDO:
return OPCODE_MOVE_RESULT;
case IOPCODE_MOVE_RESULT_PSEUDO_OBJECT:
return OPCODE_MOVE_RESULT_OBJECT;
case IOPCODE_MOVE_RESULT_PSEUDO_WIDE:
return OPCODE_MOVE_RESULT_WIDE;
default:
not_reached();
}
}
IROpcode iget_opcode_for_field(const DexField* field) {
switch (type::to_datatype(field->get_type())) {
case DataType::Array:
case DataType::Object:
return OPCODE_IGET_OBJECT;
case DataType::Boolean:
return OPCODE_IGET_BOOLEAN;
case DataType::Byte:
return OPCODE_IGET_BYTE;
case DataType::Char:
return OPCODE_IGET_CHAR;
case DataType::Short:
return OPCODE_IGET_SHORT;
case DataType::Int:
case DataType::Float:
return OPCODE_IGET;
case DataType::Long:
case DataType::Double:
return OPCODE_IGET_WIDE;
case DataType::Void:
default:
not_reached();
}
}
IROpcode sget_opcode_for_field(const DexField* field) {
switch (type::to_datatype(field->get_type())) {
case DataType::Array:
case DataType::Object:
return OPCODE_SGET_OBJECT;
case DataType::Boolean:
return OPCODE_SGET_BOOLEAN;
case DataType::Byte:
return OPCODE_SGET_BYTE;
case DataType::Char:
return OPCODE_SGET_CHAR;
case DataType::Short:
return OPCODE_SGET_SHORT;
case DataType::Int:
case DataType::Float:
return OPCODE_SGET;
case DataType::Long:
case DataType::Double:
return OPCODE_SGET_WIDE;
case DataType::Void:
break;
}
not_reached();
}
IROpcode invert_conditional_branch(IROpcode op) {
switch (op) {
case OPCODE_IF_EQ:
return OPCODE_IF_NE;
case OPCODE_IF_NE:
return OPCODE_IF_EQ;
case OPCODE_IF_LT:
return OPCODE_IF_GE;
case OPCODE_IF_GE:
return OPCODE_IF_LT;
case OPCODE_IF_GT:
return OPCODE_IF_LE;
case OPCODE_IF_LE:
return OPCODE_IF_GT;
case OPCODE_IF_EQZ:
return OPCODE_IF_NEZ;
case OPCODE_IF_NEZ:
return OPCODE_IF_EQZ;
case OPCODE_IF_LTZ:
return OPCODE_IF_GEZ;
case OPCODE_IF_GEZ:
return OPCODE_IF_LTZ;
case OPCODE_IF_GTZ:
return OPCODE_IF_LEZ;
case OPCODE_IF_LEZ:
return OPCODE_IF_GTZ;
default:
not_reached_log("Invalid conditional opcode %s", SHOW(op));
}
}
bool has_side_effects(IROpcode opc) {
switch (opc) {
case OPCODE_RETURN_VOID:
case OPCODE_RETURN:
case OPCODE_RETURN_WIDE:
case OPCODE_RETURN_OBJECT:
case OPCODE_MONITOR_ENTER:
case OPCODE_MONITOR_EXIT:
case OPCODE_FILL_ARRAY_DATA:
case OPCODE_THROW:
case OPCODE_GOTO:
case OPCODE_SWITCH:
case OPCODE_IF_EQ:
case OPCODE_IF_NE:
case OPCODE_IF_LT:
case OPCODE_IF_GE:
case OPCODE_IF_GT:
case OPCODE_IF_LE:
case OPCODE_IF_EQZ:
case OPCODE_IF_NEZ:
case OPCODE_IF_LTZ:
case OPCODE_IF_GEZ:
case OPCODE_IF_GTZ:
case OPCODE_IF_LEZ:
case OPCODE_APUT:
case OPCODE_APUT_WIDE:
case OPCODE_APUT_OBJECT:
case OPCODE_APUT_BOOLEAN:
case OPCODE_APUT_BYTE:
case OPCODE_APUT_CHAR:
case OPCODE_APUT_SHORT:
case OPCODE_IPUT:
case OPCODE_IPUT_WIDE:
case OPCODE_IPUT_OBJECT:
case OPCODE_IPUT_BOOLEAN:
case OPCODE_IPUT_BYTE:
case OPCODE_IPUT_CHAR:
case OPCODE_IPUT_SHORT:
case OPCODE_SPUT:
case OPCODE_SPUT_WIDE:
case OPCODE_SPUT_OBJECT:
case OPCODE_SPUT_BOOLEAN:
case OPCODE_SPUT_BYTE:
case OPCODE_SPUT_CHAR:
case OPCODE_SPUT_SHORT:
case OPCODE_INVOKE_VIRTUAL:
case OPCODE_INVOKE_SUPER:
case OPCODE_INVOKE_DIRECT:
case OPCODE_INVOKE_STATIC:
case OPCODE_INVOKE_INTERFACE:
case IOPCODE_LOAD_PARAM:
case IOPCODE_LOAD_PARAM_OBJECT:
case IOPCODE_LOAD_PARAM_WIDE:
case IOPCODE_INIT_CLASS:
return true;
default:
return false;
}
not_reached();
}
} // namespace opcode
namespace opcode_impl {
bool has_dest(IROpcode op) {
if (opcode::is_an_internal(op)) {
return op != IOPCODE_INIT_CLASS;
} else {
auto dex_op = opcode::to_dex_opcode(op);
return !opcode::may_throw(op) && dex_opcode::has_dest(dex_op);
}
}
bool has_move_result_pseudo(IROpcode op) {
if (opcode::is_an_internal(op)) {
return false;
} else if (op == OPCODE_CHECK_CAST) {
return true;
} else {
auto dex_op = opcode::to_dex_opcode(op);
return dex_opcode::has_dest(dex_op) && opcode::may_throw(op);
}
}
unsigned min_srcs_size(IROpcode op) {
if (opcode::is_an_internal(op)) {
return 0;
} else {
auto dex_op = opcode::to_dex_opcode(op);
return dex_opcode::min_srcs_size(dex_op);
}
}
bool dest_is_wide(IROpcode op) {
switch (op) {
case OPCODE_MOVE_WIDE:
case OPCODE_MOVE_RESULT_WIDE:
case OPCODE_CONST_WIDE:
case OPCODE_AGET_WIDE:
case OPCODE_IGET_WIDE:
case OPCODE_SGET_WIDE:
case OPCODE_NEG_LONG:
case OPCODE_NOT_LONG:
case OPCODE_NEG_DOUBLE:
case OPCODE_INT_TO_LONG:
case OPCODE_INT_TO_DOUBLE:
case OPCODE_LONG_TO_DOUBLE:
case OPCODE_FLOAT_TO_LONG:
case OPCODE_FLOAT_TO_DOUBLE:
case OPCODE_DOUBLE_TO_LONG:
case OPCODE_ADD_LONG:
case OPCODE_SUB_LONG:
case OPCODE_MUL_LONG:
case OPCODE_DIV_LONG:
case OPCODE_REM_LONG:
case OPCODE_AND_LONG:
case OPCODE_OR_LONG:
case OPCODE_XOR_LONG:
case OPCODE_SHL_LONG:
case OPCODE_SHR_LONG:
case OPCODE_USHR_LONG:
case OPCODE_ADD_DOUBLE:
case OPCODE_SUB_DOUBLE:
case OPCODE_MUL_DOUBLE:
case OPCODE_DIV_DOUBLE:
case OPCODE_REM_DOUBLE:
return true;
case IOPCODE_LOAD_PARAM:
case IOPCODE_LOAD_PARAM_OBJECT:
return false;
case IOPCODE_LOAD_PARAM_WIDE:
return true;
case IOPCODE_MOVE_RESULT_PSEUDO:
case IOPCODE_MOVE_RESULT_PSEUDO_OBJECT:
return false;
case IOPCODE_MOVE_RESULT_PSEUDO_WIDE:
return true;
default:
return false;
}
}
bool dest_is_object(IROpcode op) {
switch (op) {
case OPCODE_NOP:
not_reached_log("No dest");
case OPCODE_MOVE:
case OPCODE_MOVE_WIDE:
return false;
case OPCODE_MOVE_OBJECT:
return true;
case OPCODE_MOVE_RESULT:
case OPCODE_MOVE_RESULT_WIDE:
return false;
case OPCODE_MOVE_RESULT_OBJECT:
case OPCODE_MOVE_EXCEPTION:
return true;
case OPCODE_RETURN_VOID:
case OPCODE_RETURN:
case OPCODE_RETURN_WIDE:
case OPCODE_RETURN_OBJECT:
not_reached_log("No dest");
case OPCODE_MONITOR_ENTER:
case OPCODE_MONITOR_EXIT:
case OPCODE_THROW:
case OPCODE_GOTO:
not_reached_log("No dest");
case OPCODE_NEG_INT:
case OPCODE_NOT_INT:
case OPCODE_NEG_LONG:
case OPCODE_NOT_LONG:
case OPCODE_NEG_FLOAT:
case OPCODE_NEG_DOUBLE:
case OPCODE_INT_TO_LONG:
case OPCODE_INT_TO_FLOAT:
case OPCODE_INT_TO_DOUBLE:
case OPCODE_LONG_TO_INT:
case OPCODE_LONG_TO_FLOAT:
case OPCODE_LONG_TO_DOUBLE:
case OPCODE_FLOAT_TO_INT:
case OPCODE_FLOAT_TO_LONG:
case OPCODE_FLOAT_TO_DOUBLE:
case OPCODE_DOUBLE_TO_INT:
case OPCODE_DOUBLE_TO_LONG:
case OPCODE_DOUBLE_TO_FLOAT:
case OPCODE_INT_TO_BYTE:
case OPCODE_INT_TO_CHAR:
case OPCODE_INT_TO_SHORT:
case OPCODE_ARRAY_LENGTH:
return false;
case OPCODE_CMPL_FLOAT:
case OPCODE_CMPG_FLOAT:
case OPCODE_CMPL_DOUBLE:
case OPCODE_CMPG_DOUBLE:
case OPCODE_CMP_LONG:
return false;
case OPCODE_IF_EQ:
case OPCODE_IF_NE:
case OPCODE_IF_LT:
case OPCODE_IF_GE:
case OPCODE_IF_GT:
case OPCODE_IF_LE:
case OPCODE_IF_EQZ:
case OPCODE_IF_NEZ:
case OPCODE_IF_LTZ:
case OPCODE_IF_GEZ:
case OPCODE_IF_GTZ:
case OPCODE_IF_LEZ:
not_reached_log("No dest");
case OPCODE_AGET:
case OPCODE_AGET_WIDE:
return false;
case OPCODE_AGET_OBJECT:
return true;
case OPCODE_AGET_BOOLEAN:
case OPCODE_AGET_BYTE:
case OPCODE_AGET_CHAR:
case OPCODE_AGET_SHORT:
return false;
case OPCODE_APUT:
case OPCODE_APUT_WIDE:
case OPCODE_APUT_OBJECT:
case OPCODE_APUT_BOOLEAN:
case OPCODE_APUT_BYTE:
case OPCODE_APUT_CHAR:
case OPCODE_APUT_SHORT:
not_reached_log("No dest");
case OPCODE_ADD_INT:
case OPCODE_SUB_INT:
case OPCODE_MUL_INT:
case OPCODE_DIV_INT:
case OPCODE_REM_INT:
case OPCODE_AND_INT:
case OPCODE_OR_INT:
case OPCODE_XOR_INT:
case OPCODE_SHL_INT:
case OPCODE_SHR_INT:
case OPCODE_USHR_INT:
case OPCODE_ADD_LONG:
case OPCODE_SUB_LONG:
case OPCODE_MUL_LONG:
case OPCODE_DIV_LONG:
case OPCODE_REM_LONG:
case OPCODE_AND_LONG:
case OPCODE_OR_LONG:
case OPCODE_XOR_LONG:
case OPCODE_SHL_LONG:
case OPCODE_SHR_LONG:
case OPCODE_USHR_LONG:
case OPCODE_ADD_FLOAT:
case OPCODE_SUB_FLOAT:
case OPCODE_MUL_FLOAT:
case OPCODE_DIV_FLOAT:
case OPCODE_REM_FLOAT:
case OPCODE_ADD_DOUBLE:
case OPCODE_SUB_DOUBLE:
case OPCODE_MUL_DOUBLE:
case OPCODE_DIV_DOUBLE:
case OPCODE_REM_DOUBLE:
return false;
case OPCODE_ADD_INT_LIT16:
case OPCODE_RSUB_INT:
case OPCODE_MUL_INT_LIT16:
case OPCODE_DIV_INT_LIT16:
case OPCODE_REM_INT_LIT16:
case OPCODE_AND_INT_LIT16:
case OPCODE_OR_INT_LIT16:
case OPCODE_XOR_INT_LIT16:
case OPCODE_ADD_INT_LIT8:
case OPCODE_RSUB_INT_LIT8:
case OPCODE_MUL_INT_LIT8:
case OPCODE_DIV_INT_LIT8:
case OPCODE_REM_INT_LIT8:
case OPCODE_AND_INT_LIT8:
case OPCODE_OR_INT_LIT8:
case OPCODE_XOR_INT_LIT8:
case OPCODE_SHL_INT_LIT8:
case OPCODE_SHR_INT_LIT8:
case OPCODE_USHR_INT_LIT8:
return false;
case OPCODE_CONST:
return false;
case OPCODE_FILL_ARRAY_DATA:
case OPCODE_SWITCH:
not_reached_log("No dest");
case OPCODE_CONST_WIDE:
case OPCODE_IGET:
case OPCODE_IGET_WIDE:
return false;
case OPCODE_IGET_OBJECT:
return true;
case OPCODE_IGET_BOOLEAN:
case OPCODE_IGET_BYTE:
case OPCODE_IGET_CHAR:
case OPCODE_IGET_SHORT:
return false;
case OPCODE_IPUT:
case OPCODE_IPUT_WIDE:
case OPCODE_IPUT_OBJECT:
case OPCODE_IPUT_BOOLEAN:
case OPCODE_IPUT_BYTE:
case OPCODE_IPUT_CHAR:
case OPCODE_IPUT_SHORT:
not_reached_log("No dest");
case OPCODE_SGET:
case OPCODE_SGET_WIDE:
return false;
case OPCODE_SGET_OBJECT:
return true;
case OPCODE_SGET_BOOLEAN:
case OPCODE_SGET_BYTE:
case OPCODE_SGET_CHAR:
case OPCODE_SGET_SHORT:
return false;
case OPCODE_SPUT:
case OPCODE_SPUT_WIDE:
case OPCODE_SPUT_OBJECT:
case OPCODE_SPUT_BOOLEAN:
case OPCODE_SPUT_BYTE:
case OPCODE_SPUT_CHAR:
case OPCODE_SPUT_SHORT:
not_reached_log("No dest");
case OPCODE_INVOKE_VIRTUAL:
case OPCODE_INVOKE_SUPER:
case OPCODE_INVOKE_DIRECT:
case OPCODE_INVOKE_STATIC:
case OPCODE_INVOKE_INTERFACE:
case OPCODE_INVOKE_CUSTOM:
case OPCODE_INVOKE_POLYMORPHIC:
not_reached_log("No dest");
case OPCODE_CONST_STRING:
case OPCODE_CONST_CLASS:
case OPCODE_CHECK_CAST:
return true;
case OPCODE_INSTANCE_OF:
return false;
case OPCODE_NEW_INSTANCE:
case OPCODE_NEW_ARRAY:
case OPCODE_FILLED_NEW_ARRAY:
return true;
case IOPCODE_LOAD_PARAM:
return false;
case IOPCODE_LOAD_PARAM_OBJECT:
return true;
case IOPCODE_LOAD_PARAM_WIDE:
return false;
case IOPCODE_MOVE_RESULT_PSEUDO:
return false;
case IOPCODE_MOVE_RESULT_PSEUDO_OBJECT:
return true;
case IOPCODE_MOVE_RESULT_PSEUDO_WIDE:
return false;
default:
not_reached_log("Unknown opcode %02x\n", op);
}
}
} // namespace opcode_impl