Changeset 19183 in webkit for trunk/JavaScriptCore/bindings/runtime_root.cpp
- Timestamp:
- Jan 26, 2007, 8:50:17 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/bindings/runtime_root.cpp
r18811 r19183 28 28 #include "runtime_root.h" 29 29 #include <wtf/HashCountedSet.h> 30 #include <wtf/HashSet.h> 30 31 31 32 namespace KJS { namespace Bindings { 32 33 33 // Java does NOT always call finalize (and thus KJS_JSObject_JSFinalize) when 34 // it collects an objects. This presents some difficulties. We must ensure 35 // the a JavaJSObject's corresponding JavaScript object doesn't get collected. We 36 // do this by incrementing the JavaScript's reference count the first time we 37 // create a JavaJSObject for it, and decrementing the JavaScript reference count when 38 // the last JavaJSObject that refers to it is finalized, or when the applet is 39 // shutdown. 40 // 41 // To do this we keep a map that maps each applet instance 42 // to the JavaScript objects it is referencing. For each JavaScript instance 43 // we also maintain a secondary reference count. When that reference count reaches 44 // 1 OR the applet is shutdown we deref the JavaScript instance. Applet instances 45 // are represented by a jlong. 46 47 typedef HashMap<const RootObject*, ProtectCountSet*> RootObjectMap; 48 49 static RootObjectMap* rootObjectMap() 50 { 51 static RootObjectMap staticRootObjectMap; 52 return &staticRootObjectMap; 53 } 54 55 static ProtectCountSet* getProtectCountSet(const RootObject* rootObject) 56 { 57 ProtectCountSet* protectCountSet = rootObjectMap()->get(rootObject); 58 59 if (!protectCountSet) { 60 protectCountSet = new ProtectCountSet; 61 rootObjectMap()->add(rootObject, protectCountSet); 62 } 63 return protectCountSet; 64 } 65 66 static void destroyProtectCountSet(const RootObject* rootObject, ProtectCountSet* protectCountSet) 67 { 68 rootObjectMap()->remove(rootObject); 69 delete protectCountSet; 34 // This code attempts to solve two problems: (1) plug-ins leaking references to 35 // JS and the DOM; (2) plug-ins holding stale references to JS and the DOM. Previous 36 // comments in this file claimed that problem #1 was an issue in Java, in particular, 37 // because Java, allegedly, didn't always call finalize when collecting an object. 38 39 typedef HashSet<RootObject*> RootObjectSet; 40 41 static RootObjectSet* rootObjectSet() 42 { 43 static RootObjectSet staticRootObjectSet; 44 return &staticRootObjectSet; 70 45 } 71 46 … … 73 48 // fix them by adding a JSObject to RootObject dictionary. 74 49 75 ProtectCountSet* findProtectCountSet(JSObject* jsObject) 76 { 77 const RootObject* rootObject = findRootObject(jsObject); 78 return rootObject ? getProtectCountSet(rootObject) : 0; 79 } 80 81 const RootObject* findRootObject(JSObject* jsObject) 82 { 83 RootObjectMap::const_iterator end = rootObjectMap()->end(); 84 for (RootObjectMap::const_iterator it = rootObjectMap()->begin(); it != end; ++it) { 85 ProtectCountSet* set = it->second; 86 if (set->contains(jsObject)) 87 return it->first; 88 } 89 50 RootObject* findRootObject(JSObject* jsObject) 51 { 52 RootObjectSet::const_iterator end = rootObjectSet()->end(); 53 for (RootObjectSet::const_iterator it = rootObjectSet()->begin(); it != end; ++it) { 54 if ((*it)->gcIsProtected(jsObject)) 55 return *it; 56 } 90 57 return 0; 91 58 } 92 59 93 const RootObject* findRootObject(Interpreter* interpreter) 94 { 95 RootObjectMap::const_iterator end = rootObjectMap()->end(); 96 for (RootObjectMap::const_iterator it = rootObjectMap()->begin(); it != end; ++it) { 97 const RootObject* aRootObject = it->first; 98 99 if (aRootObject->interpreter() == interpreter) 100 return aRootObject; 101 } 102 60 RootObject* findRootObject(Interpreter* interpreter) 61 { 62 RootObjectSet::const_iterator end = rootObjectSet()->end(); 63 for (RootObjectSet::const_iterator it = rootObjectSet()->begin(); it != end; ++it) { 64 if ((*it)->interpreter() == interpreter) 65 return *it; 66 } 103 67 return 0; 104 }105 106 void addNativeReference(const RootObject* rootObject, JSObject* jsObject)107 {108 if (!rootObject)109 return;110 111 ProtectCountSet* protectCountSet = getProtectCountSet(rootObject);112 if (!protectCountSet->contains(jsObject)) {113 JSLock lock;114 gcProtect(jsObject);115 }116 protectCountSet->add(jsObject);117 }118 119 void removeNativeReference(JSObject* jsObject)120 {121 if (!jsObject)122 return;123 124 // We might have manually detroyed the root object and its protect set already125 ProtectCountSet* protectCountSet = findProtectCountSet(jsObject);126 if (!protectCountSet)127 return;128 129 if (protectCountSet->count(jsObject) == 1) {130 JSLock lock;131 gcUnprotect(jsObject);132 }133 protectCountSet->remove(jsObject);134 68 } 135 69 … … 256 190 CFRunLoopAddSource(RootObject::_runLoop, RootObject::_performJavaScriptSource, kCFRunLoopDefaultMode); 257 191 } 192 258 193 #endif 259 194 260 // Destroys the RootObject and unprotects all JSObjects associated with it. 261 void RootObject::destroy() 262 { 263 ProtectCountSet* protectCountSet = getProtectCountSet(this); 264 265 if (protectCountSet) { 266 ProtectCountSet::iterator end = protectCountSet->end(); 267 for (ProtectCountSet::iterator it = protectCountSet->begin(); it != end; ++it) { 268 JSLock lock; 269 gcUnprotect(it->first); 270 } 271 272 destroyProtectCountSet(this, protectCountSet); 273 } 274 275 delete this; 195 PassRefPtr<RootObject> RootObject::create(const void* nativeHandle, PassRefPtr<Interpreter> interpreter) 196 { 197 return new RootObject(nativeHandle, interpreter); 198 } 199 200 RootObject::RootObject(const void* nativeHandle, PassRefPtr<Interpreter> interpreter) 201 : m_refCount(0) 202 , m_isValid(true) 203 , m_nativeHandle(nativeHandle) 204 , m_interpreter(interpreter) 205 { 206 ASSERT(m_interpreter); 207 rootObjectSet()->add(this); 208 } 209 210 RootObject::~RootObject() 211 { 212 if (m_isValid) 213 invalidate(); 214 } 215 216 void RootObject::invalidate() 217 { 218 if (!m_isValid) 219 return; 220 221 m_isValid = false; 222 223 m_nativeHandle = 0; 224 m_interpreter = 0; 225 226 ProtectCountSet::iterator end = m_protectCountSet.end(); 227 for (ProtectCountSet::iterator it = m_protectCountSet.begin(); it != end; ++it) { 228 JSLock lock; 229 KJS::gcUnprotect(it->first); 230 } 231 m_protectCountSet.clear(); 232 233 rootObjectSet()->remove(this); 234 } 235 236 void RootObject::gcProtect(JSObject* jsObject) 237 { 238 ASSERT(m_isValid); 239 240 if (!m_protectCountSet.contains(jsObject)) { 241 JSLock lock; 242 KJS::gcProtect(jsObject); 243 } 244 m_protectCountSet.add(jsObject); 245 } 246 247 void RootObject::gcUnprotect(JSObject* jsObject) 248 { 249 ASSERT(m_isValid); 250 251 if (!jsObject) 252 return; 253 254 if (m_protectCountSet.count(jsObject) == 1) { 255 JSLock lock; 256 KJS::gcUnprotect(jsObject); 257 } 258 m_protectCountSet.remove(jsObject); 259 } 260 261 bool RootObject::gcIsProtected(JSObject* jsObject) 262 { 263 ASSERT(m_isValid); 264 return m_protectCountSet.contains(jsObject); 265 } 266 267 const void* RootObject::nativeHandle() const 268 { 269 ASSERT(m_isValid); 270 return m_nativeHandle; 271 } 272 273 Interpreter* RootObject::interpreter() const 274 { 275 ASSERT(m_isValid); 276 return m_interpreter.get(); 276 277 } 277 278
Note:
See TracChangeset
for help on using the changeset viewer.