/*
 * Copyright (C) 2009, 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "bindings/core/v8/WorkerOrWorkletScriptController.h"

#include <memory>

#include "bindings/core/v8/ScriptController.h"
#include "bindings/core/v8/ScriptSourceCode.h"
#include "bindings/core/v8/ScriptValue.h"
#include "bindings/core/v8/SourceLocation.h"
#include "bindings/core/v8/V8ErrorHandler.h"
#include "bindings/core/v8/V8Initializer.h"
#include "bindings/core/v8/V8ScriptRunner.h"
#include "core/dom/ExecutionContext.h"
#include "core/events/ErrorEvent.h"
#include "core/inspector/InspectorTraceEvents.h"
#include "core/inspector/WorkerThreadDebugger.h"
#include "core/workers/WorkerGlobalScope.h"
#include "core/workers/WorkerOrWorkletGlobalScope.h"
#include "core/workers/WorkerThread.h"
#include "platform/bindings/V8DOMWrapper.h"
#include "platform/bindings/V8ObjectConstructor.h"
#include "platform/bindings/WrapperTypeInfo.h"
#include "platform/heap/ThreadState.h"
#include "public/platform/Platform.h"
#include "v8/include/v8.h"

namespace blink {

class WorkerOrWorkletScriptController::ExecutionState final {
  STACK_ALLOCATED();

 public:
  explicit ExecutionState(WorkerOrWorkletScriptController* controller)
      : had_exception(false),
        controller_(controller),
        outer_state_(controller->execution_state_) {
    controller_->execution_state_ = this;
  }

  ~ExecutionState() { controller_->execution_state_ = outer_state_; }

  bool had_exception;
  String error_message;
  std::unique_ptr<SourceLocation> location_;
  ScriptValue exception;
  Member<ErrorEvent> error_event_from_imported_script_;

  // A ExecutionState context is stack allocated by
  // WorkerOrWorkletScriptController::evaluate(), with the contoller using it
  // during script evaluation. To handle nested evaluate() uses,
  // ExecutionStates are chained together;
  // |m_outerState| keeps a pointer to the context object one level out
  // (or 0, if outermost.) Upon return from evaluate(), the
  // WorkerOrWorkletScriptController's ExecutionState is popped and the
  // previous one restored (see above dtor.)
  //
  // With Oilpan, |m_outerState| isn't traced. It'll be "up the stack"
  // and its fields will be traced when scanning the stack.
  Member<WorkerOrWorkletScriptController> controller_;
  ExecutionState* outer_state_;
};

WorkerOrWorkletScriptController* WorkerOrWorkletScriptController::Create(
    WorkerOrWorkletGlobalScope* global_scope,
    v8::Isolate* isolate) {
  return new WorkerOrWorkletScriptController(global_scope, isolate);
}

WorkerOrWorkletScriptController::WorkerOrWorkletScriptController(
    WorkerOrWorkletGlobalScope* global_scope,
    v8::Isolate* isolate)
    : global_scope_(global_scope),
      isolate_(isolate),
      execution_forbidden_(false),
      rejected_promises_(RejectedPromises::Create()),
      execution_state_(0) {
  DCHECK(isolate);
  world_ =
      DOMWrapperWorld::Create(isolate, DOMWrapperWorld::WorldType::kWorker);
}

WorkerOrWorkletScriptController::~WorkerOrWorkletScriptController() {
  DCHECK(!rejected_promises_);
}

void WorkerOrWorkletScriptController::Dispose() {
  rejected_promises_->Dispose();
  rejected_promises_ = nullptr;

  world_->Dispose();

  DisposeContextIfNeeded();
}

void WorkerOrWorkletScriptController::DisposeContextIfNeeded() {
  if (!IsContextInitialized())
    return;

  if (global_scope_->IsWorkerGlobalScope() ||
      global_scope_->IsThreadedWorkletGlobalScope()) {
    ScriptState::Scope scope(script_state_.Get());
    WorkerThreadDebugger* debugger = WorkerThreadDebugger::From(isolate_);
    debugger->ContextWillBeDestroyed(global_scope_->GetThread(),
                                     script_state_->GetContext());
  }
  script_state_->DisposePerContextData();
}

bool WorkerOrWorkletScriptController::InitializeContextIfNeeded() {
  v8::HandleScope handle_scope(isolate_);

  if (IsContextInitialized())
    return true;

  // Create a new v8::Context with the worker/worklet as the global object
  // (aka the inner global).
  ScriptWrappable* script_wrappable = global_scope_->GetScriptWrappable();
  const WrapperTypeInfo* wrapper_type_info =
      script_wrappable->GetWrapperTypeInfo();
  v8::Local<v8::FunctionTemplate> global_interface_template =
      wrapper_type_info->domTemplate(isolate_, *world_);
  if (global_interface_template.IsEmpty())
    return false;
  v8::Local<v8::ObjectTemplate> global_template =
      global_interface_template->InstanceTemplate();
  v8::Local<v8::Context> context;
  {
    // Initialize V8 extensions before creating the context.
    Vector<const char*> extension_names;
    if (global_scope_->IsServiceWorkerGlobalScope() &&
        Platform::Current()->AllowScriptExtensionForServiceWorker(
            ToWorkerGlobalScope(global_scope_.Get())->Url())) {
      const V8Extensions& extensions = ScriptController::RegisteredExtensions();
      extension_names.ReserveInitialCapacity(extensions.size());
      for (const auto* extension : extensions)
        extension_names.push_back(extension->name());
    }
    v8::ExtensionConfiguration extension_configuration(extension_names.size(),
                                                       extension_names.data());

    V8PerIsolateData::UseCounterDisabledScope use_counter_disabled(
        V8PerIsolateData::From(isolate_));
    context =
        v8::Context::New(isolate_, &extension_configuration, global_template);
  }
  if (context.IsEmpty())
    return false;

  script_state_ = ScriptState::Create(context, world_);

  ScriptState::Scope scope(script_state_.Get());

  // Associate the global proxy object, the global object and the worker
  // instance (C++ object) as follows.
  //
  //   global proxy object <====> worker or worklet instance
  //                               ^
  //                               |
  //   global object       --------+
  //
  // Per HTML spec, there is no corresponding object for workers to WindowProxy.
  // However, V8 always creates the global proxy object, we associate these
  // objects in the same manner as WindowProxy and Window.
  //
  // a) worker or worklet instance --> global proxy object
  // As we shouldn't expose the global object to author scripts, we map the
  // worker or worklet instance to the global proxy object.
  // b) global proxy object --> worker or worklet instance
  // Blink's callback functions are called by V8 with the global proxy object,
  // we need to map the global proxy object to the worker or worklet instance.
  // c) global object --> worker or worklet instance
  // The global proxy object is NOT considered as a wrapper object of the
  // worker or worklet instance because it's not an instance of
  // v8::FunctionTemplate of worker or worklet, especially note that
  // v8::Object::FindInstanceInPrototypeChain skips the global proxy object.
  // Thus we need to map the global object to the worker or worklet instance.

  // The global proxy object.  Note this is not the global object.
  v8::Local<v8::Object> global_proxy = context->Global();
  v8::Local<v8::Object> associated_wrapper =
      V8DOMWrapper::AssociateObjectWithWrapper(isolate_, script_wrappable,
                                               wrapper_type_info, global_proxy);
  CHECK(global_proxy == associated_wrapper);

  // The global object, aka worker/worklet wrapper object.
  v8::Local<v8::Object> global_object =
      global_proxy->GetPrototype().As<v8::Object>();
  V8DOMWrapper::SetNativeInfo(isolate_, global_object, wrapper_type_info,
                              script_wrappable);

  // All interfaces must be registered to V8PerContextData.
  // So we explicitly call constructorForType for the global object.
  V8PerContextData::From(context)->ConstructorForType(wrapper_type_info);

  // Name new context for debugging. For main thread worklet global scopes
  // this is done once the context is initialized.
  if (global_scope_->IsWorkerGlobalScope() ||
      global_scope_->IsThreadedWorkletGlobalScope()) {
    WorkerThreadDebugger* debugger = WorkerThreadDebugger::From(isolate_);
    debugger->ContextCreated(global_scope_->GetThread(), context);
  }

  return true;
}

ScriptValue WorkerOrWorkletScriptController::Evaluate(
    const String& script,
    const String& file_name,
    const TextPosition& script_start_position,
    CachedMetadataHandler* cache_handler,
    V8CacheOptions v8_cache_options) {
  TRACE_EVENT1("devtools.timeline", "EvaluateScript", "data",
               InspectorEvaluateScriptEvent::Data(nullptr, file_name,
                                                  script_start_position));
  if (!InitializeContextIfNeeded())
    return ScriptValue();

  ScriptState::Scope scope(script_state_.Get());

  if (!disable_eval_pending_.IsEmpty()) {
    script_state_->GetContext()->AllowCodeGenerationFromStrings(false);
    script_state_->GetContext()->SetErrorMessageForCodeGenerationFromStrings(
        V8String(isolate_, disable_eval_pending_));
    disable_eval_pending_ = String();
  }

  v8::TryCatch block(isolate_);

  v8::Local<v8::Script> compiled_script;
  v8::MaybeLocal<v8::Value> maybe_result;
  if (V8ScriptRunner::CompileScript(
          script, file_name, String(), script_start_position, isolate_,
          cache_handler, kSharableCrossOrigin, v8_cache_options)
          .ToLocal(&compiled_script))
    maybe_result = V8ScriptRunner::RunCompiledScript(isolate_, compiled_script,
                                                     global_scope_);

  if (!block.CanContinue()) {
    ForbidExecution();
    return ScriptValue();
  }

  if (block.HasCaught()) {
    v8::Local<v8::Message> message = block.Message();
    execution_state_->had_exception = true;
    execution_state_->error_message = ToCoreString(message->Get());
    execution_state_->location_ = SourceLocation::FromMessage(
        isolate_, message, ExecutionContext::From(script_state_.Get()));
    execution_state_->exception =
        ScriptValue(script_state_.Get(), block.Exception());
    block.Reset();
  } else {
    execution_state_->had_exception = false;
  }

  v8::Local<v8::Value> result;
  if (!maybe_result.ToLocal(&result) || result->IsUndefined())
    return ScriptValue();

  return ScriptValue(script_state_.Get(), result);
}

bool WorkerOrWorkletScriptController::Evaluate(
    const ScriptSourceCode& source_code,
    ErrorEvent** error_event,
    CachedMetadataHandler* cache_handler,
    V8CacheOptions v8_cache_options) {
  if (IsExecutionForbidden())
    return false;

  ExecutionState state(this);
  Evaluate(source_code.Source(), source_code.Url().GetString(),
           source_code.StartPosition(), cache_handler, v8_cache_options);
  if (IsExecutionForbidden())
    return false;

  ScriptState::Scope scope(script_state_.Get());
  if (state.had_exception) {
    if (error_event) {
      if (state.error_event_from_imported_script_) {
        // Propagate inner error event outwards.
        *error_event = state.error_event_from_imported_script_.Release();
        return false;
      }
      if (global_scope_->ShouldSanitizeScriptError(state.location_->Url(),
                                                   kNotSharableCrossOrigin)) {
        *error_event = ErrorEvent::CreateSanitizedError(world_.Get());
      } else {
        *error_event =
            ErrorEvent::Create(state.error_message, state.location_->Clone(),
                               state.exception, world_.Get());
      }
      V8ErrorHandler::StoreExceptionOnErrorEventWrapper(
          script_state_.Get(), *error_event, state.exception.V8Value(),
          script_state_->GetContext()->Global());
    } else {
      DCHECK(!global_scope_->ShouldSanitizeScriptError(
          state.location_->Url(), kNotSharableCrossOrigin));
      ErrorEvent* event = nullptr;
      if (state.error_event_from_imported_script_) {
        event = state.error_event_from_imported_script_.Release();
      } else {
        event =
            ErrorEvent::Create(state.error_message, state.location_->Clone(),
                               state.exception, world_.Get());
      }
      global_scope_->DispatchErrorEvent(event, kNotSharableCrossOrigin);
    }
    return false;
  }
  return true;
}

ScriptValue WorkerOrWorkletScriptController::EvaluateAndReturnValueForTest(
    const ScriptSourceCode& source_code) {
  ExecutionState state(this);
  return Evaluate(source_code.Source(), source_code.Url().GetString(),
                  source_code.StartPosition(), nullptr, kV8CacheOptionsDefault);
}

void WorkerOrWorkletScriptController::ForbidExecution() {
  DCHECK(global_scope_->IsContextThread());
  execution_forbidden_ = true;
}

bool WorkerOrWorkletScriptController::IsExecutionForbidden() const {
  DCHECK(global_scope_->IsContextThread());
  return execution_forbidden_;
}

void WorkerOrWorkletScriptController::DisableEval(const String& error_message) {
  disable_eval_pending_ = error_message;
}

void WorkerOrWorkletScriptController::RethrowExceptionFromImportedScript(
    ErrorEvent* error_event,
    ExceptionState& exception_state) {
  const String& error_message = error_event->message();
  if (execution_state_)
    execution_state_->error_event_from_imported_script_ = error_event;
  exception_state.RethrowV8Exception(
      V8ThrowException::CreateError(isolate_, error_message));
}

DEFINE_TRACE(WorkerOrWorkletScriptController) {
  visitor->Trace(global_scope_);
}

}  // namespace blink
