/*
 * Copyright (C) 2018 Apple 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:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "config.h"
#include "WorkletScriptController.h"

#if ENABLE(CSS_PAINTING_API)

#include "JSDOMBinding.h"
#include "JSEventTarget.h"
#include "JSExecState.h"
#include "JSPaintWorkletGlobalScope.h"
#include "ScriptSourceCode.h"
#include "WebCoreJSClientData.h"
#include "WorkletConsoleClient.h"

#include <JavaScriptCore/Completion.h>
#include <JavaScriptCore/Exception.h>
#include <JavaScriptCore/ExceptionHelpers.h>
#include <JavaScriptCore/GCActivityCallback.h>
#include <JavaScriptCore/JSLock.h>
#include <JavaScriptCore/PromiseDeferredTimer.h>
#include <JavaScriptCore/StrongInlines.h>

namespace WebCore {
using namespace JSC;

WorkletScriptController::WorkletScriptController(WorkletGlobalScope* workletGlobalScope)
    : m_vm(VM::create())
    , m_workletGlobalScope(workletGlobalScope)
    , m_workletGlobalScopeWrapper(*m_vm)
{
    m_vm->heap.acquireAccess(); // It's not clear that we have good discipline for heap access, so turn it on permanently.
    JSVMClientData::initNormalWorld(m_vm.get());
}

WorkletScriptController::~WorkletScriptController()
{
    JSLockHolder lock(vm());
    forbidExecution();

    if (m_workletGlobalScopeWrapper) {
        m_workletGlobalScopeWrapper->clearDOMGuardedObjects();
        m_workletGlobalScopeWrapper->setConsoleClient(nullptr);
        m_consoleClient = nullptr;
    }
    m_workletGlobalScopeWrapper.clear();
    m_vm = nullptr;
}

void WorkletScriptController::forbidExecution()
{
    ASSERT(m_workletGlobalScope->isContextThread());
    m_executionForbidden = true;
}

bool WorkletScriptController::isExecutionForbidden() const
{
    ASSERT(m_workletGlobalScope->isContextThread());
    return m_executionForbidden;
}

void WorkletScriptController::disableEval(const String& errorMessage)
{
    if (isExecutionForbidden())
        return;

    initScriptIfNeeded();
    JSLockHolder lock { vm() };

    m_workletGlobalScopeWrapper->setEvalEnabled(false, errorMessage);
}

void WorkletScriptController::disableWebAssembly(const String& errorMessage)
{
    if (isExecutionForbidden())
        return;

    initScriptIfNeeded();
    JSLockHolder lock { vm() };

    m_workletGlobalScopeWrapper->setWebAssemblyEnabled(false, errorMessage);
}


template<typename JSGlobalScopePrototype, typename JSGlobalScope, typename GlobalScope>
void WorkletScriptController::initScriptWithSubclass()
{
    ASSERT(!m_workletGlobalScopeWrapper);

    JSLockHolder lock { vm() };

    // Explicitly protect the global object's prototype so it isn't collected
    // when we allocate the global object. (Once the global object is fully
    // constructed, it can mark its own prototype.)
    Structure* contextPrototypeStructure = JSGlobalScopePrototype::createStructure(*m_vm, nullptr, jsNull());
    auto* contextPrototype = JSGlobalScopePrototype::create(*m_vm, nullptr, contextPrototypeStructure);
    Structure* structure = JSGlobalScope::createStructure(*m_vm, nullptr, contextPrototype);
    auto* proxyStructure = JSProxy::createStructure(*m_vm, nullptr, jsNull(), PureForwardingProxyType);
    auto* proxy = JSProxy::create(*m_vm, proxyStructure);

    m_workletGlobalScopeWrapper.set(*m_vm, JSGlobalScope::create(*m_vm, structure, static_cast<GlobalScope&>(*m_workletGlobalScope), proxy));
    contextPrototypeStructure->setGlobalObject(*m_vm, m_workletGlobalScopeWrapper.get());
    ASSERT(structure->globalObject() == m_workletGlobalScopeWrapper);
    ASSERT(m_workletGlobalScopeWrapper->structure(*m_vm)->globalObject() == m_workletGlobalScopeWrapper);
    contextPrototype->structure(*m_vm)->setGlobalObject(*m_vm, m_workletGlobalScopeWrapper.get());
    auto* globalScopePrototype = JSGlobalScope::prototype(*m_vm, *m_workletGlobalScopeWrapper.get());
    globalScopePrototype->didBecomePrototype();
    contextPrototype->structure(*m_vm)->setPrototypeWithoutTransition(*m_vm, globalScopePrototype);

    proxy->setTarget(*m_vm, m_workletGlobalScopeWrapper.get());
    proxy->structure(*m_vm)->setGlobalObject(*m_vm, m_workletGlobalScopeWrapper.get());

    ASSERT(m_workletGlobalScopeWrapper->globalObject() == m_workletGlobalScopeWrapper);
    ASSERT(asObject(m_workletGlobalScopeWrapper->getPrototypeDirect(*m_vm))->globalObject() == m_workletGlobalScopeWrapper);

    m_consoleClient = makeUnique<WorkletConsoleClient>(*m_workletGlobalScope);
    m_workletGlobalScopeWrapper->setConsoleClient(m_consoleClient.get());
}

void WorkletScriptController::initScript()
{
    if (isExecutionForbidden())
        return;

    if (is<PaintWorkletGlobalScope>(m_workletGlobalScope)) {
        initScriptWithSubclass<JSPaintWorkletGlobalScopePrototype, JSPaintWorkletGlobalScope, PaintWorkletGlobalScope>();
        return;
    }

    ASSERT_NOT_REACHED();
}

void WorkletScriptController::evaluate(const ScriptSourceCode& sourceCode, String* returnedExceptionMessage)
{
    if (isExecutionForbidden())
        return;

    NakedPtr<JSC::Exception> exception;
    evaluate(sourceCode, exception, returnedExceptionMessage);
    if (exception) {
        JSLockHolder lock(vm());
        reportException(m_workletGlobalScopeWrapper->globalExec(), exception);
    }
}

// Important: The caller of this function must verify that the returned exception message does not violate CORS if it is going to be passed back to JS.
void WorkletScriptController::evaluate(const ScriptSourceCode& sourceCode, NakedPtr<JSC::Exception>& returnedException, String* returnedExceptionMessage)
{
    if (isExecutionForbidden())
        return;

    initScriptIfNeeded();

    auto& state = *m_workletGlobalScopeWrapper->globalExec();
    VM& vm = state.vm();
    JSLockHolder lock { vm };

    JSExecState::profiledEvaluate(&state, JSC::ProfilingReason::Other, sourceCode.jsSourceCode(), m_workletGlobalScopeWrapper->globalThis(), returnedException);

    if (returnedException && returnedExceptionMessage) {
        // This FIXME is from WorkerScriptController.
        // FIXME: It's not great that this can run arbitrary code to string-ify the value of the exception.
        // Do we need to do anything to handle that properly, if it, say, raises another exception?
        *returnedExceptionMessage = returnedException->value().toWTFString(&state);
    }
}

void WorkletScriptController::setException(JSC::Exception* exception)
{
    auto* exec = m_workletGlobalScopeWrapper->globalExec();
    VM& vm = exec->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);
    throwException(exec, scope, exception);
}

} // namespace WebCore
#endif
