/*
 * Copyright (C) 2012 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 "common_runtime_test.h"

#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <stdlib.h>
#include <cstdio>
#include "nativehelper/scoped_local_ref.h"

#include "android-base/stringprintf.h"

#include "art_field-inl.h"
#include "base/file_utils.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/mem_map.h"
#include "base/mutex.h"
#include "base/os.h"
#include "base/runtime_debug.h"
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
#include "class_loader_utils.h"
#include "compiler_callbacks.h"
#include "dex/art_dex_file_loader.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
#include "dex/method_reference.h"
#include "dex/primitive.h"
#include "dex/type_reference.h"
#include "gc/heap.h"
#include "gc/space/image_space.h"
#include "gc_root-inl.h"
#include "gtest/gtest.h"
#include "handle_scope-inl.h"
#include "interpreter/unstarted_runtime.h"
#include "jni/java_vm_ext.h"
#include "jni/jni_internal.h"
#include "mirror/class-alloc-inl.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader-inl.h"
#include "mirror/object_array-alloc-inl.h"
#include "native/dalvik_system_DexFile.h"
#include "noop_compiler_callbacks.h"
#include "profile/profile_compilation_info.h"
#include "runtime-inl.h"
#include "runtime_intrinsics.h"
#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "well_known_classes-inl.h"

namespace art HIDDEN {

using android::base::StringPrintf;

static bool unstarted_initialized_ = false;

CommonRuntimeTestImpl::CommonRuntimeTestImpl()
    : class_linker_(nullptr),
      java_lang_dex_file_(nullptr),
      boot_class_path_(),
      callbacks_(),
      use_boot_image_(false) {
}

CommonRuntimeTestImpl::~CommonRuntimeTestImpl() {
  // Ensure the dex files are cleaned up before the runtime.
  loaded_dex_files_.clear();
  runtime_.reset();
}

void CommonRuntimeTestImpl::SetUp() {
  CommonArtTestImpl::SetUp();

  std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB));
  std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB));

  RuntimeOptions options;
  std::string boot_class_path_string =
      GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames());
  std::string boot_class_path_locations_string =
      GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations());

  options.push_back(std::make_pair(boot_class_path_string, nullptr));
  options.push_back(std::make_pair(boot_class_path_locations_string, nullptr));
  if (use_boot_image_) {
    options.emplace_back("-Ximage:" + GetImageLocation(), nullptr);
  }
  options.push_back(std::make_pair("-Xcheck:jni", nullptr));
  options.push_back(std::make_pair(min_heap_string, nullptr));
  options.push_back(std::make_pair(max_heap_string, nullptr));

  // Technically this is redundant w/ common_art_test, but still check.
  options.push_back(std::make_pair("-XX:SlowDebug=true", nullptr));
  static bool gSlowDebugTestFlag = false;
  RegisterRuntimeDebugFlag(&gSlowDebugTestFlag);

  callbacks_.reset(new NoopCompilerCallbacks());

  SetUpRuntimeOptions(&options);

  // Install compiler-callbacks if SetUpRuntimeOptions hasn't deleted them.
  if (callbacks_.get() != nullptr) {
    options.push_back(std::make_pair("compilercallbacks", callbacks_.get()));
  }

  PreRuntimeCreate();
  {
    ScopedLogSeverity sls(LogSeverity::WARNING);
    if (!Runtime::Create(options, false)) {
      LOG(FATAL) << "Failed to create runtime";
      UNREACHABLE();
    }
  }
  PostRuntimeCreate();
  runtime_.reset(Runtime::Current());
  class_linker_ = runtime_->GetClassLinker();

  // Runtime::Create acquired the mutator_lock_ that is normally given away when we
  // Runtime::Start, give it away now and then switch to a more managable ScopedObjectAccess.
  Thread::Current()->TransitionFromRunnableToSuspended(ThreadState::kNative);

  // Get the boot class path from the runtime so it can be used in tests.
  boot_class_path_ = class_linker_->GetBootClassPath();
  ASSERT_FALSE(boot_class_path_.empty());
  java_lang_dex_file_ = boot_class_path_[0];

  FinalizeSetup();

  if (kIsDebugBuild) {
    // Ensure that we're really running with debug checks enabled.
    CHECK(gSlowDebugTestFlag);
  }
}

void CommonRuntimeTestImpl::FinalizeSetup() {
  // Initialize maps for unstarted runtime. This needs to be here, as running clinits needs this
  // set up.
  if (!unstarted_initialized_) {
    interpreter::UnstartedRuntime::Initialize();
    unstarted_initialized_ = true;
  } else {
    interpreter::UnstartedRuntime::Reinitialize();
  }

  {
    ScopedObjectAccess soa(Thread::Current());
    runtime_->GetClassLinker()->RunEarlyRootClinits(soa.Self());
    InitializeIntrinsics();
    runtime_->RunRootClinits(soa.Self());
  }

  runtime_->GetHeap()->VerifyHeap();  // Check for heap corruption before the test
  // Reduce timinig-dependent flakiness in OOME behavior (eg StubTest.AllocObject).
  runtime_->GetHeap()->SetMinIntervalHomogeneousSpaceCompactionByOom(0U);
}

void CommonRuntimeTestImpl::TearDown() {
  CommonArtTestImpl::TearDown();
  if (runtime_ != nullptr) {
    runtime_->GetHeap()->VerifyHeap();  // Check for heap corruption after the test
  }
}

// Check that for target builds we have ART_TARGET_NATIVETEST_DIR set.
#ifdef ART_TARGET
#ifndef ART_TARGET_NATIVETEST_DIR
#error "ART_TARGET_NATIVETEST_DIR not set."
#endif
// Wrap it as a string literal.
#define ART_TARGET_NATIVETEST_DIR_STRING STRINGIFY(ART_TARGET_NATIVETEST_DIR) "/"
#else
#define ART_TARGET_NATIVETEST_DIR_STRING ""
#endif

std::vector<const DexFile*> CommonRuntimeTestImpl::GetDexFiles(jobject jclass_loader) {
  ScopedObjectAccess soa(Thread::Current());

  StackHandleScope<1> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader = hs.NewHandle(
      soa.Decode<mirror::ClassLoader>(jclass_loader));
  return GetDexFiles(soa.Self(), class_loader);
}

std::vector<const DexFile*> CommonRuntimeTestImpl::GetDexFiles(
    Thread* self,
    Handle<mirror::ClassLoader> class_loader) {
  DCHECK((class_loader->GetClass() == WellKnownClasses::dalvik_system_PathClassLoader) ||
         (class_loader->GetClass() == WellKnownClasses::dalvik_system_DelegateLastClassLoader));

  std::vector<const DexFile*> ret;
  VisitClassLoaderDexFiles(self,
                           class_loader,
                           [&](const DexFile* cp_dex_file) {
                             if (cp_dex_file == nullptr) {
                               LOG(WARNING) << "Null DexFile";
                             } else {
                               ret.push_back(cp_dex_file);
                             }
                             return true;
                           });
  return ret;
}

const DexFile* CommonRuntimeTestImpl::GetFirstDexFile(jobject jclass_loader) {
  std::vector<const DexFile*> tmp(GetDexFiles(jclass_loader));
  DCHECK(!tmp.empty());
  const DexFile* ret = tmp[0];
  DCHECK(ret != nullptr);
  return ret;
}

jobject CommonRuntimeTestImpl::LoadMultiDex(const char* first_dex_name,
                                            const char* second_dex_name) {
  std::vector<std::unique_ptr<const DexFile>> first_dex_files = OpenTestDexFiles(first_dex_name);
  std::vector<std::unique_ptr<const DexFile>> second_dex_files = OpenTestDexFiles(second_dex_name);
  std::vector<const DexFile*> class_path;
  CHECK_NE(0U, first_dex_files.size());
  CHECK_NE(0U, second_dex_files.size());
  for (auto& dex_file : first_dex_files) {
    class_path.push_back(dex_file.get());
    loaded_dex_files_.push_back(std::move(dex_file));
  }
  for (auto& dex_file : second_dex_files) {
    class_path.push_back(dex_file.get());
    loaded_dex_files_.push_back(std::move(dex_file));
  }

  Thread* self = Thread::Current();
  jobject class_loader = Runtime::Current()->GetClassLinker()->CreatePathClassLoader(self,
                                                                                     class_path);
  self->SetClassLoaderOverride(class_loader);
  return class_loader;
}

jobject CommonRuntimeTestImpl::LoadDex(const char* dex_name) {
  jobject class_loader = LoadDexInPathClassLoader(dex_name, nullptr);
  Thread::Current()->SetClassLoaderOverride(class_loader);
  return class_loader;
}

jobject
CommonRuntimeTestImpl::LoadDexInWellKnownClassLoader(ScopedObjectAccess& soa,
                                                     const std::vector<std::string>& dex_names,
                                                     ObjPtr<mirror::Class> loader_class,
                                                     jobject parent_loader,
                                                     jobject shared_libraries,
                                                     jobject shared_libraries_after) {
  std::vector<const DexFile*> class_path;
  for (const std::string& dex_name : dex_names) {
    std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles(dex_name.c_str());
    CHECK_NE(0U, dex_files.size());
    for (auto& dex_file : dex_files) {
      class_path.push_back(dex_file.get());
      loaded_dex_files_.push_back(std::move(dex_file));
    }
  }
  StackHandleScope<4> hs(soa.Self());
  Handle<mirror::Class> h_loader_class = hs.NewHandle(loader_class);
  Handle<mirror::ClassLoader> h_parent_loader =
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(parent_loader));
  Handle<mirror::ObjectArray<mirror::ClassLoader>> h_shared_libraries =
      hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::ClassLoader>>(shared_libraries));
  Handle<mirror::ObjectArray<mirror::ClassLoader>> h_shared_libraries_after =
      hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::ClassLoader>>(shared_libraries_after));

  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
  ObjPtr<mirror::ClassLoader> result = class_linker->CreateWellKnownClassLoader(
      soa.Self(),
      class_path,
      h_loader_class,
      h_parent_loader,
      h_shared_libraries,
      h_shared_libraries_after);

  {
    // Verify we build the correct chain.

    // Verify that the result has the correct class.
    CHECK_EQ(h_loader_class.Get(), result->GetClass());
    // Verify that the parent is not null. The boot class loader will be set up as a
    // proper object.
    ObjPtr<mirror::ClassLoader> actual_parent(result->GetParent());
    CHECK(actual_parent != nullptr);

    if (parent_loader != nullptr) {
      // We were given a parent. Verify that it's what we expect.
      CHECK_EQ(h_parent_loader.Get(), actual_parent);
    } else {
      // No parent given. The parent must be the BootClassLoader.
      CHECK(class_linker->IsBootClassLoader(actual_parent));
    }
  }

  return soa.Env()->GetVm()->AddGlobalRef(soa.Self(), result);
}

jobject CommonRuntimeTestImpl::LoadDexInPathClassLoader(const std::string& dex_name,
                                                        jobject parent_loader,
                                                        jobject shared_libraries,
                                                        jobject shared_libraries_after) {
  return LoadDexInPathClassLoader(std::vector<std::string>{ dex_name },
                                  parent_loader,
                                  shared_libraries,
                                  shared_libraries_after);
}

jobject CommonRuntimeTestImpl::LoadDexInPathClassLoader(const std::vector<std::string>& names,
                                                        jobject parent_loader,
                                                        jobject shared_libraries,
                                                        jobject shared_libraries_after) {
  ScopedObjectAccess soa(Thread::Current());
  return LoadDexInWellKnownClassLoader(soa,
                                       names,
                                       WellKnownClasses::dalvik_system_PathClassLoader.Get(),
                                       parent_loader,
                                       shared_libraries,
                                       shared_libraries_after);
}

jobject CommonRuntimeTestImpl::LoadDexInDelegateLastClassLoader(const std::string& dex_name,
                                                                jobject parent_loader) {
  ScopedObjectAccess soa(Thread::Current());
  return LoadDexInWellKnownClassLoader(
      soa,
      { dex_name },
      WellKnownClasses::dalvik_system_DelegateLastClassLoader.Get(),
      parent_loader);
}

jobject CommonRuntimeTestImpl::LoadDexInInMemoryDexClassLoader(const std::string& dex_name,
                                                               jobject parent_loader) {
  ScopedObjectAccess soa(Thread::Current());
  return LoadDexInWellKnownClassLoader(
      soa,
      { dex_name },
      WellKnownClasses::dalvik_system_InMemoryDexClassLoader.Get(),
      parent_loader);
}

void CommonRuntimeTestImpl::FillHeap(Thread* self,
                                     ClassLinker* class_linker,
                                     VariableSizedHandleScope* handle_scope) {
  DCHECK(handle_scope != nullptr);

  Runtime::Current()->GetHeap()->SetIdealFootprint(1 * GB);

  // Class java.lang.Object.
  Handle<mirror::Class> c(handle_scope->NewHandle(
      class_linker->FindSystemClass(self, "Ljava/lang/Object;")));
  // Array helps to fill memory faster.
  Handle<mirror::Class> ca(handle_scope->NewHandle(
      class_linker->FindSystemClass(self, "[Ljava/lang/Object;")));

  // Start allocating with ~128K
  size_t length = 128 * KB;
  while (length > 40) {
    const int32_t array_length = length / 4;  // Object[] has elements of size 4.
    MutableHandle<mirror::Object> h(handle_scope->NewHandle<mirror::Object>(
        mirror::ObjectArray<mirror::Object>::Alloc(self, ca.Get(), array_length)));
    if (self->IsExceptionPending() || h == nullptr) {
      self->ClearException();

      // Try a smaller length
      length = length / 2;
      // Use at most a quarter the reported free space.
      size_t mem = Runtime::Current()->GetHeap()->GetFreeMemory();
      if (length * 4 > mem) {
        length = mem / 4;
      }
    }
  }

  // Allocate simple objects till it fails.
  while (!self->IsExceptionPending()) {
    handle_scope->NewHandle<mirror::Object>(c->AllocObject(self));
  }
  self->ClearException();
}

void CommonRuntimeTestImpl::SetUpRuntimeOptionsForFillHeap(RuntimeOptions *options) {
  // Use a smaller heap
  bool found = false;
  for (std::pair<std::string, const void*>& pair : *options) {
    if (pair.first.find("-Xmx") == 0) {
      pair.first = "-Xmx4M";  // Smallest we can go.
      found = true;
    }
  }
  if (!found) {
    options->emplace_back("-Xmx4M", nullptr);
  }
}

void CommonRuntimeTestImpl::MakeInterpreted(ObjPtr<mirror::Class> klass) {
  PointerSize pointer_size = class_linker_->GetImagePointerSize();
  for (ArtMethod& method : klass->GetMethods(pointer_size)) {
    Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(&method, /*aot_code=*/ nullptr);
  }
}

