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 "Document.h"
32 #include "MessagePort.h"
33 #include "SecurityOrigin.h"
34 #include "WorkerContext.h"
35 #include "WorkerThread.h"
36 #include <wtf/MainThread.h>
37 #include <wtf/PassRefPtr.h>
38
39 namespace WebCore {
40
41 class ProcessMessagesSoonTask : public ScriptExecutionContext::Task {
42 public:
create()43 static PassRefPtr<ProcessMessagesSoonTask> create()
44 {
45 return adoptRef(new ProcessMessagesSoonTask);
46 }
47
performTask(ScriptExecutionContext * context)48 virtual void performTask(ScriptExecutionContext* context)
49 {
50 context->dispatchMessagePortEvents();
51 }
52 };
53
ScriptExecutionContext()54 ScriptExecutionContext::ScriptExecutionContext()
55 {
56 }
57
~ScriptExecutionContext()58 ScriptExecutionContext::~ScriptExecutionContext()
59 {
60 HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
61 for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
62 ASSERT(iter->first->scriptExecutionContext() == this);
63 iter->first->contextDestroyed();
64 }
65
66 HashSet<MessagePort*>::iterator messagePortsEnd = m_messagePorts.end();
67 for (HashSet<MessagePort*>::iterator iter = m_messagePorts.begin(); iter != messagePortsEnd; ++iter) {
68 ASSERT((*iter)->scriptExecutionContext() == this);
69 (*iter)->contextDestroyed();
70 }
71 }
72
processMessagePortMessagesSoon()73 void ScriptExecutionContext::processMessagePortMessagesSoon()
74 {
75 postTask(ProcessMessagesSoonTask::create());
76 }
77
dispatchMessagePortEvents()78 void ScriptExecutionContext::dispatchMessagePortEvents()
79 {
80 RefPtr<ScriptExecutionContext> protect(this);
81
82 // Make a frozen copy.
83 Vector<MessagePort*> ports;
84 copyToVector(m_messagePorts, ports);
85
86 unsigned portCount = ports.size();
87 for (unsigned i = 0; i < portCount; ++i) {
88 MessagePort* port = ports[i];
89 // The port may be destroyed, and another one created at the same address, but this is safe, as the worst that can happen
90 // as a result is that dispatchMessages() will be called needlessly.
91 if (m_messagePorts.contains(port) && port->queueIsOpen())
92 port->dispatchMessages();
93 }
94 }
95
createdMessagePort(MessagePort * port)96 void ScriptExecutionContext::createdMessagePort(MessagePort* port)
97 {
98 ASSERT(port);
99 #if ENABLE(WORKERS)
100 ASSERT((isDocument() && isMainThread())
101 || (isWorkerContext() && currentThread() == static_cast<WorkerContext*>(this)->thread()->threadID()));
102 #endif
103
104 m_messagePorts.add(port);
105 }
106
destroyedMessagePort(MessagePort * port)107 void ScriptExecutionContext::destroyedMessagePort(MessagePort* port)
108 {
109 ASSERT(port);
110 #if ENABLE(WORKERS)
111 ASSERT((isDocument() && isMainThread())
112 || (isWorkerContext() && currentThread() == static_cast<WorkerContext*>(this)->thread()->threadID()));
113 #endif
114
115 m_messagePorts.remove(port);
116 }
117
canSuspendActiveDOMObjects()118 bool ScriptExecutionContext::canSuspendActiveDOMObjects()
119 {
120 // No protection against m_activeDOMObjects changing during iteration: canSuspend() shouldn't execute arbitrary JS.
121 HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
122 for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
123 ASSERT(iter->first->scriptExecutionContext() == this);
124 if (!iter->first->canSuspend())
125 return false;
126 }
127 return true;
128 }
129
suspendActiveDOMObjects()130 void ScriptExecutionContext::suspendActiveDOMObjects()
131 {
132 // No protection against m_activeDOMObjects changing during iteration: suspend() shouldn't execute arbitrary JS.
133 HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
134 for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
135 ASSERT(iter->first->scriptExecutionContext() == this);
136 iter->first->suspend();
137 }
138 }
139
resumeActiveDOMObjects()140 void ScriptExecutionContext::resumeActiveDOMObjects()
141 {
142 // No protection against m_activeDOMObjects changing during iteration: resume() shouldn't execute arbitrary JS.
143 HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
144 for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
145 ASSERT(iter->first->scriptExecutionContext() == this);
146 iter->first->resume();
147 }
148 }
149
stopActiveDOMObjects()150 void ScriptExecutionContext::stopActiveDOMObjects()
151 {
152 // No protection against m_activeDOMObjects changing during iteration: stop() shouldn't execute arbitrary JS.
153 HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
154 for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
155 ASSERT(iter->first->scriptExecutionContext() == this);
156 iter->first->stop();
157 }
158 }
159
createdActiveDOMObject(ActiveDOMObject * object,void * upcastPointer)160 void ScriptExecutionContext::createdActiveDOMObject(ActiveDOMObject* object, void* upcastPointer)
161 {
162 ASSERT(object);
163 ASSERT(upcastPointer);
164 m_activeDOMObjects.add(object, upcastPointer);
165 }
166
destroyedActiveDOMObject(ActiveDOMObject * object)167 void ScriptExecutionContext::destroyedActiveDOMObject(ActiveDOMObject* object)
168 {
169 ASSERT(object);
170 m_activeDOMObjects.remove(object);
171 }
172
setSecurityOrigin(PassRefPtr<SecurityOrigin> securityOrigin)173 void ScriptExecutionContext::setSecurityOrigin(PassRefPtr<SecurityOrigin> securityOrigin)
174 {
175 m_securityOrigin = securityOrigin;
176 }
177
~Task()178 ScriptExecutionContext::Task::~Task()
179 {
180 }
181
182 } // namespace WebCore
183