Beispiel #1
0
void UsedVarsFixpointIterator::analyze_instruction(
    const IRInstruction* insn, UsedVarsSet* used_vars) const {
  TRACE(DEAD_CODE, 5, "Before %s : %s : %s\n", SHOW(insn), SHOW(*used_vars),
        show_subset(m_insn_env_map.at(insn), insn).c_str());
  bool required = is_required(insn, *used_vars);
  auto op = insn->opcode();
  if (ptrs::is_alloc_opcode(op)) {
    used_vars->remove(insn);
  }
  if (insn->dests_size()) {
    used_vars->remove(insn->dest());
  } else if (insn->has_move_result()) {
    used_vars->remove(RESULT_REGISTER);
  }
  if (required) {
    const auto& env = m_insn_env_map.at(insn);
    if (env.is_bottom()) {
      return;
    }
    for (auto reg : object_read_registers(insn)) {
      auto pointers = env.get_pointers(reg);
      // XXX: We should never encounter this case since we explicitly bind all
      // potential pointer-containing registers to non-Top values in our
      // environment. If we did encounter Top here, however, we should treat
      // all local allocations as potentially used -- a read from
      // PointerSet::top() must be treated like a read from every possible
      // heap location.
      always_assert(!pointers.is_top());
      for (auto pointer : pointers.elements()) {
        used_vars->add(pointer);
      }
    }
    for (size_t i = 0; i < insn->srcs_size(); ++i) {
      used_vars->add(insn->src(i));
    }
    if (is_move_result(op) || opcode::is_move_result_pseudo(op)) {
      used_vars->add(RESULT_REGISTER);
    }
  }
  TRACE(DEAD_CODE, 5, "After: %s\n", SHOW(*used_vars));
}
Beispiel #2
0
bool MethodTransform::inline_16regs(InlineContext& context,
                                    DexMethod *callee,
                                    DexOpcodeMethod *invoke) {
  TRACE(INL, 2, "caller: %s\ncallee: %s\n",
      SHOW(context.caller), SHOW(callee));
  auto caller = context.caller;
  MethodTransformer mtcaller(caller);
  MethodTransformer mtcallee(callee);
  auto fcaller = mtcaller->m_fmethod;
  auto fcallee = mtcallee->m_fmethod;

  auto callee_code = callee->get_code();
  auto temps_needed =
      callee_code->get_registers_size() - callee_code->get_ins_size();
  uint16_t newregs = caller->get_code()->get_registers_size();
  if (context.inline_regs_used < temps_needed) {
    newregs = newregs + temps_needed - context.inline_regs_used;
    if (newregs > 16) return false;
    remap_caller_regs(caller, fcaller, newregs);
    context.inline_regs_used = temps_needed;
  }
  RegMap callee_reg_map;
  build_remap_regs(callee_reg_map, invoke, callee, context.new_tmp_off);

  auto pos = std::find_if(
    fcaller->begin(), fcaller->end(),
    [invoke](const MethodItemEntry& mei) {
      return mei.type == MFLOW_OPCODE && mei.insn == invoke;
    });
  // find the move-result after the invoke, if any. Must be the first
  // instruction after the invoke
  auto move_res = pos;
  while (move_res++ != fcaller->end() && move_res->type != MFLOW_OPCODE);
  if (!is_move_result(move_res->insn->opcode())) {
    move_res = fcaller->end();
  }

  // Skip dbg prologue in callee, we don't need two.
  auto it = fcallee->begin();
  if (it->type == MFLOW_DEBUG && it->dbgop->opcode() == DBG_SET_PROLOGUE_END) {
    ++it;
  }
  // find the last position entry before the invoke.
  // we need to decrement the reverse iterator because it gets constructed
  // as pointing to the element preceding pos
  auto position_it = --FatMethod::reverse_iterator(pos);
  while (++position_it != fcaller->rend()
      && position_it->type != MFLOW_POSITION);
  auto invoke_position =
    position_it == fcaller->rend() ? nullptr : position_it->pos;
  if (invoke_position != nullptr) {
    TRACE(MTRANS, 5, "Inlining call at %s:%d\n", invoke_position->file->c_str(),
        invoke_position->line);
  }

  // Copy the callee up to the return. Everything else we push at the end
  // of the caller
  auto splice = MethodSplicer(callee_reg_map, invoke_position);
  auto ret_it =
      std::find_if(it, fcallee->end(), [](const MethodItemEntry& mei) {
        return mei.type == MFLOW_OPCODE && is_return(mei.insn->opcode());
      });
  splice(fcaller, pos, it, ret_it);
  if (move_res != fcaller->end()) {
    std::unique_ptr<DexInstruction> ret_insn(ret_it->insn->clone());
    remap_registers(ret_insn.get(), callee_reg_map);
    DexInstruction* move = move_result(ret_insn.get(), move_res->insn);
    auto move_mei = new MethodItemEntry(move);
    fcaller->insert(pos, *move_mei);
  }
  // ensure that the caller's code after the inlined method retain their
  // original position
  if (invoke_position != nullptr) {
    fcaller->insert(pos, *(new MethodItemEntry(invoke_position)));
  }

  // remove invoke
  fcaller->erase_and_dispose(pos, FatMethodDisposer());
  // remove move_result
  if (move_res != fcaller->end()) {
    fcaller->erase_and_dispose(move_res, FatMethodDisposer());
  }
  // Copy the opcodes in the callee after the return and put them at the end of
  // the caller.
  splice(fcaller, fcaller->end(), std::next(ret_it), fcallee->end());

  // adjust method header
  caller->get_code()->set_registers_size(newregs);
  caller->get_code()->set_outs_size(
      std::max(callee->get_code()->get_outs_size(),
      caller->get_code()->get_outs_size()));
  return true;
}