|
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 #if ENABLE(FILE_READER) || ENABLE(FILE_WRITER) |
|
35 #include "FileThread.h" |
|
36 #endif |
|
37 #include "MessagePort.h" |
|
38 #include "SecurityOrigin.h" |
|
39 #include "WorkerContext.h" |
|
40 #include "WorkerThread.h" |
|
41 #include <wtf/MainThread.h> |
|
42 #include <wtf/PassRefPtr.h> |
|
43 |
|
44 #if USE(JSC) |
|
45 #include "JSDOMWindow.h" |
|
46 #endif |
|
47 |
|
48 namespace WebCore { |
|
49 |
|
50 class ProcessMessagesSoonTask : public ScriptExecutionContext::Task { |
|
51 public: |
|
52 static PassOwnPtr<ProcessMessagesSoonTask> create() |
|
53 { |
|
54 return new ProcessMessagesSoonTask; |
|
55 } |
|
56 |
|
57 virtual void performTask(ScriptExecutionContext* context) |
|
58 { |
|
59 context->dispatchMessagePortEvents(); |
|
60 } |
|
61 }; |
|
62 |
|
63 ScriptExecutionContext::ScriptExecutionContext() |
|
64 #if ENABLE(DATABASE) |
|
65 : m_hasOpenDatabases(false) |
|
66 #endif |
|
67 { |
|
68 } |
|
69 |
|
70 ScriptExecutionContext::~ScriptExecutionContext() |
|
71 { |
|
72 HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end(); |
|
73 for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { |
|
74 ASSERT(iter->first->scriptExecutionContext() == this); |
|
75 iter->first->contextDestroyed(); |
|
76 } |
|
77 |
|
78 HashSet<MessagePort*>::iterator messagePortsEnd = m_messagePorts.end(); |
|
79 for (HashSet<MessagePort*>::iterator iter = m_messagePorts.begin(); iter != messagePortsEnd; ++iter) { |
|
80 ASSERT((*iter)->scriptExecutionContext() == this); |
|
81 (*iter)->contextDestroyed(); |
|
82 } |
|
83 #if ENABLE(DATABASE) |
|
84 if (m_databaseThread) { |
|
85 ASSERT(m_databaseThread->terminationRequested()); |
|
86 m_databaseThread = 0; |
|
87 } |
|
88 #endif |
|
89 #if ENABLE(FILE_READER) || ENABLE(FILE_WRITER) |
|
90 if (m_fileThread) { |
|
91 m_fileThread->stop(); |
|
92 m_fileThread = 0; |
|
93 } |
|
94 #endif |
|
95 } |
|
96 |
|
97 #if ENABLE(DATABASE) |
|
98 |
|
99 DatabaseThread* ScriptExecutionContext::databaseThread() |
|
100 { |
|
101 if (!m_databaseThread && !m_hasOpenDatabases) { |
|
102 // Create the database thread on first request - but not if at least one database was already opened, |
|
103 // because in that case we already had a database thread and terminated it and should not create another. |
|
104 m_databaseThread = DatabaseThread::create(); |
|
105 if (!m_databaseThread->start()) |
|
106 m_databaseThread = 0; |
|
107 } |
|
108 |
|
109 return m_databaseThread.get(); |
|
110 } |
|
111 |
|
112 void ScriptExecutionContext::stopDatabases(DatabaseTaskSynchronizer* cleanupSync) |
|
113 { |
|
114 ASSERT(isContextThread()); |
|
115 if (m_databaseThread) |
|
116 m_databaseThread->requestTermination(cleanupSync); |
|
117 else if (cleanupSync) |
|
118 cleanupSync->taskCompleted(); |
|
119 } |
|
120 |
|
121 #endif |
|
122 |
|
123 void ScriptExecutionContext::processMessagePortMessagesSoon() |
|
124 { |
|
125 postTask(ProcessMessagesSoonTask::create()); |
|
126 } |
|
127 |
|
128 void ScriptExecutionContext::dispatchMessagePortEvents() |
|
129 { |
|
130 RefPtr<ScriptExecutionContext> protect(this); |
|
131 |
|
132 // Make a frozen copy. |
|
133 Vector<MessagePort*> ports; |
|
134 copyToVector(m_messagePorts, ports); |
|
135 |
|
136 unsigned portCount = ports.size(); |
|
137 for (unsigned i = 0; i < portCount; ++i) { |
|
138 MessagePort* port = ports[i]; |
|
139 // The port may be destroyed, and another one created at the same address, but this is safe, as the worst that can happen |
|
140 // as a result is that dispatchMessages() will be called needlessly. |
|
141 if (m_messagePorts.contains(port) && port->started()) |
|
142 port->dispatchMessages(); |
|
143 } |
|
144 } |
|
145 |
|
146 void ScriptExecutionContext::createdMessagePort(MessagePort* port) |
|
147 { |
|
148 ASSERT(port); |
|
149 #if ENABLE(WORKERS) |
|
150 ASSERT((isDocument() && isMainThread()) |
|
151 || (isWorkerContext() && currentThread() == static_cast<WorkerContext*>(this)->thread()->threadID())); |
|
152 #endif |
|
153 |
|
154 m_messagePorts.add(port); |
|
155 } |
|
156 |
|
157 void ScriptExecutionContext::destroyedMessagePort(MessagePort* port) |
|
158 { |
|
159 ASSERT(port); |
|
160 #if ENABLE(WORKERS) |
|
161 ASSERT((isDocument() && isMainThread()) |
|
162 || (isWorkerContext() && currentThread() == static_cast<WorkerContext*>(this)->thread()->threadID())); |
|
163 #endif |
|
164 |
|
165 m_messagePorts.remove(port); |
|
166 } |
|
167 |
|
168 bool ScriptExecutionContext::canSuspendActiveDOMObjects() |
|
169 { |
|
170 // No protection against m_activeDOMObjects changing during iteration: canSuspend() shouldn't execute arbitrary JS. |
|
171 HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end(); |
|
172 for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { |
|
173 ASSERT(iter->first->scriptExecutionContext() == this); |
|
174 if (!iter->first->canSuspend()) |
|
175 return false; |
|
176 } |
|
177 return true; |
|
178 } |
|
179 |
|
180 void ScriptExecutionContext::suspendActiveDOMObjects() |
|
181 { |
|
182 // No protection against m_activeDOMObjects changing during iteration: suspend() shouldn't execute arbitrary JS. |
|
183 HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end(); |
|
184 for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { |
|
185 ASSERT(iter->first->scriptExecutionContext() == this); |
|
186 iter->first->suspend(); |
|
187 } |
|
188 } |
|
189 |
|
190 void ScriptExecutionContext::resumeActiveDOMObjects() |
|
191 { |
|
192 // No protection against m_activeDOMObjects changing during iteration: resume() shouldn't execute arbitrary JS. |
|
193 HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end(); |
|
194 for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { |
|
195 ASSERT(iter->first->scriptExecutionContext() == this); |
|
196 iter->first->resume(); |
|
197 } |
|
198 } |
|
199 |
|
200 void ScriptExecutionContext::stopActiveDOMObjects() |
|
201 { |
|
202 // No protection against m_activeDOMObjects changing during iteration: stop() 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->stop(); |
|
207 } |
|
208 } |
|
209 |
|
210 void ScriptExecutionContext::createdActiveDOMObject(ActiveDOMObject* object, void* upcastPointer) |
|
211 { |
|
212 ASSERT(object); |
|
213 ASSERT(upcastPointer); |
|
214 m_activeDOMObjects.add(object, upcastPointer); |
|
215 } |
|
216 |
|
217 void ScriptExecutionContext::destroyedActiveDOMObject(ActiveDOMObject* object) |
|
218 { |
|
219 ASSERT(object); |
|
220 m_activeDOMObjects.remove(object); |
|
221 } |
|
222 |
|
223 void ScriptExecutionContext::setSecurityOrigin(PassRefPtr<SecurityOrigin> securityOrigin) |
|
224 { |
|
225 m_securityOrigin = securityOrigin; |
|
226 } |
|
227 |
|
228 void ScriptExecutionContext::addTimeout(int timeoutId, DOMTimer* timer) |
|
229 { |
|
230 ASSERT(!m_timeouts.contains(timeoutId)); |
|
231 m_timeouts.set(timeoutId, timer); |
|
232 } |
|
233 |
|
234 void ScriptExecutionContext::removeTimeout(int timeoutId) |
|
235 { |
|
236 m_timeouts.remove(timeoutId); |
|
237 } |
|
238 |
|
239 DOMTimer* ScriptExecutionContext::findTimeout(int timeoutId) |
|
240 { |
|
241 return m_timeouts.get(timeoutId); |
|
242 } |
|
243 |
|
244 #if ENABLE(FILE_READER) || ENABLE(FILE_WRITER) |
|
245 FileThread* ScriptExecutionContext::fileThread() |
|
246 { |
|
247 if (!m_fileThread) { |
|
248 m_fileThread = FileThread::create(); |
|
249 if (!m_fileThread->start()) |
|
250 m_fileThread = 0; |
|
251 } |
|
252 return m_fileThread.get(); |
|
253 } |
|
254 #endif |
|
255 |
|
256 ScriptExecutionContext::Task::~Task() |
|
257 { |
|
258 } |
|
259 |
|
260 #if USE(JSC) |
|
261 JSC::JSGlobalData* ScriptExecutionContext::globalData() |
|
262 { |
|
263 if (isDocument()) |
|
264 return JSDOMWindow::commonJSGlobalData(); |
|
265 |
|
266 #if ENABLE(WORKERS) |
|
267 if (isWorkerContext()) |
|
268 return static_cast<WorkerContext*>(this)->script()->globalData(); |
|
269 #endif |
|
270 |
|
271 ASSERT_NOT_REACHED(); |
|
272 return 0; |
|
273 } |
|
274 #endif |
|
275 |
|
276 } // namespace WebCore |