c02e4c2f34c012a19961c18dc6848c59d4420e24
[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/ExceptionHelpers.h>
44 #include <runtime/Error.h>
45 #include <runtime/JSLock.h>
46
47 using namespace JSC;
48
49 namespace WebCore {
50
51 WorkerScriptController::WorkerScriptController(WorkerGlobalScope* workerGlobalScope)
52     : m_vm(VM::create())
53     , m_workerGlobalScope(workerGlobalScope)
54     , m_workerGlobalScopeWrapper(*m_vm)
55     , m_executionForbidden(false)
56 {
57     initNormalWorldClientData(m_vm.get());
58 }
59
60 WorkerScriptController::~WorkerScriptController()
61 {
62     JSLockHolder lock(vm());
63     m_workerGlobalScopeWrapper.clear();
64     m_vm.clear();
65 }
66
67 void WorkerScriptController::initScript()
68 {
69     ASSERT(!m_workerGlobalScopeWrapper);
70
71     JSLockHolder lock(m_vm.get());
72
73     // Explicitly protect the global object's prototype so it isn't collected
74     // when we allocate the global object. (Once the global object is fully
75     // constructed, it can mark its own prototype.)
76     Structure* workerGlobalScopePrototypeStructure = JSWorkerGlobalScopePrototype::createStructure(*m_vm, 0, jsNull());
77     Strong<JSWorkerGlobalScopePrototype> workerGlobalScopePrototype(*m_vm, JSWorkerGlobalScopePrototype::create(*m_vm, 0, workerGlobalScopePrototypeStructure));
78
79     if (m_workerGlobalScope->isDedicatedWorkerGlobalScope()) {
80         Structure* dedicatedContextPrototypeStructure = JSDedicatedWorkerGlobalScopePrototype::createStructure(*m_vm, 0, workerGlobalScopePrototype.get());
81         Strong<JSDedicatedWorkerGlobalScopePrototype> dedicatedContextPrototype(*m_vm, JSDedicatedWorkerGlobalScopePrototype::create(*m_vm, 0, dedicatedContextPrototypeStructure));
82         Structure* structure = JSDedicatedWorkerGlobalScope::createStructure(*m_vm, 0, dedicatedContextPrototype.get());
83
84         m_workerGlobalScopeWrapper.set(*m_vm, JSDedicatedWorkerGlobalScope::create(*m_vm, structure, static_cast<DedicatedWorkerGlobalScope&>(*m_workerGlobalScope)));
85         workerGlobalScopePrototypeStructure->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
86         dedicatedContextPrototypeStructure->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
87         ASSERT(structure->globalObject() == m_workerGlobalScopeWrapper);
88         ASSERT(m_workerGlobalScopeWrapper->structure()->globalObject() == m_workerGlobalScopeWrapper);
89         workerGlobalScopePrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
90         dedicatedContextPrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
91     }
92     ASSERT(m_workerGlobalScopeWrapper->globalObject() == m_workerGlobalScopeWrapper);
93     ASSERT(asObject(m_workerGlobalScopeWrapper->prototype())->globalObject() == m_workerGlobalScopeWrapper);
94 }
95
96 void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode)
97 {
98     if (isExecutionForbidden())
99         return;
100
101     Deprecated::ScriptValue exception;
102     evaluate(sourceCode, &exception);
103     if (exception.jsValue()) {
104         JSLockHolder lock(vm());
105         reportException(m_workerGlobalScopeWrapper->globalExec(), exception.jsValue());
106     }
107 }
108
109 void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, Deprecated::ScriptValue* exception)
110 {
111     if (isExecutionForbidden())
112         return;
113
114     initScriptIfNeeded();
115
116     ExecState* exec = m_workerGlobalScopeWrapper->globalExec();
117     JSLockHolder lock(exec);
118
119     JSValue evaluationException;
120     JSC::evaluate(exec, sourceCode.jsSourceCode(), m_workerGlobalScopeWrapper->globalThis(), &evaluationException);
121
122     VM& vm = exec->vm();
123     if ((evaluationException && isTerminatedExecutionException(evaluationException)) 
124         || (vm.watchdog && vm.watchdog->didFire())) {
125         forbidExecution();
126         return;
127     }
128
129     if (evaluationException) {
130         String errorMessage;
131         int lineNumber = 0;
132         int columnNumber = 0;
133         String sourceURL = sourceCode.url().string();
134         if (m_workerGlobalScope->sanitizeScriptError(errorMessage, lineNumber, columnNumber, sourceURL, sourceCode.cachedScript()))
135             *exception = Deprecated::ScriptValue(*m_vm, exec->vm().throwException(exec, createError(exec, errorMessage.impl())));
136         else
137             *exception = Deprecated::ScriptValue(*m_vm, evaluationException);
138     }
139 }
140
141 void WorkerScriptController::setException(const Deprecated::ScriptValue& exception)
142 {
143     m_workerGlobalScopeWrapper->globalExec()->vm().throwException(m_workerGlobalScopeWrapper->globalExec(), exception.jsValue());
144 }
145
146 void WorkerScriptController::scheduleExecutionTermination()
147 {
148     // The mutex provides a memory barrier to ensure that once
149     // termination is scheduled, isExecutionTerminating will
150     // accurately reflect that state when called from another thread.
151     MutexLocker locker(m_scheduledTerminationMutex);
152     if (m_vm->watchdog)
153         m_vm->watchdog->fire();
154 }
155
156 bool WorkerScriptController::isExecutionTerminating() const
157 {
158     // See comments in scheduleExecutionTermination regarding mutex usage.
159     MutexLocker locker(m_scheduledTerminationMutex);
160     if (m_vm->watchdog)
161         return m_vm->watchdog->didFire();
162     return false;
163 }
164
165 void WorkerScriptController::forbidExecution()
166 {
167     ASSERT(m_workerGlobalScope->isContextThread());
168     m_executionForbidden = true;
169 }
170
171 bool WorkerScriptController::isExecutionForbidden() const
172 {
173     ASSERT(m_workerGlobalScope->isContextThread());
174     return m_executionForbidden;
175 }
176
177 void WorkerScriptController::disableEval(const String& errorMessage)
178 {
179     initScriptIfNeeded();
180     JSLockHolder lock(vm());
181
182     m_workerGlobalScopeWrapper->setEvalEnabled(false, errorMessage);
183 }
184
185 void WorkerScriptController::attachDebugger(JSC::Debugger* debugger)
186 {
187     initScriptIfNeeded();
188     debugger->attach(m_workerGlobalScopeWrapper->globalObject());
189 }
190
191 void WorkerScriptController::detachDebugger(JSC::Debugger* debugger)
192 {
193     debugger->detach(m_workerGlobalScopeWrapper->globalObject(), JSC::Debugger::TerminatingDebuggingSession);
194 }
195
196 } // namespace WebCore