void Transform::simplify_instruction()

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: {
  }
  }
}