1/*
2 * Copyright (C) 2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
4 * Copyright (C) 2003-2017 Apple Inc. All rights reseved.
5 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6 * Copyright (C) 2009 Google Inc. All rights reseved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 */
23
24#include "config.h"
25#include "ScheduledAction.h"
26
27#include "ContentSecurityPolicy.h"
28#include "DOMWindow.h"
29#include "DOMWrapperWorld.h"
30#include "Document.h"
31#include "Frame.h"
32#include "FrameLoader.h"
33#include "JSDOMExceptionHandling.h"
34#include "JSDOMWindow.h"
35#include "JSExecState.h"
36#include "JSExecStateInstrumentation.h"
37#include "JSWorkerGlobalScope.h"
38#include "ScriptController.h"
39#include "ScriptExecutionContext.h"
40#include "ScriptSourceCode.h"
41#include "WorkerGlobalScope.h"
42#include "WorkerThread.h"
43#include <JavaScriptCore/JSLock.h>
44
45namespace WebCore {
46using namespace JSC;
47
48std::unique_ptr<ScheduledAction> ScheduledAction::create(DOMWrapperWorld& isolatedWorld, JSC::Strong<JSC::Unknown>&& function)
49{
50 return std::unique_ptr<ScheduledAction>(new ScheduledAction(isolatedWorld, WTFMove(function)));
51}
52
53std::unique_ptr<ScheduledAction> ScheduledAction::create(DOMWrapperWorld& isolatedWorld, String&& code)
54{
55 return std::unique_ptr<ScheduledAction>(new ScheduledAction(isolatedWorld, WTFMove(code)));
56}
57
58ScheduledAction::ScheduledAction(DOMWrapperWorld& isolatedWorld, JSC::Strong<JSC::Unknown>&& function)
59 : m_isolatedWorld(isolatedWorld)
60 , m_function(WTFMove(function))
61{
62}
63
64ScheduledAction::ScheduledAction(DOMWrapperWorld& isolatedWorld, String&& code)
65 : m_isolatedWorld(isolatedWorld)
66 , m_function(isolatedWorld.vm())
67 , m_code(WTFMove(code))
68{
69}
70
71ScheduledAction::~ScheduledAction() = default;
72
73void ScheduledAction::addArguments(Vector<JSC::Strong<JSC::Unknown>>&& arguments)
74{
75 m_arguments = WTFMove(arguments);
76}
77
78auto ScheduledAction::type() const -> Type
79{
80 return m_function ? Type::Function : Type::Code;
81}
82
83void ScheduledAction::execute(ScriptExecutionContext& context)
84{
85 if (is<Document>(context))
86 execute(downcast<Document>(context));
87 else
88 execute(downcast<WorkerGlobalScope>(context));
89}
90
91void ScheduledAction::executeFunctionInContext(JSGlobalObject* globalObject, JSValue thisValue, ScriptExecutionContext& context)
92{
93 ASSERT(m_function);
94 VM& vm = context.vm();
95 JSLockHolder lock(vm);
96 auto scope = DECLARE_THROW_SCOPE(vm);
97
98 CallData callData;
99 CallType callType = getCallData(vm, m_function.get(), callData);
100 if (callType == CallType::None)
101 return;
102
103 ExecState* exec = globalObject->globalExec();
104
105 MarkedArgumentBuffer arguments;
106 for (auto& argument : m_arguments)
107 arguments.append(argument.get());
108 if (UNLIKELY(arguments.hasOverflowed())) {
109 throwOutOfMemoryError(exec, scope);
110 NakedPtr<JSC::Exception> exception = scope.exception();
111 reportException(exec, exception);
112 return;
113 }
114
115 InspectorInstrumentationCookie cookie = JSExecState::instrumentFunctionCall(&context, callType, callData);
116
117 NakedPtr<JSC::Exception> exception;
118 JSExecState::profiledCall(exec, JSC::ProfilingReason::Other, m_function.get(), callType, callData, thisValue, arguments, exception);
119
120 InspectorInstrumentation::didCallFunction(cookie, &context);
121
122 if (exception)
123 reportException(exec, exception);
124}
125
126void ScheduledAction::execute(Document& document)
127{
128 JSDOMWindow* window = toJSDOMWindow(document.frame(), m_isolatedWorld);
129 if (!window)
130 return;
131
132 RefPtr<Frame> frame = window->wrapped().frame();
133 if (!frame || !frame->script().canExecuteScripts(AboutToExecuteScript))
134 return;
135
136 if (m_function)
137 executeFunctionInContext(window, window->proxy(), document);
138 else
139 frame->script().executeScriptInWorld(m_isolatedWorld, m_code);
140}
141
142void ScheduledAction::execute(WorkerGlobalScope& workerGlobalScope)
143{
144 // In a Worker, the execution should always happen on a worker thread.
145 ASSERT(workerGlobalScope.thread().thread() == &Thread::current());
146
147 WorkerScriptController* scriptController = workerGlobalScope.script();
148
149 if (m_function) {
150 JSWorkerGlobalScope* contextWrapper = scriptController->workerGlobalScopeWrapper();
151 executeFunctionInContext(contextWrapper, contextWrapper, workerGlobalScope);
152 } else {
153 ScriptSourceCode code(m_code, URL(workerGlobalScope.url()));
154 scriptController->evaluate(code);
155 }
156}
157
158} // namespace WebCore
159