f8a62d314e5a0129b459c4a80767edb9cabbc400
[WebKit-https.git] / Source / WebCore / bindings / js / WorkerScriptController.cpp
1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2011, 2012 Google Inc. All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  *
26  */
27
28 #include "config.h"
29 #include "WorkerScriptController.h"
30
31 #include "JSDOMBinding.h"
32 #include "JSDedicatedWorkerGlobalScope.h"
33 #include "ScriptSourceCode.h"
34 #include "WebCoreJSClientData.h"
35 #include "WorkerGlobalScope.h"
36 #include "WorkerObjectProxy.h"
37 #include "WorkerScriptDebugServer.h"
38 #include "WorkerThread.h"
39 #include <bindings/ScriptValue.h>
40 #include <heap/StrongInlines.h>
41 #include <interpreter/Interpreter.h>
42 #include <runtime/Completion.h>
43 #include <runtime/Exception.h>
44 #include <runtime/ExceptionHelpers.h>
45 #include <runtime/Error.h>
46 #include <runtime/JSLock.h>
47
48 using namespace JSC;
49
50 namespace WebCore {
51
52 WorkerScriptController::WorkerScriptController(WorkerGlobalScope* workerGlobalScope)
53     : m_vm(VM::create())
54     , m_workerGlobalScope(workerGlobalScope)
55     , m_workerGlobalScopeWrapper(*m_vm)
56     , m_executionForbidden(false)
57 {
58     initNormalWorldClientData(m_vm.get());
59 }
60
61 WorkerScriptController::~WorkerScriptController()
62 {
63     JSLockHolder lock(vm());
64     m_workerGlobalScopeWrapper.clear();
65     m_vm.clear();
66 }
67
68 void WorkerScriptController::initScript()
69 {
70     ASSERT(!m_workerGlobalScopeWrapper);
71
72     JSLockHolder lock(m_vm.get());
73
74     // Explicitly protect the global object's prototype so it isn't collected
75     // when we allocate the global object. (Once the global object is fully
76     // constructed, it can mark its own prototype.)
77     Structure* workerGlobalScopePrototypeStructure = JSWorkerGlobalScopePrototype::createStructure(*m_vm, 0, jsNull());
78     Strong<JSWorkerGlobalScopePrototype> workerGlobalScopePrototype(*m_vm, JSWorkerGlobalScopePrototype::create(*m_vm, 0, workerGlobalScopePrototypeStructure));
79
80     if (m_workerGlobalScope->isDedicatedWorkerGlobalScope()) {
81         Structure* dedicatedContextPrototypeStructure = JSDedicatedWorkerGlobalScopePrototype::createStructure(*m_vm, 0, workerGlobalScopePrototype.get());
82         Strong<JSDedicatedWorkerGlobalScopePrototype> dedicatedContextPrototype(*m_vm, JSDedicatedWorkerGlobalScopePrototype::create(*m_vm, 0, dedicatedContextPrototypeStructure));
83         Structure* structure = JSDedicatedWorkerGlobalScope::createStructure(*m_vm, 0, dedicatedContextPrototype.get());
84
85         m_workerGlobalScopeWrapper.set(*m_vm, JSDedicatedWorkerGlobalScope::create(*m_vm, structure, static_cast<DedicatedWorkerGlobalScope&>(*m_workerGlobalScope)));
86         workerGlobalScopePrototypeStructure->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
87         dedicatedContextPrototypeStructure->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
88         ASSERT(structure->globalObject() == m_workerGlobalScopeWrapper);
89         ASSERT(m_workerGlobalScopeWrapper->structure()->globalObject() == m_workerGlobalScopeWrapper);
90         workerGlobalScopePrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
91         dedicatedContextPrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
92     }
93     ASSERT(m_workerGlobalScopeWrapper->globalObject() == m_workerGlobalScopeWrapper);
94     ASSERT(asObject(m_workerGlobalScopeWrapper->prototype())->globalObject() == m_workerGlobalScopeWrapper);
95 }
96
97 void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode)
98 {
99     if (isExecutionForbidden())
100         return;
101
102     Exception* exception;
103     evaluate(sourceCode, exception);
104     if (exception) {
105         JSLockHolder lock(vm());
106         reportException(m_workerGlobalScopeWrapper->globalExec(), exception);
107     }
108 }
109
110 void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, JSC::Exception*& returnedException)
111 {
112     if (isExecutionForbidden())
113         return;
114
115     initScriptIfNeeded();
116
117     ExecState* exec = m_workerGlobalScopeWrapper->globalExec();
118     JSLockHolder lock(exec);
119
120     JSC::Exception* evaluationException;
121     JSC::evaluate(exec, sourceCode.jsSourceCode(), m_workerGlobalScopeWrapper->globalThis(), evaluationException);
122
123     VM& vm = exec->vm();
124     if ((evaluationException && isTerminatedExecutionException(evaluationException)) 
125         || (vm.watchdog && vm.watchdog->didFire())) {
126         forbidExecution();
127         return;
128     }
129
130     if (evaluationException) {
131         String errorMessage;
132         int lineNumber = 0;
133         int columnNumber = 0;
134         String sourceURL = sourceCode.url().string();
135         if (m_workerGlobalScope->sanitizeScriptError(errorMessage, lineNumber, columnNumber, sourceURL, sourceCode.cachedScript())) {
136             vm.throwException(exec, createError(exec, errorMessage.impl()));
137             evaluationException = vm.exception();
138             vm.clearException();
139         }
140     }
141     returnedException = evaluationException;
142 }
143
144 void WorkerScriptController::setException(JSC::Exception* exception)
145 {
146     JSC::ExecState* exec = m_workerGlobalScopeWrapper->globalExec();
147     exec->vm().throwException(exec, exception);
148 }
149
150 void WorkerScriptController::scheduleExecutionTermination()
151 {
152     // The mutex provides a memory barrier to ensure that once
153     // termination is scheduled, isExecutionTerminating will
154     // accurately reflect that state when called from another thread.
155     MutexLocker locker(m_scheduledTerminationMutex);
156     if (m_vm->watchdog)
157         m_vm->watchdog->fire();
158 }
159
160 bool WorkerScriptController::isExecutionTerminating() const
161 {
162     // See comments in scheduleExecutionTermination regarding mutex usage.
163     MutexLocker locker(m_scheduledTerminationMutex);
164     if (m_vm->watchdog)
165         return m_vm->watchdog->didFire();
166     return false;
167 }
168
169 void WorkerScriptController::forbidExecution()
170 {
171     ASSERT(m_workerGlobalScope->isContextThread());
172     m_executionForbidden = true;
173 }
174
175 bool WorkerScriptController::isExecutionForbidden() const
176 {
177     ASSERT(m_workerGlobalScope->isContextThread());
178     return m_executionForbidden;
179 }
180
181 void WorkerScriptController::disableEval(const String& errorMessage)
182 {
183     initScriptIfNeeded();
184     JSLockHolder lock(vm());
185
186     m_workerGlobalScopeWrapper->setEvalEnabled(false, errorMessage);
187 }
188
189 void WorkerScriptController::attachDebugger(JSC::Debugger* debugger)
190 {
191     initScriptIfNeeded();
192     debugger->attach(m_workerGlobalScopeWrapper->globalObject());
193 }
194
195 void WorkerScriptController::detachDebugger(JSC::Debugger* debugger)
196 {
197     debugger->detach(m_workerGlobalScopeWrapper->globalObject(), JSC::Debugger::TerminatingDebuggingSession);
198 }
199
200 } // namespace WebCore