in service/constant-propagation/ConstantPropagationTransform.cpp [473:569]
void Transform::simplify_instruction(const ConstantEnvironment& env,
const WholeProgramState& wps,
const cfg::InstructionIterator& cfg_it,
const XStoreRefs* xstores,
const DexType* declaring_type) {
auto* insn = cfg_it->insn;
switch (insn->opcode()) {
case IOPCODE_LOAD_PARAM:
case IOPCODE_LOAD_PARAM_OBJECT:
case IOPCODE_LOAD_PARAM_WIDE: {
if (m_config.add_param_const) {
generate_const_param(env, cfg_it, xstores, declaring_type);
}
break;
}
case OPCODE_MOVE:
case OPCODE_MOVE_WIDE:
if (m_config.replace_moves_with_consts) {
replace_with_const(env, cfg_it, xstores, declaring_type);
}
break;
case IOPCODE_MOVE_RESULT_PSEUDO:
case IOPCODE_MOVE_RESULT_PSEUDO_WIDE:
case IOPCODE_MOVE_RESULT_PSEUDO_OBJECT: {
auto& cfg = cfg_it.cfg();
auto primary_insn = cfg.primary_instruction_of_move_result(cfg_it)->insn;
auto op = primary_insn->opcode();
if (opcode::is_an_sget(op) || opcode::is_an_iget(op) ||
opcode::is_an_aget(op) || opcode::is_div_int_lit(op) ||
opcode::is_rem_int_lit(op) || opcode::is_instance_of(op) ||
opcode::is_rem_int_or_long(op) || opcode::is_div_int_or_long(op) ||
opcode::is_check_cast(op)) {
replace_with_const(env, cfg_it, xstores, declaring_type);
}
break;
}
// Currently it's default to not replace move-result opcodes with consts
// because it's unlikely that we can get a more compact encoding (move-result
// can address 8-bit register operands while taking up just 1 code unit).
// However it can be a net win if we can remove the invoke opcodes as well --
// we need a purity analysis for that though.
case OPCODE_MOVE_RESULT:
case OPCODE_MOVE_RESULT_WIDE:
case OPCODE_MOVE_RESULT_OBJECT: {
if (m_config.replace_move_result_with_consts) {
replace_with_const(env, cfg_it, xstores, declaring_type);
} else if (m_config.getter_methods_for_immutable_fields) {
auto& cfg = cfg_it.cfg();
auto primary_insn = cfg.primary_instruction_of_move_result(cfg_it)->insn;
if (opcode::is_invoke_virtual(primary_insn->opcode())) {
auto invoked =
resolve_method(primary_insn->get_method(), MethodSearch::Virtual);
if (m_config.getter_methods_for_immutable_fields->count(invoked)) {
replace_with_const(env, cfg_it, xstores, declaring_type);
}
}
}
break;
}
case OPCODE_ADD_INT_LIT16:
case OPCODE_ADD_INT_LIT8:
case OPCODE_RSUB_INT:
case OPCODE_RSUB_INT_LIT8:
case OPCODE_MUL_INT_LIT16:
case OPCODE_MUL_INT_LIT8:
case OPCODE_AND_INT_LIT16:
case OPCODE_AND_INT_LIT8:
case OPCODE_OR_INT_LIT16:
case OPCODE_OR_INT_LIT8:
case OPCODE_XOR_INT_LIT16:
case OPCODE_XOR_INT_LIT8:
case OPCODE_SHL_INT_LIT8:
case OPCODE_SHR_INT_LIT8:
case OPCODE_USHR_INT_LIT8:
case OPCODE_ADD_INT:
case OPCODE_SUB_INT:
case OPCODE_MUL_INT:
case OPCODE_AND_INT:
case OPCODE_OR_INT:
case OPCODE_XOR_INT:
case OPCODE_ADD_LONG:
case OPCODE_SUB_LONG:
case OPCODE_MUL_LONG:
case OPCODE_AND_LONG:
case OPCODE_OR_LONG:
case OPCODE_XOR_LONG: {
if (replace_with_const(env, cfg_it, xstores, declaring_type)) {
break;
}
try_simplify(env, cfg_it, m_config, *m_mutation);
break;
}
default: {
}
}
}