<commit_before>// Copyright 2015 Las Venturas Playground. All rights reserved.
// Use of this source code is governed by the MIT license, a copy of which can
// be found in the LICENSE file.

#include "bindings/runtime.h"

#include <algorithm>
#include <chrono>
#include <fstream>
#include <sstream>
#include <streambuf>
#include <string.h>
#include <thread>
#include <unordered_map>

#include <include/libplatform/libplatform.h>

#include "base/logging.h"
#include "base/time.h"
#include "bindings/exception_handler.h"
#include "bindings/frame_observer.h"
#include "bindings/global_scope.h"
#include "bindings/profiler.h"
#include "bindings/runtime_modulator.h"
#include "bindings/script_prologue.h"
#include "bindings/timer_queue.h"
#include "bindings/utilities.h"

namespace bindings {

namespace {

// Map of v8 Isolates to the associated Runtime instances (weak references).
std::unordered_map<v8::Isolate*, std::weak_ptr<Runtime>> g_runtime_instances_;

// String of the v8 flags that should apply to this virtual machine. See flag-definitions.h in
// the v8 source code for a list of all supported command line flags.
const char kRuntimeFlags[] =
    "--expose_gc "
    "--use_strict "
    "--harmony "

    // Dynamic imports
    "--harmony_dynamic_import "
    "--harmony_import_meta "

    // Arbitrary precision integers (beyond the usual 53 bits)
    "--harmony_bigint "

    // Public and class fields to be usable in class literals
    "--harmony_public_fields "
    "--harmony_class_fields "

