• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 #include "config.h"
28 #include "ScriptExecutionContext.h"
29 
30 #include "ActiveDOMObject.h"
31 #include "Database.h"
32 #include "DatabaseTask.h"
33 #include "DatabaseThread.h"
34 #include "MessagePort.h"
35 #include "SecurityOrigin.h"
36 #include "WorkerContext.h"
37 #include "WorkerThread.h"
38 #include <wtf/MainThread.h>
39 #include <wtf/PassRefPtr.h>
40 
41 #if USE(JSC)
42 #include "JSDOMWindow.h"
43 #endif
44 
45 namespace WebCore {
46 
47 class ProcessMessagesSoonTask : public ScriptExecutionContext::Task {
48 public:
create()49     static PassOwnPtr<ProcessMessagesSoonTask> create()
50     {
51         return new ProcessMessagesSoonTask;
52     }
53 
performTask(ScriptExecutionContext * context)54     virtual void performTask(ScriptExecutionContext* context)
55     {
56         context->dispatchMessagePortEvents();
57     }
58 };
59 
ScriptExecutionContext()60 ScriptExecutionContext::ScriptExecutionContext()
61 #if ENABLE(DATABASE)
62     : m_hasOpenDatabases(false)
63 #endif
64 {
65 }
66 
~ScriptExecutionContext()67 ScriptExecutionContext::~ScriptExecutionContext()
68 {
69     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
70     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
71         ASSERT(iter->first->scriptExecutionContext() == this);
72         iter->first->contextDestroyed();
73     }
74 
75     HashSet<MessagePort*>::iterator messagePortsEnd = m_messagePorts.end();
76     for (HashSet<MessagePort*>::iterator iter = m_messagePorts.begin(); iter != messagePortsEnd; ++iter) {
77         ASSERT((*iter)->scriptExecutionContext() == this);
78         (*iter)->contextDestroyed();
79     }
80 #if ENABLE(DATABASE)
81     if (m_databaseThread) {
82         ASSERT(m_databaseThread->terminationRequested());
83         m_databaseThread = 0;
84     }
85 #endif
86 }
87 
88 #if ENABLE(DATABASE)
89 
databaseThread()90 DatabaseThread* ScriptExecutionContext::databaseThread()
91 {
92     if (!m_databaseThread && !m_hasOpenDatabases) {
93         // Create the database thread on first request - but not if at least one database was already opened,
94         // because in that case we already had a database thread and terminated it and should not create another.
95         m_databaseThread = DatabaseThread::create();
96         if (!m_databaseThread->start())
97             m_databaseThread = 0;
98     }
99 
100     return m_databaseThread.get();
101 }
102 
addOpenDatabase(Database * database)103 void ScriptExecutionContext::addOpenDatabase(Database* database)
104 {
105     ASSERT(isContextThread());
106     if (!m_openDatabaseSet)
107         m_openDatabaseSet.set(new DatabaseSet());
108 
109     ASSERT(!m_openDatabaseSet->contains(database));
110     m_openDatabaseSet->add(database);
111 }
112 
removeOpenDatabase(Database * database)113 void ScriptExecutionContext::removeOpenDatabase(Database* database)
114 {
115     ASSERT(isContextThread());
116     ASSERT(m_openDatabaseSet && m_openDatabaseSet->contains(database));
117     if (!m_openDatabaseSet)
118         return;
119     m_openDatabaseSet->remove(database);
120 }
121 
stopDatabases(DatabaseTaskSynchronizer * cleanupSync)122 void ScriptExecutionContext::stopDatabases(DatabaseTaskSynchronizer* cleanupSync)
123 {
124     ASSERT(isContextThread());
125     if (m_openDatabaseSet) {
126         DatabaseSet::iterator i = m_openDatabaseSet->begin();
127         DatabaseSet::iterator end = m_openDatabaseSet->end();
128         for (; i != end; ++i) {
129             (*i)->stop();
130             if (m_databaseThread)
131                 m_databaseThread->unscheduleDatabaseTasks(*i);
132         }
133     }
134 
135     if (m_databaseThread)
136         m_databaseThread->requestTermination(cleanupSync);
137     else if (cleanupSync)
138         cleanupSync->taskCompleted();
139 }
140 
141 #endif
142 
processMessagePortMessagesSoon()143 void ScriptExecutionContext::processMessagePortMessagesSoon()
144 {
145     postTask(ProcessMessagesSoonTask::create());
146 }
147 
dispatchMessagePortEvents()148 void ScriptExecutionContext::dispatchMessagePortEvents()
149 {
150     RefPtr<ScriptExecutionContext> protect(this);
151 
152     // Make a frozen copy.
153     Vector<MessagePort*> ports;
154     copyToVector(m_messagePorts, ports);
155 
156     unsigned portCount = ports.size();
157     for (unsigned i = 0; i < portCount; ++i) {
158         MessagePort* port = ports[i];
159         // The port may be destroyed, and another one created at the same address, but this is safe, as the worst that can happen
160         // as a result is that dispatchMessages() will be called needlessly.
161         if (m_messagePorts.contains(port) && port->started())
162             port->dispatchMessages();
163     }
164 }
165 
createdMessagePort(MessagePort * port)166 void ScriptExecutionContext::createdMessagePort(MessagePort* port)
167 {
168     ASSERT(port);
169 #if ENABLE(WORKERS)
170     ASSERT((isDocument() && isMainThread())
171         || (isWorkerContext() && currentThread() == static_cast<WorkerContext*>(this)->thread()->threadID()));
172 #endif
173 
174     m_messagePorts.add(port);
175 }
176 
destroyedMessagePort(MessagePort * port)177 void ScriptExecutionContext::destroyedMessagePort(MessagePort* port)
178 {
179     ASSERT(port);
180 #if ENABLE(WORKERS)
181     ASSERT((isDocument() && isMainThread())
182         || (isWorkerContext() && currentThread() == static_cast<WorkerContext*>(this)->thread()->threadID()));
183 #endif
184 
185     m_messagePorts.remove(port);
186 }
187 
canSuspendActiveDOMObjects()188 bool ScriptExecutionContext::canSuspendActiveDOMObjects()
189 {
190     // No protection against m_activeDOMObjects changing during iteration: canSuspend() shouldn't execute arbitrary JS.
191     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
192     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
193         ASSERT(iter->first->scriptExecutionContext() == this);
194         if (!iter->first->canSuspend())
195             return false;
196     }
197     return true;
198 }
199 
suspendActiveDOMObjects()200 void ScriptExecutionContext::suspendActiveDOMObjects()
201 {
202     // No protection against m_activeDOMObjects changing during iteration: suspend() shouldn't execute arbitrary JS.
203     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
204     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
205         ASSERT(iter->first->scriptExecutionContext() == this);
206         iter->first->suspend();
207     }
208 }
209 
resumeActiveDOMObjects()210 void ScriptExecutionContext::resumeActiveDOMObjects()
211 {
212     // No protection against m_activeDOMObjects changing during iteration: resume() shouldn't execute arbitrary JS.
213     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
214     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
215         ASSERT(iter->first->scriptExecutionContext() == this);
216         iter->first->resume();
217     }
218 }
219 
stopActiveDOMObjects()220 void ScriptExecutionContext::stopActiveDOMObjects()
221 {
222     // No protection against m_activeDOMObjects changing during iteration: stop() shouldn't execute arbitrary JS.
223     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
224     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
225         ASSERT(iter->first->scriptExecutionContext() == this);
226         iter->first->stop();
227     }
228 }
229 
createdActiveDOMObject(ActiveDOMObject * object,void * upcastPointer)230 void ScriptExecutionContext::createdActiveDOMObject(ActiveDOMObject* object, void* upcastPointer)
231 {
232     ASSERT(object);
233     ASSERT(upcastPointer);
234     m_activeDOMObjects.add(object, upcastPointer);
235 }
236 
destroyedActiveDOMObject(ActiveDOMObject * object)237 void ScriptExecutionContext::destroyedActiveDOMObject(ActiveDOMObject* object)
238 {
239     ASSERT(object);
240     m_activeDOMObjects.remove(object);
241 }
242 
setSecurityOrigin(PassRefPtr<SecurityOrigin> securityOrigin)243 void ScriptExecutionContext::setSecurityOrigin(PassRefPtr<SecurityOrigin> securityOrigin)
244 {
245     m_securityOrigin = securityOrigin;
246 }
247 
addTimeout(int timeoutId,DOMTimer * timer)248 void ScriptExecutionContext::addTimeout(int timeoutId, DOMTimer* timer)
249 {
250     ASSERT(!m_timeouts.contains(timeoutId));
251     m_timeouts.set(timeoutId, timer);
252 }
253 
removeTimeout(int timeoutId)254 void ScriptExecutionContext::removeTimeout(int timeoutId)
255 {
256     m_timeouts.remove(timeoutId);
257 }
258 
findTimeout(int timeoutId)259 DOMTimer* ScriptExecutionContext::findTimeout(int timeoutId)
260 {
261     return m_timeouts.get(timeoutId);
262 }
263 
~Task()264 ScriptExecutionContext::Task::~Task()
265 {
266 }
267 
268 #if USE(JSC)
globalData()269 JSC::JSGlobalData* ScriptExecutionContext::globalData()
270 {
271      if (isDocument())
272         return JSDOMWindow::commonJSGlobalData();
273 
274 #if ENABLE(WORKERS)
275     if (isWorkerContext())
276         return static_cast<WorkerContext*>(this)->script()->globalData();
277 #endif
278 
279     ASSERT_NOT_REACHED();
280     return 0;
281 }
282 #endif
283 
284 } // namespace WebCore
285