/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <memory>
#include <set>

#include "boot_image_profile.h"
#include "dex/class_accessor-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/method_reference.h"
#include "dex/type_reference.h"
#include "profile/profile_compilation_info.h"

namespace art {

using Hotness = ProfileCompilationInfo::MethodHotness;

void GenerateBootImageProfile(
    const std::vector<std::unique_ptr<const DexFile>>& dex_files,
    const std::vector<std::unique_ptr<const ProfileCompilationInfo>>& profiles,
    const BootImageOptions& options,
    bool verbose,
    ProfileCompilationInfo* out_profile) {
  for (const std::unique_ptr<const ProfileCompilationInfo>& profile : profiles) {
    // Avoid merging classes since we may want to only add classes that fit a certain criteria.
    // If we merged the classes, every single class in each profile would be in the out_profile,
    // but we want to only included classes that are in at least a few profiles.
    out_profile->MergeWith(*profile, /*merge_classes=*/ false);
  }

  // Image classes that were added because they are commonly used.
  size_t class_count = 0;
  // Image classes that were only added because they were clean.
  size_t clean_class_count = 0;
  // Total clean classes.
  size_t clean_count = 0;
  // Total dirty classes.
  size_t dirty_count = 0;

  for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
    // Inferred classes are classes inferred from method samples.
    std::set<std::pair<const ProfileCompilationInfo*, dex::TypeIndex>> inferred_classes;
    for (size_t i = 0; i < dex_file->NumMethodIds(); ++i) {
      MethodReference ref(dex_file.get(), i);
      // This counter is how many profiles contain the method as sampled or hot.
      size_t counter = 0;
      for (const std::unique_ptr<const ProfileCompilationInfo>& profile : profiles) {
        Hotness hotness = profile->GetMethodHotness(ref);
        if (hotness.IsInProfile()) {
          ++counter;
          out_profile->AddMethod(
              ProfileMethodInfo(ref),
              static_cast<ProfileCompilationInfo::MethodHotness::Flag>(hotness.GetFlags()));
          inferred_classes.emplace(profile.get(), ref.GetMethodId().class_idx_);
        }
      }
      // If the counter is greater or equal to the compile threshold, mark the method as hot.
      // Note that all hot methods are also marked as hot in the out profile during the merging
      // process.
      if (counter >= options.compiled_method_threshold) {
        Hotness hotness;
        hotness.AddFlag(Hotness::kFlagHot);
        out_profile->AddMethod(
             ProfileMethodInfo(ref),
             static_cast<ProfileCompilationInfo::MethodHotness::Flag>(hotness.GetFlags()));
      }
    }
    // Walk all of the classes and add them to the profile if they meet the requirements.
    for (ClassAccessor accessor : dex_file->GetClasses()) {
      TypeReference ref(dex_file.get(), accessor.GetClassIdx());
      bool is_clean = true;
      auto method_visitor = [&](const ClassAccessor::Method& method) {
        const uint32_t flags = method.GetAccessFlags();
        if ((flags & kAccNative) != 0) {
          // Native method will get dirtied.
          is_clean = false;
        }
        if ((flags & kAccConstructor) != 0 && (flags & kAccStatic) != 0) {
          // Class initializer, may get dirtied (not sure).
          is_clean = false;
        }
      };
      accessor.VisitFieldsAndMethods(
          [&](const ClassAccessor::Field& field) {
            if (!field.IsFinal()) {
              // Not final static field will probably dirty the class.
              is_clean = false;
            }
          },
          /*instance_field_visitor=*/ VoidFunctor(),
          method_visitor,
          method_visitor);

      ++(is_clean ? clean_count : dirty_count);
      // This counter is how many profiles contain the class.
      size_t counter = 0;
      for (const std::unique_ptr<const ProfileCompilationInfo>& profile : profiles) {
        auto it = inferred_classes.find(std::make_pair(profile.get(), ref.TypeIndex()));
        if (it != inferred_classes.end() ||
            profile->ContainsClass(*ref.dex_file, ref.TypeIndex())) {
          ++counter;
        }
      }
      if (counter == 0) {
        continue;
      }
      std::set<dex::TypeIndex> classes;
      if (counter >= options.image_class_theshold) {
        ++class_count;
        classes.insert(ref.TypeIndex());
      } else if (is_clean && counter >= options.image_class_clean_theshold) {
        ++clean_class_count;
        classes.insert(ref.TypeIndex());
      }
      out_profile->AddClassesForDex(ref.dex_file, classes.begin(), classes.end());
    }
  }
  if (verbose) {
    LOG(INFO) << "Image classes " << class_count + clean_class_count
              << " added because clean " << clean_class_count
              << " total clean " << clean_count << " total dirty " << dirty_count;
  }
}

}  // namespace art
