2 * Copyright (C) 2004 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
13 * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
27 #include "runtime_root.h"
29 #include "BridgeJSC.h"
30 #include "runtime_object.h"
31 #include <heap/StrongInlines.h>
32 #include <heap/Weak.h>
33 #include <heap/WeakInlines.h>
34 #include <runtime/JSGlobalObject.h>
35 #include <wtf/HashCountedSet.h>
36 #include <wtf/HashSet.h>
37 #include <wtf/NeverDestroyed.h>
39 #include <wtf/StdLibExtras.h>
41 namespace JSC { namespace Bindings {
43 // This code attempts to solve two problems: (1) plug-ins leaking references to
44 // JS and the DOM; (2) plug-ins holding stale references to JS and the DOM. Previous
45 // comments in this file claimed that problem #1 was an issue in Java, in particular,
46 // because Java, allegedly, didn't always call finalize when collecting an object.
48 typedef HashSet<RootObject*> RootObjectSet;
50 static RootObjectSet& rootObjectSet()
52 static NeverDestroyed<RootObjectSet> staticRootObjectSet;
53 return staticRootObjectSet;
56 // FIXME: These two functions are a potential performance problem. We could
57 // fix them by adding a JSObject to RootObject dictionary.
59 RootObject* findProtectingRootObject(JSObject* jsObject)
61 RootObjectSet::const_iterator end = rootObjectSet().end();
62 for (RootObjectSet::const_iterator it = rootObjectSet().begin(); it != end; ++it) {
63 if ((*it)->gcIsProtected(jsObject))
69 RootObject* findRootObject(JSGlobalObject* globalObject)
71 RootObjectSet::const_iterator end = rootObjectSet().end();
72 for (RootObjectSet::const_iterator it = rootObjectSet().begin(); it != end; ++it) {
73 if ((*it)->globalObject() == globalObject)
79 RootObject::InvalidationCallback::~InvalidationCallback()
83 PassRefPtr<RootObject> RootObject::create(const void* nativeHandle, JSGlobalObject* globalObject)
85 return adoptRef(new RootObject(nativeHandle, globalObject));
88 RootObject::RootObject(const void* nativeHandle, JSGlobalObject* globalObject)
90 , m_nativeHandle(nativeHandle)
91 , m_globalObject(globalObject->vm(), globalObject)
94 rootObjectSet().add(this);
97 RootObject::~RootObject()
103 void RootObject::invalidate()
109 // Get the objects from the keys; the values might be nulled.
110 // Safe because finalized runtime objects are removed from m_runtimeObjects by RootObject::finalize.
111 for (RuntimeObject* runtimeObject : m_runtimeObjects.keys())
112 runtimeObject->invalidate();
114 m_runtimeObjects.clear();
120 m_globalObject.clear();
123 HashSet<InvalidationCallback*>::iterator end = m_invalidationCallbacks.end();
124 for (HashSet<InvalidationCallback*>::iterator iter = m_invalidationCallbacks.begin(); iter != end; ++iter)
127 m_invalidationCallbacks.clear();
130 ProtectCountSet::iterator end = m_protectCountSet.end();
131 for (ProtectCountSet::iterator it = m_protectCountSet.begin(); it != end; ++it)
132 JSC::gcUnprotect(it->key);
133 m_protectCountSet.clear();
135 rootObjectSet().remove(this);
138 void RootObject::gcProtect(JSObject* jsObject)
142 if (!m_protectCountSet.contains(jsObject)) {
143 JSC::JSLockHolder holder(&globalObject()->vm());
144 JSC::gcProtect(jsObject);
146 m_protectCountSet.add(jsObject);
149 void RootObject::gcUnprotect(JSObject* jsObject)
156 if (m_protectCountSet.count(jsObject) == 1) {
157 JSC::JSLockHolder holder(&globalObject()->vm());
158 JSC::gcUnprotect(jsObject);
160 m_protectCountSet.remove(jsObject);
163 bool RootObject::gcIsProtected(JSObject* jsObject)
166 return m_protectCountSet.contains(jsObject);
169 const void* RootObject::nativeHandle() const
172 return m_nativeHandle;
175 JSGlobalObject* RootObject::globalObject() const
178 return m_globalObject.get();
181 void RootObject::updateGlobalObject(JSGlobalObject* globalObject)
183 m_globalObject.set(globalObject->vm(), globalObject);
186 void RootObject::addRuntimeObject(VM&, RuntimeObject* object)
189 weakAdd(m_runtimeObjects, object, JSC::Weak<RuntimeObject>(object, this));
192 void RootObject::removeRuntimeObject(RuntimeObject* object)
196 weakRemove(m_runtimeObjects, object, object);
199 void RootObject::finalize(JSC::Handle<JSC::Unknown> handle, void*)
201 RuntimeObject* object = static_cast<RuntimeObject*>(handle.slot()->asCell());
203 Ref<RootObject> protect(*this);
204 object->invalidate();
205 weakRemove(m_runtimeObjects, object, object);
208 } } // namespace JSC::Bindings