Home | History | Annotate | Download | only in bridge
      1 /*
      2  * Copyright (C) 2004 Apple Computer, 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 #include "config.h"
     27 #include "runtime_root.h"
     28 
     29 #include "BridgeJSC.h"
     30 #include "runtime_object.h"
     31 #include <runtime/JSGlobalObject.h>
     32 #include <wtf/HashCountedSet.h>
     33 #include <wtf/HashSet.h>
     34 #include <wtf/StdLibExtras.h>
     35 
     36 namespace JSC { namespace Bindings {
     37 
     38 // This code attempts to solve two problems: (1) plug-ins leaking references to
     39 // JS and the DOM; (2) plug-ins holding stale references to JS and the DOM. Previous
     40 // comments in this file claimed that problem #1 was an issue in Java, in particular,
     41 // because Java, allegedly, didn't always call finalize when collecting an object.
     42 
     43 typedef HashSet<RootObject*> RootObjectSet;
     44 
     45 static RootObjectSet* rootObjectSet()
     46 {
     47     DEFINE_STATIC_LOCAL(RootObjectSet, staticRootObjectSet, ());
     48     return &staticRootObjectSet;
     49 }
     50 
     51 // FIXME:  These two functions are a potential performance problem.  We could
     52 // fix them by adding a JSObject to RootObject dictionary.
     53 
     54 RootObject* findProtectingRootObject(JSObject* jsObject)
     55 {
     56     RootObjectSet::const_iterator end = rootObjectSet()->end();
     57     for (RootObjectSet::const_iterator it = rootObjectSet()->begin(); it != end; ++it) {
     58         if ((*it)->gcIsProtected(jsObject))
     59             return *it;
     60     }
     61     return 0;
     62 }
     63 
     64 RootObject* findRootObject(JSGlobalObject* globalObject)
     65 {
     66     RootObjectSet::const_iterator end = rootObjectSet()->end();
     67     for (RootObjectSet::const_iterator it = rootObjectSet()->begin(); it != end; ++it) {
     68         if ((*it)->globalObject() == globalObject)
     69             return *it;
     70     }
     71     return 0;
     72 }
     73 
     74 RootObject::InvalidationCallback::~InvalidationCallback()
     75 {
     76 }
     77 
     78 PassRefPtr<RootObject> RootObject::create(const void* nativeHandle, JSGlobalObject* globalObject)
     79 {
     80     return adoptRef(new RootObject(nativeHandle, globalObject));
     81 }
     82 
     83 RootObject::RootObject(const void* nativeHandle, JSGlobalObject* globalObject)
     84     : m_isValid(true)
     85     , m_nativeHandle(nativeHandle)
     86     , m_globalObject(globalObject->globalData(), globalObject)
     87 {
     88     ASSERT(globalObject);
     89     rootObjectSet()->add(this);
     90 }
     91 
     92 RootObject::~RootObject()
     93 {
     94     if (m_isValid)
     95         invalidate();
     96 }
     97 
     98 void RootObject::invalidate()
     99 {
    100     if (!m_isValid)
    101         return;
    102 
    103     {
    104         WeakGCMap<RuntimeObject*, RuntimeObject>::iterator end = m_runtimeObjects.end();
    105         for (WeakGCMap<RuntimeObject*, RuntimeObject>::iterator it = m_runtimeObjects.begin(); it != end; ++it) {
    106             it.get().second->invalidate();
    107         }
    108 
    109         m_runtimeObjects.clear();
    110     }
    111 
    112     m_isValid = false;
    113 
    114     m_nativeHandle = 0;
    115     m_globalObject.clear();
    116 
    117     {
    118         HashSet<InvalidationCallback*>::iterator end = m_invalidationCallbacks.end();
    119         for (HashSet<InvalidationCallback*>::iterator iter = m_invalidationCallbacks.begin(); iter != end; ++iter)
    120             (**iter)(this);
    121 
    122         m_invalidationCallbacks.clear();
    123     }
    124 
    125     ProtectCountSet::iterator end = m_protectCountSet.end();
    126     for (ProtectCountSet::iterator it = m_protectCountSet.begin(); it != end; ++it)
    127         JSC::gcUnprotect(it->first);
    128     m_protectCountSet.clear();
    129 
    130     rootObjectSet()->remove(this);
    131 }
    132 
    133 void RootObject::gcProtect(JSObject* jsObject)
    134 {
    135     ASSERT(m_isValid);
    136 
    137     if (!m_protectCountSet.contains(jsObject))
    138         JSC::gcProtect(jsObject);
    139     m_protectCountSet.add(jsObject);
    140 }
    141 
    142 void RootObject::gcUnprotect(JSObject* jsObject)
    143 {
    144     ASSERT(m_isValid);
    145 
    146     if (!jsObject)
    147         return;
    148 
    149     if (m_protectCountSet.count(jsObject) == 1)
    150         JSC::gcUnprotect(jsObject);
    151     m_protectCountSet.remove(jsObject);
    152 }
    153 
    154 bool RootObject::gcIsProtected(JSObject* jsObject)
    155 {
    156     ASSERT(m_isValid);
    157     return m_protectCountSet.contains(jsObject);
    158 }
    159 
    160 const void* RootObject::nativeHandle() const
    161 {
    162     ASSERT(m_isValid);
    163     return m_nativeHandle;
    164 }
    165 
    166 JSGlobalObject* RootObject::globalObject() const
    167 {
    168     ASSERT(m_isValid);
    169     return m_globalObject.get();
    170 }
    171 
    172 void RootObject::updateGlobalObject(JSGlobalObject* globalObject)
    173 {
    174     m_globalObject.set(globalObject->globalData(), globalObject);
    175 }
    176 
    177 void RootObject::addRuntimeObject(JSGlobalData& globalData, RuntimeObject* object)
    178 {
    179     ASSERT(m_isValid);
    180     ASSERT(!m_runtimeObjects.get(object));
    181 
    182     m_runtimeObjects.set(globalData, object, object);
    183 }
    184 
    185 void RootObject::removeRuntimeObject(RuntimeObject* object)
    186 {
    187     if (!m_isValid)
    188         return;
    189 
    190     ASSERT(m_runtimeObjects.get(object));
    191 
    192     m_runtimeObjects.take(object);
    193 }
    194 
    195 } } // namespace JSC::Bindings
    196