bool CommonRuntimeTestImpl::StartDex2OatCommandLine(/*out*/std::vector<std::string>* argv,
                                                    /*out*/std::string* error_msg,
                                                    bool use_runtime_bcp_and_image) {
  DCHECK(argv != nullptr);
  DCHECK(argv->empty());

  Runtime* runtime = Runtime::Current();
  if (use_runtime_bcp_and_image && runtime->GetHeap()->GetBootImageSpaces().empty()) {
    *error_msg = "No image location found for Dex2Oat.";
    return false;
  }

  argv->push_back(runtime->GetCompilerExecutable());
  if (runtime->IsJavaDebuggable()) {
    argv->push_back("--debuggable");
  }
  runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(argv);

  if (use_runtime_bcp_and_image) {
    argv->push_back("--runtime-arg");
    argv->push_back(GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames()));
    argv->push_back("--runtime-arg");
    argv->push_back(GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations()));

    const std::vector<gc::space::ImageSpace*>& image_spaces =
        runtime->GetHeap()->GetBootImageSpaces();
    DCHECK(!image_spaces.empty());
    argv->push_back("--boot-image=" + image_spaces[0]->GetImageLocation());
  }

  std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
  argv->insert(argv->end(), compiler_options.begin(), compiler_options.end());
  return true;
}

