blob: 581974798d0a4aab7fe802fe01e267209504b0b2 [file] [log] [blame]
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
* Copyright (C) 2016-2017 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. AND ITS 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 APPLE INC. OR ITS 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.
*/
#pragma once
#include "CustomElementReactionQueue.h"
#include "JSDOMBinding.h"
#include "ThreadGlobalData.h"
#include <JavaScriptCore/CatchScope.h>
#include <JavaScriptCore/Completion.h>
#include <JavaScriptCore/Microtask.h>
#include <wtf/ForbidHeapAllocation.h>
#include <wtf/MainThread.h>
namespace WebCore {
class ScriptExecutionContext;
class JSExecState {
WTF_MAKE_NONCOPYABLE(JSExecState);
WTF_FORBID_HEAP_ALLOCATION;
friend class JSMainThreadNullState;
public:
static JSC::ExecState* currentState()
{
return threadGlobalData().currentState();
};
static JSC::JSValue call(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException)
{
JSExecState currentState(exec);
return JSC::call(exec, functionObject, callType, callData, thisValue, args, returnedException);
};
static JSC::JSValue evaluate(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException)
{
JSExecState currentState(exec);
return JSC::evaluate(exec, source, thisValue, returnedException);
};
static JSC::JSValue evaluate(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue = JSC::JSValue())
{
NakedPtr<JSC::Exception> unused;
return evaluate(exec, source, thisValue, unused);
};
static JSC::JSValue profiledCall(JSC::ExecState* exec, JSC::ProfilingReason reason, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException)
{
JSExecState currentState(exec);
return JSC::profiledCall(exec, reason, functionObject, callType, callData, thisValue, args, returnedException);
}
static JSC::JSValue profiledEvaluate(JSC::ExecState* exec, JSC::ProfilingReason reason, const JSC::SourceCode& source, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException)
{
JSExecState currentState(exec);
return JSC::profiledEvaluate(exec, reason, source, thisValue, returnedException);
}
static JSC::JSValue profiledEvaluate(JSC::ExecState* exec, JSC::ProfilingReason reason, const JSC::SourceCode& source, JSC::JSValue thisValue = JSC::JSValue())
{
NakedPtr<JSC::Exception> unused;
return profiledEvaluate(exec, reason, source, thisValue, unused);
}
static void runTask(JSC::ExecState* exec, JSC::Microtask& task)
{
JSExecState currentState(exec);
task.run(exec);
}
static JSC::JSInternalPromise& loadModule(JSC::ExecState& state, const String& moduleName, JSC::JSValue parameters, JSC::JSValue scriptFetcher)
{
JSExecState currentState(&state);
return *JSC::loadModule(&state, moduleName, parameters, scriptFetcher);
}
static JSC::JSInternalPromise& loadModule(JSC::ExecState& state, const JSC::SourceCode& sourceCode, JSC::JSValue scriptFetcher)
{
JSExecState currentState(&state);
return *JSC::loadModule(&state, sourceCode, scriptFetcher);
}
static JSC::JSValue linkAndEvaluateModule(JSC::ExecState& state, const JSC::Identifier& moduleKey, JSC::JSValue scriptFetcher, NakedPtr<JSC::Exception>& returnedException)
{
JSC::VM& vm = state.vm();
auto scope = DECLARE_CATCH_SCOPE(vm);
JSExecState currentState(&state);
auto returnValue = JSC::linkAndEvaluateModule(&state, moduleKey, scriptFetcher);
if (UNLIKELY(scope.exception())) {
returnedException = scope.exception();
scope.clearException();
return JSC::jsUndefined();
}
return returnValue;
}
static void instrumentFunctionCall(ScriptExecutionContext*, JSC::CallType, const JSC::CallData&);
static void instrumentFunctionConstruct(ScriptExecutionContext*, JSC::ConstructType, const JSC::ConstructData&);
private:
explicit JSExecState(JSC::ExecState* exec)
: m_previousState(currentState())
, m_lock(exec)
{
setCurrentState(exec);
};
~JSExecState()
{
JSC::VM& vm = currentState()->vm();
auto scope = DECLARE_CATCH_SCOPE(vm);
scope.assertNoException();
JSC::ExecState* state = currentState();
bool didExitJavaScript = state && !m_previousState;
setCurrentState(m_previousState);
if (didExitJavaScript)
didLeaveScriptContext(state);
}
static void setCurrentState(JSC::ExecState* state)
{
threadGlobalData().setCurrentState(state);
}
template<typename Type, Type jsType, typename DataType> static void instrumentFunctionInternal(ScriptExecutionContext*, Type, const DataType&);
JSC::ExecState* m_previousState;
JSC::JSLockHolder m_lock;
static void didLeaveScriptContext(JSC::ExecState*);
};
// Null state prevents origin security checks.
// Used by non-JavaScript bindings (ObjC, GObject).
class JSMainThreadNullState {
WTF_MAKE_NONCOPYABLE(JSMainThreadNullState);
WTF_FORBID_HEAP_ALLOCATION;
public:
explicit JSMainThreadNullState()
: m_previousState(JSExecState::currentState())
, m_customElementReactionStack(m_previousState)
{
ASSERT(isMainThread());
JSExecState::setCurrentState(nullptr);
}
~JSMainThreadNullState()
{
ASSERT(isMainThread());
JSExecState::setCurrentState(m_previousState);
}
private:
JSC::ExecState* m_previousState;
CustomElementReactionStack m_customElementReactionStack;
};
JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState*, JSC::JSValue functionObject, JSC::CallType, const JSC::CallData&, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException);
JSC::JSValue evaluateHandlerFromAnyThread(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException);
} // namespace WebCore