1/* 2 * Copyright (C) 2004 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 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. 24 */ 25 26#include "config.h" 27#include "runtime_root.h" 28 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> 38#include <wtf/Ref.h> 39#include <wtf/StdLibExtras.h> 40 41namespace JSC { namespace Bindings { 42 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. 47 48typedef HashSet<RootObject*> RootObjectSet; 49 50static RootObjectSet& rootObjectSet() 51{ 52 static NeverDestroyed<RootObjectSet> staticRootObjectSet; 53 return staticRootObjectSet; 54} 55 56// FIXME: These two functions are a potential performance problem. We could 57// fix them by adding a JSObject to RootObject dictionary. 58 59RootObject* findProtectingRootObject(JSObject* jsObject) 60{ 61 RootObjectSet::const_iterator end = rootObjectSet().end(); 62 for (RootObjectSet::const_iterator it = rootObjectSet().begin(); it != end; ++it) { 63 if ((*it)->gcIsProtected(jsObject)) 64 return *it; 65 } 66 return 0; 67} 68 69RootObject* findRootObject(JSGlobalObject* globalObject) 70{ 71 RootObjectSet::const_iterator end = rootObjectSet().end(); 72 for (RootObjectSet::const_iterator it = rootObjectSet().begin(); it != end; ++it) { 73 if ((*it)->globalObject() == globalObject) 74 return *it; 75 } 76 return 0; 77} 78 79RootObject::InvalidationCallback::~InvalidationCallback() 80{ 81} 82 83PassRefPtr<RootObject> RootObject::create(const void* nativeHandle, JSGlobalObject* globalObject) 84{ 85 return adoptRef(new RootObject(nativeHandle, globalObject)); 86} 87 88RootObject::RootObject(const void* nativeHandle, JSGlobalObject* globalObject) 89 : m_isValid(true) 90 , m_nativeHandle(nativeHandle) 91 , m_globalObject(globalObject->vm(), globalObject) 92{ 93 ASSERT(globalObject); 94 rootObjectSet().add(this); 95} 96 97RootObject::~RootObject() 98{ 99 if (m_isValid) 100 invalidate(); 101} 102 103void RootObject::invalidate() 104{ 105 if (!m_isValid) 106 return; 107 108 { 109 HashMap<RuntimeObject*, JSC::Weak<RuntimeObject>>::iterator end = m_runtimeObjects.end(); 110 for (HashMap<RuntimeObject*, JSC::Weak<RuntimeObject>>::iterator it = m_runtimeObjects.begin(); it != end; ++it) { 111 RuntimeObject* runtimeObject = it->value.get(); 112 if (!runtimeObject) // Skip zombies. 113 continue; 114 runtimeObject->invalidate(); 115 } 116 117 m_runtimeObjects.clear(); 118 } 119 120 m_isValid = false; 121 122 m_nativeHandle = 0; 123 m_globalObject.clear(); 124 125 { 126 HashSet<InvalidationCallback*>::iterator end = m_invalidationCallbacks.end(); 127 for (HashSet<InvalidationCallback*>::iterator iter = m_invalidationCallbacks.begin(); iter != end; ++iter) 128 (**iter)(this); 129 130 m_invalidationCallbacks.clear(); 131 } 132 133 ProtectCountSet::iterator end = m_protectCountSet.end(); 134 for (ProtectCountSet::iterator it = m_protectCountSet.begin(); it != end; ++it) 135 JSC::gcUnprotect(it->key); 136 m_protectCountSet.clear(); 137 138 rootObjectSet().remove(this); 139} 140 141void RootObject::gcProtect(JSObject* jsObject) 142{ 143 ASSERT(m_isValid); 144 145 if (!m_protectCountSet.contains(jsObject)) { 146 JSC::JSLockHolder holder(&globalObject()->vm()); 147 JSC::gcProtect(jsObject); 148 } 149 m_protectCountSet.add(jsObject); 150} 151 152void RootObject::gcUnprotect(JSObject* jsObject) 153{ 154 ASSERT(m_isValid); 155 156 if (!jsObject) 157 return; 158 159 if (m_protectCountSet.count(jsObject) == 1) { 160 JSC::JSLockHolder holder(&globalObject()->vm()); 161 JSC::gcUnprotect(jsObject); 162 } 163 m_protectCountSet.remove(jsObject); 164} 165 166bool RootObject::gcIsProtected(JSObject* jsObject) 167{ 168 ASSERT(m_isValid); 169 return m_protectCountSet.contains(jsObject); 170} 171 172const void* RootObject::nativeHandle() const 173{ 174 ASSERT(m_isValid); 175 return m_nativeHandle; 176} 177 178JSGlobalObject* RootObject::globalObject() const 179{ 180 ASSERT(m_isValid); 181 return m_globalObject.get(); 182} 183 184void RootObject::updateGlobalObject(JSGlobalObject* globalObject) 185{ 186 m_globalObject.set(globalObject->vm(), globalObject); 187} 188 189void RootObject::addRuntimeObject(VM&, RuntimeObject* object) 190{ 191 ASSERT(m_isValid); 192 weakAdd(m_runtimeObjects, object, JSC::Weak<RuntimeObject>(object, this)); 193} 194 195void RootObject::removeRuntimeObject(RuntimeObject* object) 196{ 197 if (!m_isValid) 198 return; 199 weakRemove(m_runtimeObjects, object, object); 200} 201 202void RootObject::finalize(JSC::Handle<JSC::Unknown> handle, void*) 203{ 204 RuntimeObject* object = static_cast<RuntimeObject*>(handle.slot()->asCell()); 205 206 Ref<RootObject> protect(*this); 207 object->invalidate(); 208 weakRemove(m_runtimeObjects, object, object); 209} 210 211} } // namespace JSC::Bindings 212