    // Array.prototype.values
    "--harmony_array_prototype_values";

// Returns whether |character| represents a line break.
bool IsLineBreak(char character) {
  return character == '\n' || character == '\r';
}

// Returns a string with all line breaks removed from |line|.
std::string RemoveLineBreaks(std::string line) {
  line.erase(std::remove_if(line.begin(), line.end(), IsLineBreak), line.end());
  return line;
}

// Callback for the v8 message handler. Forward the call to the exception handler.
void MessageCallback(v8::Local<v8::Message> message, v8::Local<v8::Value> error) {
  std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(v8::Isolate::GetCurrent());
  if (runtime)
    runtime->GetExceptionHandler()->OnMessage(
        message, error, ExceptionHandler::MessageSource::kScript);
}

// Callback for the v8 fatal error handler. Forward the call to the exception handler.
void FatalErrorCallback(const char* location, const char* message) {
  std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(v8::Isolate::GetCurrent());
  if (runtime)
    runtime->GetExceptionHandler()->OnFatalError(location, message);
}

// Callback for uncaught promise rejection events. Output the exception message to the console
// after all, so that developers can pick up on the error and deal with it.
void PromiseRejectCallback(v8::PromiseRejectMessage message) {
  std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(v8::Isolate::GetCurrent());
  if (!runtime)
    return;

  if (message.GetEvent() == v8::kPromiseHandlerAddedAfterReject) {
    runtime->GetExceptionHandler()->RevokeQueuedMessages(message.GetPromise());
    return;
  }

  v8::Local<v8::Value> value = message.GetValue();
  if (value.IsEmpty() || !value->IsNativeError())
    return;

  v8::Local<v8::Message> error_message = v8::Exception::CreateMessage(value);
  if (error_message.IsEmpty())
    return;

  runtime->GetExceptionHandler()->OnMessage(
      error_message, value, ExceptionHandler::MessageSource::kRejectedPromise, message.GetPromise());
}

}  // namespace

// static
std::shared_ptr<Runtime> Runtime::FromIsolate(v8::Isolate* isolate) {
  const auto instance = g_runtime_instances_.find(isolate);
  if (instance == g_runtime_instances_.end())
    return nullptr;

  CHECK(!instance->second.expired());
  return instance->second.lock();
}

// static
std::shared_ptr<Runtime> Runtime::Create(Delegate* runtime_delegate,
                                         plugin::PluginController* plugin_controller) {
  auto instance = std::shared_ptr<Runtime>(
      new Runtime(runtime_delegate, plugin_controller));
  CHECK(instance->isolate());

  g_runtime_instances_[instance->isolate()] = instance;
  return instance;
}

Runtime::Runtime(Delegate* runtime_delegate,
                 plugin::PluginController* plugin_controller)
    : global_scope_(new GlobalScope(plugin_controller)),
      runtime_delegate_(runtime_delegate),
      is_ready_(false),
      frame_counter_start_(::base::monotonicallyIncreasingTime()),
      frame_counter_(0) {
  v8::V8::InitializeICU();

  platform_.reset(v8::platform::CreateDefaultPlatform());
  v8::V8::InitializePlatform(platform_.get());

  v8::V8::SetFlagsFromString(kRuntimeFlags, sizeof(kRuntimeFlags));
  v8::V8::Initialize();

  allocator_.reset(v8::ArrayBuffer::Allocator::NewDefaultAllocator());

  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = allocator_.get();

  isolate_ = v8::Isolate::New(create_params);
  isolate_scope_.reset(new v8::Isolate::Scope(isolate_));

  exception_handler_.reset(new ExceptionHandler(this, runtime_delegate_));
  isolate_->SetCaptureStackTraceForUncaughtExceptions(true, 15);
  isolate_->AddMessageListener(MessageCallback);
  isolate_->SetFatalErrorHandler(FatalErrorCallback);
  isolate_->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
  isolate_->SetPromiseRejectCallback(PromiseRejectCallback);
  isolate_->SetHostImportModuleDynamicallyCallback(
      &RuntimeModulator::ImportModuleDynamicallyCallback);

  profiler_.reset(new Profiler(isolate_));
  timer_queue_.reset(new TimerQueue(this));

  source_directory_ = base::FilePath::CurrentDirectory().Append("javascript");
}

Runtime::~Runtime() {
  // TODO: Multiple instances would now break.
  //g_runtime_instances_.erase(isolate_);

  global_scope_.reset();
  modulator_.reset();

  isolate_scope_.reset();
  isolate_->Dispose();

  v8::V8::Dispose();
  v8::V8::ShutdownPlatform();
}<commit_msg>Fix another shutdown crash<commit_after>// Copyright 2015 Las Venturas Playground. All rights reserved.
// Use of this source code is governed by the MIT license, a copy of which can
// be found in the LICENSE file.

#include "bindings/runtime.h"

#include <algorithm>
#include <chrono>
#include <fstream>
#include <sstream>
#include <streambuf>
#include <string.h>
#include <thread>
#include <unordered_map>

#include <include/libplatform/libplatform.h>

#include "base/logging.h"
#include "base/time.h"
#include "bindings/exception_handler.h"
#include "bindings/frame_observer.h"
#include "bindings/global_scope.h"
#include "bindings/profiler.h"
#include "bindings/runtime_modulator.h"
#include "bindings/script_prologue.h"
#include "bindings/timer_queue.h"
#include "bindings/utilities.h"

namespace bindings {

namespace {

// Map of v8 Isolates to the associated Runtime instances (weak references).
std::unordered_map<v8::Isolate*, std::weak_ptr<Runtime>> g_runtime_instances_;

// String of the v8 flags that should apply to this virtual machine. See flag-definitions.h in
// the v8 source code for a list of all supported command line flags.
const char kRuntimeFlags[] =
    "--expose_gc "
    "--use_strict "
    "--harmony "

    // Dynamic imports
    "--harmony_dynamic_import "
    "--harmony_import_meta "

    // Arbitrary precision integers (beyond the usual 53 bits)
    "--harmony_bigint "

    // Public and class fields to be usable in class literals
    "--harmony_public_fields "
    "--harmony_class_fields "

