bool relocate_method_if_no_changes(DexMethod* method, DexType* to_type) { if (!gather_invoked_methods_that_prevent_relocation(method)) { return false; } set_public(method); relocate_method(method, to_type); change_visibility(method); return true; }
void MultiMethodInliner::inline_callees( InlineContext& inline_context, std::vector<DexMethod*>& callees) { size_t found = 0; auto caller = inline_context.caller; auto insns = caller->get_code()->get_instructions(); // walk the caller opcodes collecting all candidates to inline // Build a callee to opcode map std::vector<std::pair<DexMethod*, DexOpcodeMethod*>> inlinables; for (auto insn = insns.begin(); insn != insns.end(); ++insn) { if (!is_invoke((*insn)->opcode())) continue; auto mop = static_cast<DexOpcodeMethod*>(*insn); auto callee = resolver(mop->get_method(), opcode_to_search(*insn)); if (callee == nullptr) continue; if (std::find(callees.begin(), callees.end(), callee) == callees.end()) { continue; } always_assert(callee->is_concrete()); found++; inlinables.push_back(std::make_pair(callee, mop)); if (found == callees.size()) break; } if (found != callees.size()) { always_assert(found <= callees.size()); info.not_found += callees.size() - found; } // attempt to inline all inlinable candidates for (auto inlinable : inlinables) { auto callee = inlinable.first; auto mop = inlinable.second; if (!is_inlinable(callee, caller)) continue; auto op = mop->opcode(); if (is_invoke_range(op)) { info.invoke_range++; continue; } TRACE(MMINL, 4, "inline %s (%d) in %s (%d)\n", SHOW(callee), caller->get_code()->get_registers_size(), SHOW(caller), callee->get_code()->get_registers_size() - callee->get_code()->get_ins_size()); change_visibility(callee); MethodTransform::inline_16regs(inline_context, callee, mop); info.calls_inlined++; inlined.insert(callee); } }