<commit_before>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include "SimpleInline.h"
#include "InlineHelper.h"
#include "Deleter.h"
#include "DexClass.h"
#include "DexInstruction.h"
#include "DexUtil.h"
#include "Resolver.h"
#include "Transform.h"
#include "Walkers.h"
#include "ReachableClasses.h"
#include "VirtualScope.h"

#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <set>

namespace {

// the max number of callers we care to track explicitly, after that we
// group all callees/callers count in the same bucket
const int MAX_COUNT = 10;

DEBUG_ONLY bool method_breakup(
    std::vector<std::vector<DexMethod*>>& calls_group) {
  size_t size = calls_group.size();
  for (size_t i = 0; i < size; ++i) {
    size_t inst = 0;
    size_t stat = 0;
    auto group = calls_group[i];
    for (auto callee : group) {
      is_static(callee) ? stat++ : inst++;
    }
    TRACE(SINL, 5, "%ld callers %ld: instance %ld, static %ld\n",
        i, group.size(), inst, stat);
  }
  return true;
}

std::unordered_set<DexType*> no_inline_annos(
  const std::vector<std::string>& annos,
  ConfigFiles& cfg
) {
  std::unordered_set<DexType*> no_inline;
  for (const auto& anno : cfg.get_no_optimizations_annos()) {
    no_inline.insert(anno);
  }
  for (auto const& no_inline_anno : annos) {
    auto type = DexType::get_type(
        DexString::get_string(no_inline_anno.c_str()));
    if (type != nullptr) {
      no_inline.insert(type);
    }
  }
  return no_inline;
}

std::unordered_set<DexType*> force_inline_annos(
    const std::vector<std::string>& annos) {
  std::unordered_set<DexType*> force_inline;
  for (auto const& force_inline_anno : annos) {
    auto type = DexType::get_type(force_inline_anno.c_str());
    if (type != nullptr) {
      force_inline.insert(type);
    }
  }
  return force_inline;
}

template<typename DexMember>
bool has_anno(DexMember* m, const std::unordered_set<DexType*>& no_inline) {
  if (no_inline.size() == 0) return false;
  if (m != nullptr && m->get_anno_set() != nullptr) {
    for (const auto& anno : m->get_anno_set()->get_annotations()) {
      if (no_inline.count(anno->type()) > 0) {
        return true;
      }
    }
  }
  return false;
}

}

void SimpleInlinePass::run_pass(DexStoresVector& stores, ConfigFiles& cfg, PassManager& mgr) {
  if (mgr.no_proguard_rules()) {
    TRACE(SINL, 1, "SimpleInlinePass not run because no ProGuard configuration was provided.");
    return;
  }
  const auto no_inline = no_inline_annos(m_no_inline_annos, cfg);
  const auto force_inline = force_inline_annos(m_force_inline_annos);

  auto scope = build_class_scope(stores);
  // gather all inlinable candidates
  auto methods = gather_non_virtual_methods(scope, no_inline, force_inline);
  select_single_called(scope, methods);

  auto resolver = [&](DexMethod* method, MethodSearch search) {
    return resolve_method(method, search, resolved_refs);
  };

  // inline candidates
  MultiMethodInliner inliner(
      scope, stores[0].get_dexen()[0], inlinable, resolver, m_inliner_config);
  inliner.inline_methods();

  MethodTransform::sync_all(scope);
  MethodTransform::balloon_all(scope);

  // 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, "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, 3, "caller too large %ld\n", inliner.get_info().caller_too_large);
  TRACE(SINL, 1,<commit_msg>Don't call sync_all after SimpleInline<commit_after>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include "SimpleInline.h"
#include "InlineHelper.h"
#include "Deleter.h"
#include "DexClass.h"
#include "DexInstruction.h"
#include "DexUtil.h"
#include "Resolver.h"
#include "Transform.h"
#include "Walkers.h"
#include "ReachableClasses.h"
#include "VirtualScope.h"

#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <set>

namespace {

// the max number of callers we care to track explicitly, after that we
// group all callees/callers count in the same bucket
const int MAX_COUNT = 10;

DEBUG_ONLY bool method_breakup(
    std::vector<std::vector<DexMethod*>>& calls_group) {
  size_t size = calls_group.size();
  for (size_t i = 0; i < size; ++i) {
    size_t inst = 0;
    size_t stat = 0;
    auto group = calls_group[i];
    for (auto callee : group) {
      is_static(callee) ? stat++ : inst++;
    }
    TRACE(SINL, 5, "%ld callers %ld: instance %ld, static %ld\n",
        i, group.size(), inst, stat);
  }
  return true;
}

std::unordered_set<DexType*> no_inline_annos(
  const std::vector<std::string>& annos,
  ConfigFiles& cfg
) {
  std::unordered_set<DexType*> no_inline;
  for (const auto& anno : cfg.get_no_optimizations_annos()) {
    no_inline.insert(anno);
  }
  for (auto const& no_inline_anno : annos) {
    auto type = DexType::get_type(
        DexString::get_string(no_inline_anno.c_str()));
    if (type != nullptr) {
      no_inline.insert(type);
    }
  }
  return no_inline;
}

std::unordered_set<DexType*> force_inline_annos(
    const std::vector<std::string>& annos) {
  std::unordered_set<DexType*> force_inline;
  for (auto const& force_inline_anno : annos) {
    auto type = DexType::get_type(force_inline_anno.c_str());
    if (type != nullptr) {
      force_inline.insert(type);
    }
  }
  return force_inline;
}

template<typename DexMember>
bool has_anno(DexMember* m, const std::unordered_set<DexType*>& no_inline) {
  if (no_inline.size() == 0) return false;
  if (m != nullptr && m->get_anno_set() != nullptr) {
    for (const auto& anno : m->get_anno_set()->get_annotations()) {
      if (no_inline.count(anno->type()) > 0) {
        return true;
      }
    }
  }
  return false;
}

}

void SimpleInlinePass::run_pass(DexStoresVector& stores, ConfigFiles& cfg, PassManager& mgr) {
  if (mgr.no_proguard_rules()) {
    TRACE(SINL, 1, "SimpleInlinePass not run because no ProGuard configuration was provided.");
    return;
  }
  const auto no_inline = no_inline_annos(m_no_inline_annos, cfg);
  const auto force_inline = force_inline_annos(m_force_inline_annos);

  auto scope = build_class_scope(stores);
  // gather all inlinable candidates
  auto methods = gather_non_virtual_methods(scope, no_inline, force_inline);
  select_single_called(scope, methods);

  auto resolver = [&](DexMethod* method, MethodSearch search) {
    return resolve_method(method, search, resolved_refs);
  };

  // inline candidates
  MultiMethodInliner inliner(
      scope, stores[0].get_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, "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, 3, "caller too large %ld\n", inliner.get_info().caller_too_large);
  TRACE(SINL, 1,
{'fraction_non_alphanumeric': 0.14146728879181972, 'fraction_numerical': 0.007544922068897051, 'mean_word_length': 4.421959095801937, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5981075', 'n_tokens_mistral': 3810, 'n_tokens_neox': 3630, 'n_words': 873}