bool CommonRuntimeTestImpl::CompileBootImage(const std::vector<std::string>& extra_args,
                                             const std::string& image_file_name_prefix,
                                             ArrayRef<const std::string> dex_files,
                                             ArrayRef<const std::string> dex_locations,
                                             std::string* error_msg,
                                             const std::string& use_fd_prefix) {
  Runtime* const runtime = Runtime::Current();
  std::vector<std::string> argv {
    runtime->GetCompilerExecutable(),
    "--runtime-arg",
    "-Xms64m",
    "--runtime-arg",
    "-Xmx64m",
    "--runtime-arg",
    "-Xverify:softfail",
    "--force-determinism",
  };
  CHECK_EQ(dex_files.size(), dex_locations.size());
  for (const std::string& dex_file : dex_files) {
    argv.push_back("--dex-file=" + dex_file);
  }
  for (const std::string& dex_location : dex_locations) {
    argv.push_back("--dex-location=" + dex_location);
  }
  if (runtime->IsJavaDebuggable()) {
    argv.push_back("--debuggable");
  }
  runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);

  if (!kIsTargetBuild) {
    argv.push_back("--host");
  }

  std::unique_ptr<File> art_file;
  std::unique_ptr<File> vdex_file;
  std::unique_ptr<File> oat_file;
  if (!use_fd_prefix.empty()) {
    art_file.reset(OS::CreateEmptyFile((use_fd_prefix + ".art").c_str()));
    vdex_file.reset(OS::CreateEmptyFile((use_fd_prefix + ".vdex").c_str()));
    oat_file.reset(OS::CreateEmptyFile((use_fd_prefix + ".oat").c_str()));
    argv.push_back("--image-fd=" + std::to_string(art_file->Fd()));
    argv.push_back("--output-vdex-fd=" + std::to_string(vdex_file->Fd()));
    argv.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
    argv.push_back("--oat-location=" + image_file_name_prefix + ".oat");
  } else {
    argv.push_back("--image=" + image_file_name_prefix + ".art");
    argv.push_back("--oat-file=" + image_file_name_prefix + ".oat");
    argv.push_back("--oat-location=" + image_file_name_prefix + ".oat");
  }

  std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
  argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());

  // We must set --android-root.
  const char* android_root = getenv("ANDROID_ROOT");
  CHECK(android_root != nullptr);
  argv.push_back("--android-root=" + std::string(android_root));
  argv.insert(argv.end(), extra_args.begin(), extra_args.end());

  bool result = RunDex2Oat(argv, error_msg);
  if (art_file != nullptr) {
    CHECK_EQ(0, art_file->FlushClose());
  }
  if (vdex_file != nullptr) {
    CHECK_EQ(0, vdex_file->FlushClose());
  }
  if (oat_file != nullptr) {
    CHECK_EQ(0, oat_file->FlushClose());
  }
  return result;
}