    // Array.prototype.values
    "--harmony_array_prototype_values";

// Returns whether |character| represents a line break.
bool IsLineBreak(char character) {
  return character == '\n' || character == '\r';
}

// Returns a string with all line breaks removed from |line|.
std::string RemoveLineBreaks(std::string line) {
  line.erase(std::remove_if(line.begin(), line.end(), IsLineBreak), line.end());
  return line;
}

// Callback for the v8 message handler. Forward the call to the exception handler.
void MessageCallback(v8::Local<v8::Message> message, v8::Local<v8::Value> error) {
  std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(v8::Isolate::GetCurrent());
  if (runtime)
    runtime->GetExceptionHandler()->OnMessage(
        message, error, ExceptionHandler::MessageSource::kScript);
}

// Callback for the v8 fatal error handler. Forward the call to the exception handler.
void FatalErrorCallback(const char* location, const char* message) {
  std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(v8::Isolate::GetCurrent());
  if (runtime)
    runtime->GetExceptionHandler()->OnFatalError(location, message);
}

// Callback for uncaught promise rejection events. Output the exception message to the console
// after all, so that developers can pick up on the error and deal with it.
void PromiseRejectCallback(v8::PromiseRejectMessage message) {
  std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(v8::Isolate::GetCurrent());
  if (!runtime)
    return;

  if (message.GetEvent() == v8::kPromiseHandlerAddedAfterReject) {
    runtime->GetExceptionHandler()->RevokeQueuedMessages(message.GetPromise());
    return;
  }

  v8::Local<v8::Value> value = message.GetValue();
  if (value.IsEmpty() || !value->IsNativeError())
    return;

  v8::Local<v8::Message> error_message = v8::Exception::CreateMessage(value);
  if (error_message.IsEmpty())
    return;

  runtime->GetExceptionHandler()->OnMessage(
      error_message, value, ExceptionHandler::MessageSource::kRejectedPromise, message.GetPromise());
}

}  // namespace

// static
std::shared_ptr<Runtime> Runtime::FromIsolate(v8::Isolate* isolate) {
  const auto instance = g_runtime_instances_.find(isolate);
  if (instance == g_runtime_instances_.end())
    return nullptr;

  CHECK(!instance->second.expired());
  return instance->second.lock();
}

// static
std::shared_ptr<Runtime> Runtime::Create(Delegate* runtime_delegate,
                                         plugin::PluginController* plugin_controller) {
  auto instance = std::shared_ptr<Runtime>(
      new Runtime(runtime_delegate, plugin_controller));
  CHECK(instance->isolate());

  g_runtime_instances_[instance->isolate()] = instance;
  return instance;
}

Runtime::Runtime(Delegate* runtime_delegate,
                 plugin::PluginController* plugin_controller)
    : global_scope_(new GlobalScope(plugin_controller)),
      runtime_delegate_(runtime_delegate),
      is_ready_(false),
      frame_counter_start_(::base::monotonicallyIncreasingTime()),
      frame_counter_(0) {
  v8::V8::InitializeICU();

  platform_.reset(v8::platform::CreateDefaultPlatform());
  v8::V8::InitializePlatform(platform_.get());

  v8::V8::SetFlagsFromString(kRuntimeFlags, sizeof(kRuntimeFlags));
  v8::V8::Initialize();

  allocator_.reset(v8::ArrayBuffer::Allocator::NewDefaultAllocator());

  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = allocator_.get();

  isolate_ = v8::Isolate::New(create_params);
  isolate_scope_.reset(new v8::Isolate::Scope(isolate_));

  exception_handler_.reset(new ExceptionHandler(this, runtime_delegate_));
  isolate_->SetCaptureStackTraceForUncaughtExceptions(true, 15);
  isolate_->AddMessageListener(MessageCallback);
  isolate_->SetFatalErrorHandler(FatalErrorCallback);
  isolate_->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
  isolate_->SetPromiseRejectCallback(PromiseRejectCallback);
  isolate_->SetHostImportModuleDynamicallyCallback(
      &RuntimeModulator::ImportModuleDynamicallyCallback);

  profiler_.reset(new Profiler(isolate_));
  timer_queue_.reset(new TimerQueue(this));

  source_directory_ = base::FilePath::CurrentDirectory().Append("javascript");
}

Runtime::~Runtime() {
  // TODO: Multiple instances would now break.
  //g_runtime_instances_.erase(isolate_);

  global_scope_.reset();
  timer_queue_.reset();
  modulator_.reset();

  isolate_scope_.reset();
  isolate_->Dispose();

  v8::V8::Dispose();
  v8::V8::ShutdownPlatform();
}
{'fraction_non_alphanumeric': 0.1295971978984238, 'fraction_numerical': 0.008006004503377533, 'mean_word_length': 5.278534031413613, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 85, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1061624', 'n_tokens_mistral': 3631, 'n_tokens_neox': 3548, 'n_words': 780}