void SimpleInlinePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) { const auto no_inline = no_inline_annos(m_no_inline_annos, cfg); auto scope = build_class_scope(dexen); // gather all inlinable candidates auto methods = gather_non_virtual_methods(scope, no_inline); select_single_called(scope, methods); auto resolver = [&](DexMethod* method, MethodSearch search) { return resolve_method(method, search, resolved_refs); }; // inline candidates MultiMethodInliner inliner( scope, dexen[0], inlinable, resolver, m_inliner_config); inliner.inline_methods(); // delete all methods that can be deleted auto inlined = inliner.get_inlined(); size_t inlined_count = inlined.size(); size_t deleted = delete_methods(scope, inlined, resolver); TRACE(SINL, 3, "recursive %ld\n", inliner.get_info().recursive); TRACE(SINL, 3, "blacklisted meths %ld\n", inliner.get_info().blacklisted); TRACE(SINL, 3, "more than 16 regs %ld\n", inliner.get_info().more_than_16regs); TRACE(SINL, 3, "try/catch in callee %ld\n", inliner.get_info().try_catch_block); TRACE(SINL, 3, "try/catch in caller %ld\n", inliner.get_info().caller_tries); TRACE(SINL, 3, "virtualizing methods %ld\n", inliner.get_info().need_vmethod); TRACE(SINL, 3, "invoke super %ld\n", inliner.get_info().invoke_super); TRACE(SINL, 3, "override inputs %ld\n", inliner.get_info().write_over_ins); TRACE(SINL, 3, "escaped virtual %ld\n", inliner.get_info().escaped_virtual); TRACE(SINL, 3, "known non public virtual %ld\n", inliner.get_info().non_pub_virtual); TRACE(SINL, 3, "non public ctor %ld\n", inliner.get_info().non_pub_ctor); TRACE(SINL, 3, "unknown field %ld\n", inliner.get_info().escaped_field); TRACE(SINL, 3, "non public field %ld\n", inliner.get_info().non_pub_field); TRACE(SINL, 3, "throws %ld\n", inliner.get_info().throws); TRACE(SINL, 3, "array data %ld\n", inliner.get_info().array_data); TRACE(SINL, 3, "multiple returns %ld\n", inliner.get_info().multi_ret); TRACE(SINL, 3, "reference outside of primary %ld\n", inliner.get_info().not_in_primary); TRACE(SINL, 3, "not found %ld\n", inliner.get_info().not_found); TRACE(SINL, 1, "%ld inlined calls over %ld methods and %ld methods removed\n", inliner.get_info().calls_inlined, inlined_count, deleted); }
// Replace function calls with body void Inliner::VisitCallExpr(CallExpr *node) { FunctionDecl * calee_ptr = node->getDirectCallee(); if (!calee_ptr || !calee_ptr->hasBody()) { return; } // Visit the body and prefix all DeclRefs and Labels //string prefixed_body = PrefixFunc(fd); // Replace returns with goto + assignment // replace the prototype with locals and connect to the call arguments //if (functions_.count(calee_ptr) == 0) { Inliner inliner(rewriter_,source_manager_,contex_); inliner.VisitFunctionDecl(calee_ptr); //} stringstream ss; string calee_name = calee_ptr->getNameAsString(); // add a start label (just for readability) ss << "{\n/*" << Defines::kLabelStart << calee_name << replacements_ << ":*/\n"; // put in the arguments, start with RetVal and Ret string result_type = calee_ptr->getResultType().getAsString(); if (result_type != "void") ss << result_type << " " << Defines::kRetVal << "_" << calee_name << replacements_ << ";\n"; ss << Defines::kGuardType << " " << Defines::kRetGuard << "_" << calee_name << replacements_ << " = 0;\n"; // use temporary variables to transfer arguments to avoid this: // double foo(int x) { // foo body } main() { y = foo(x); } // turning into this: // main () { // { // int tmp_x = x; // double retval; // { // int x = tmp_x; // // foo body // } // y = retval; // } // } stringstream temps, params; for (size_t i = 0; i < calee_ptr->getNumParams() ; ++i) { ParmVarDecl * param_ptr = calee_ptr->getParamDecl(i); string decl = Utils::PrintDecl(param_ptr,contex_); string name = param_ptr->getNameAsString(); string type = decl.substr(0,decl.find_last_of(name) - name.size() + 1); temps << type << Defines::kTempPrefix << calee_name << "_" << name << replacements_<< " = " << Utils::PrintStmt(node->getArg(i),contex_) << ";\n"; params << decl << " = " << Defines::kTempPrefix << calee_name << "_" << name << replacements_ << ";\n"; } ss << temps.str() << "{\n" << params.str(); // put in the inlined body ss << inliner.body_; ss << "\n}\n"; // add the end label (just for readability) ss << "/*" << Defines::kLabelEnd << calee_name << replacements_ << ":*/\n"; // connect the return value if (!return_vars_.empty()) { ss << return_vars_.back() << " = " << Defines::kRetVal << "_" << calee_name << replacements_; } ss << ";\n"; ss << "}\n"; SourceLocation start = node->getSourceRange().getBegin(); Rewriter &rw = (current_func_->isMain()) ? main_rewriter_ : rewriter_; rw.ReplaceText(start, Utils::GetStmtLength(node),ss.str()); }