bool CommonRuntimeTestImpl::RunDex2Oat(const std::vector<std::string>& args,
                                       std::string* error_msg) {
  // We only want fatal logging for the error message.
  auto post_fork_fn = []() { return setenv("ANDROID_LOG_TAGS", "*:f", 1) == 0; };
  ForkAndExecResult res = ForkAndExec(args, post_fork_fn, error_msg);
  if (res.stage != ForkAndExecResult::kFinished) {
    *error_msg = strerror(errno);
    return false;
  }
  return res.StandardSuccess();
}

std::string CommonRuntimeTestImpl::GetImageLocation() {
  return GetImageDirectory() + "/boot.art";
}

std::string CommonRuntimeTestImpl::GetSystemImageFile() {
  std::string isa = GetInstructionSetString(kRuntimeISA);
  return GetImageDirectory() + "/" + isa + "/boot.art";
}

void CommonRuntimeTestImpl::EnterTransactionMode() {
  CHECK(!Runtime::Current()->IsActiveTransaction());
  Runtime::Current()->EnterTransactionMode(/*strict=*/ false, /*root=*/ nullptr);
}

void CommonRuntimeTestImpl::ExitTransactionMode() {
  Runtime::Current()->ExitTransactionMode();
  CHECK(!Runtime::Current()->IsActiveTransaction());
}

void CommonRuntimeTestImpl::RollbackAndExitTransactionMode() {
  Runtime::Current()->RollbackAndExitTransactionMode();
  CHECK(!Runtime::Current()->IsActiveTransaction());
}

bool CommonRuntimeTestImpl::IsTransactionAborted() {
  return Runtime::Current()->IsTransactionAborted();
}

void CommonRuntimeTestImpl::VisitDexes(ArrayRef<const std::string> dexes,
                                       const std::function<void(MethodReference)>& method_visitor,
                                       const std::function<void(TypeReference)>& class_visitor,
                                       size_t method_frequency,
                                       size_t class_frequency) {
  size_t method_counter = 0;
  size_t class_counter = 0;
  for (const std::string& dex : dexes) {
    std::vector<std::unique_ptr<const DexFile>> dex_files;
    std::string error_msg;
    ArtDexFileLoader dex_file_loader(dex);
    CHECK(dex_file_loader.Open(/*verify*/ true,
                               /*verify_checksum*/ false,
                               &error_msg,
                               &dex_files))
        << error_msg;
    for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
      for (size_t i = 0; i < dex_file->NumMethodIds(); ++i) {
        if (++method_counter % method_frequency == 0) {
          method_visitor(MethodReference(dex_file.get(), i));
        }
      }
      for (size_t i = 0; i < dex_file->NumTypeIds(); ++i) {
        if (++class_counter % class_frequency == 0) {
          class_visitor(TypeReference(dex_file.get(), dex::TypeIndex(i)));
        }
      }
    }
  }
}

void CommonRuntimeTestImpl::GenerateProfile(ArrayRef<const std::string> dexes,
                                            File* out_file,
                                            size_t method_frequency,
                                            size_t type_frequency,
                                            bool for_boot_image) {
  ProfileCompilationInfo profile(for_boot_image);
  VisitDexes(
      dexes,
      [&profile](MethodReference ref) {
        uint32_t flags = ProfileCompilationInfo::MethodHotness::kFlagHot |
            ProfileCompilationInfo::MethodHotness::kFlagStartup;
        EXPECT_TRUE(profile.AddMethod(
            ProfileMethodInfo(ref),
            static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags)));
      },
      [&profile](TypeReference ref) {
        std::set<dex::TypeIndex> classes;
        classes.insert(ref.TypeIndex());
        EXPECT_TRUE(profile.AddClassesForDex(ref.dex_file, classes.begin(), classes.end()));
      },
      method_frequency,
      type_frequency);
  profile.Save(out_file->Fd());
  EXPECT_EQ(out_file->Flush(), 0);
}

CheckJniAbortCatcher::CheckJniAbortCatcher() : vm_(Runtime::Current()->GetJavaVM()) {
  vm_->SetCheckJniAbortHook(Hook, &actual_);
}

CheckJniAbortCatcher::~CheckJniAbortCatcher() {
  vm_->SetCheckJniAbortHook(nullptr, nullptr);
  EXPECT_TRUE(actual_.empty()) << actual_;
}

void CheckJniAbortCatcher::Check(const std::string& expected_text) {
  Check(expected_text.c_str());
}

void CheckJniAbortCatcher::Check(const char* expected_text) {
  EXPECT_TRUE(actual_.find(expected_text) != std::string::npos) << "\n"
      << "Expected to find: " << expected_text << "\n"
      << "In the output   : " << actual_;
  actual_.clear();
}

void CheckJniAbortCatcher::Hook(void* data, const std::string& reason) {
  // We use += because when we're hooking the aborts like this, multiple problems can be found.
  *reinterpret_cast<std::string*>(data) += reason;
}

}  // namespace art
