Changeset 19183 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
Jan 26, 2007, 8:50:17 PM (18 years ago)
Author:
ggaren
Message:

JavaScriptCore:

Reviewed by Maciej Stachowiak.


Fixed <rdar://problem/4608404> WebScriptObject's _rootObject lack
of ownership policy causes crashes (e.g., in Dashcode)


The old model for RootObject ownership was either to (1) leak them or (2) assign
them to a single owner -- the WebCore::Frame -- which would destroy them
when it believed that all of its plug-ins had unloaded.


This model was broken because of (1) and also because plug-ins are not the only
RootObject clients. All Bindings clients are RootObjects clients, including
applications, which outlive any particular WebCore::Frame.


The new model for RootObject ownership is to reference-count them, with a
throw-back to the old model: The WebCore::Frame tracks the RootObjects
it creates, and invalidates them when it believes that all of its plug-ins
have unloaded.


We maintain this throw-back to avoid plug-in leaks, particularly from Java.
Java is completely broken when it comes to releasing JavaScript objects.
Comments in our code allege that Java does not always call finalize when
collecting objects. Moreoever, my own testing reveals that, when Java does
notify JavaScript of a finalize, the data it provides is totally bogus.


This setup is far from ideal, but I don't think we can do better without
completely rewriting the bindings code, and possibly part of the Java
plug-in / VM.


Layout tests pass. No additional leaks reported. WebCore/manual-tests/*liveconnect*
and a few LiveConnect demos on the web also run without a hitch.


const RootObject* => RootObject*, since we need to ref/deref


  • bindings/NP_jsobject.cpp: (jsDeallocate): deref our RootObjects. Also unprotect or JSObject, instead of just relying on the RootObject to do it for us when it's invalidated. (_isSafeScript): Check RootObject validity. (_NPN_CreateScriptObject): ditto (_NPN_Invoke): ditto (_NPN_Evaluate): ditto (_NPN_GetProperty): ditto (_NPN_SetProperty): ditto (_NPN_RemoveProperty): ditto (_NPN_HasProperty): ditto (_NPN_HasMethod): ditto (_NPN_SetException): ditto
  • bindings/runtime_root.cpp: Revived bit-rotted LIAR LIAR LIAR comment.


LOOK: Added support for invalidating RootObjects without deleting them,
which is the main goal of this patch.

Moved protect counting into the RootObject class, to emphasize that
the RootObject protects the JSObject, and unprotects it upon being invalidated.

addNativeReference => RootObject::gcProtect
removeNativeReference => RootObject::gcUnprotect
ProtectCountSet::contains => RootObject::gcIsProtected


I know we'll all be sad to see the word "native" go.


  • bindings/runtime_root.h: Added ref-counting support to RootObject, with all the standard accoutrements.
  • bindings/c/c_utility.cpp: (KJS::Bindings::convertValueToNPVariant): If we can't find a valid RootObject, return void instead of just leaking.
  • bindings/jni/jni_instance.cpp: (JavaInstance::JavaInstance): Don't take a RootObject in our constructor; be like other Instances and require the caller to call setRootObject. This reduces the number of ownership code paths. (JavaInstance::invokeMethod): Check RootObject for validity.
  • bindings/jni/jni_instance.h: Removed private no-arg constructor. Having an arg constructor accomplishes the same thing.
  • bindings/jni/jni_jsobject.cpp: (JavaJSObject::invoke): No need to call findProtectCountSet, because finalize() checks for RootObject validity. (JavaJSObject::JavaJSObject): check RootObject for validity (JavaJSObject::call): ditto (JavaJSObject::eval): ditto (JavaJSObject::getMember): ditto (JavaJSObject::setMember): ditto (JavaJSObject::removeMember): ditto (JavaJSObject::getSlot): ditto (JavaJSObject::setSlot): ditto (JavaJSObject::toString): ditto (JavaJSObject::finalize): ditto (JavaJSObject::createNative): No need to tell the RootObject to protect the global object, since the RootObject already owns the interpreter.
  • bindings/jni/jni_runtime.cpp: (JavaArray::JavaArray): Removed copy construcutor becaue it was unused. Dead code is dangerous code.
  • bindings/objc/objc_runtime.mm: Added WebUndefined protocol. Previous use of WebScriptObject was bogus, because WebUndefined is not a subclass of WebScriptObject. (convertValueToObjcObject): If we can't find a valid RootObject, return nil instead of just leaking.
  • bindings/objc/objc_utility.mm: (KJS::Bindings::convertValueToObjcValue): If we can't find a valid RootObject, return nil instead of just leaking.

LayoutTests:

Reviewed by Maciej Stachowiak.


Added test for <rdar://problem/4608404> WebScriptObject's _rootObject lack
of ownership policy causes crashes (e.g., in Dashcode)


No test for Java or NPP versions of this bug because there's no reliable way to
make Java and NPP objects outlive their RootObjects (although Java objects
sometimes do).

  • plugins/root-object-premature-delete-crash-expected.txt: Added.
  • plugins/root-object-premature-delete-crash.html: Added.

WebCore:

Reviewed by Maciej Stachowiak.


Fixed <rdar://problem/4608404> WebScriptObject's _executionContext lack
of ownership policy causes crashes (e.g., in Dashcode)

Added RootObject ref-counting goodness.

  • page/mac/FrameMac.h:
  • page/mac/FrameMac.mm: (WebCore::FrameMac::cleanupPluginObjects): Invalidate our RootObjects instead of detroying them. Track _bindingRootObject separately from the rest of our RootObjects, since it has its own variable.
  • page/mac/WebCoreFrameBridge.mm: (createRootObject): Use the Frame's new, more encapsulated function to create a RootObject.
  • bindings/objc/WebScriptObject.mm: Nixed rootObject setters, since they were unused and they complicated reference-counting.

WebKitTools:

Reviewed by Maciej Stachowiak.


Added support for test for <rdar://problem/4608404> WebScriptObject's
_rootObject lack of ownership policy causes crashes (e.g., in Dashcode)


  • DumpRenderTree/DumpRenderTree.m: (+[LayoutTestController isSelectorExcludedFromWebScript:]): (+[LayoutTestController webScriptNameForSelector:]): (-[LayoutTestController storeWebScriptObject:]): (-[LayoutTestController accessStoredWebScriptObject]): (-[LayoutTestController dealloc]):
Location:
trunk/JavaScriptCore
Files:
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r19178 r19183  
     12007-01-25  Geoffrey Garen  <[email protected]>
     2
     3        Reviewed by Maciej Stachowiak.
     4       
     5        Fixed <rdar://problem/4608404> WebScriptObject's _rootObject lack
     6        of ownership policy causes crashes (e.g., in Dashcode)
     7       
     8        The old model for RootObject ownership was either to (1) leak them or (2) assign
     9        them to a single owner -- the WebCore::Frame -- which would destroy them
     10        when it believed that all of its plug-ins had unloaded.
     11       
     12        This model was broken because of (1) and also because plug-ins are not the only
     13        RootObject clients. All Bindings clients are RootObjects clients, including
     14        applications, which outlive any particular WebCore::Frame.
     15       
     16        The new model for RootObject ownership is to reference-count them, with a
     17        throw-back to the old model: The WebCore::Frame tracks the RootObjects
     18        it creates, and invalidates them when it believes that all of its plug-ins
     19        have unloaded.
     20       
     21        We maintain this throw-back to avoid plug-in leaks, particularly from Java.
     22        Java is completely broken when it comes to releasing JavaScript objects.
     23        Comments in our code allege that Java does not always call finalize when
     24        collecting objects. Moreoever, my own testing reveals that, when Java does
     25        notify JavaScript of a finalize, the data it provides is totally bogus.
     26       
     27        This setup is far from ideal, but I don't think we can do better without
     28        completely rewriting the bindings code, and possibly part of the Java
     29        plug-in / VM.
     30       
     31        Layout tests pass. No additional leaks reported. WebCore/manual-tests/*liveconnect*
     32        and a few LiveConnect demos on the web also run without a hitch.
     33       
     34        const RootObject* => RootObject*, since we need to ref/deref
     35       
     36        * bindings/NP_jsobject.cpp:
     37        (jsDeallocate): deref our RootObjects. Also unprotect or JSObject, instead
     38        of just relying on the RootObject to do it for us when it's invalidated.
     39        (_isSafeScript): Check RootObject validity.
     40        (_NPN_CreateScriptObject): ditto
     41        (_NPN_Invoke): ditto
     42        (_NPN_Evaluate): ditto
     43        (_NPN_GetProperty): ditto
     44        (_NPN_SetProperty): ditto
     45        (_NPN_RemoveProperty): ditto
     46        (_NPN_HasProperty): ditto
     47        (_NPN_HasMethod): ditto
     48        (_NPN_SetException): ditto
     49
     50        * bindings/runtime_root.cpp:
     51        Revived bit-rotted LIAR LIAR LIAR comment.
     52       
     53        LOOK: Added support for invalidating RootObjects without deleting them,
     54        which is the main goal of this patch.
     55
     56        Moved protect counting into the RootObject class, to emphasize that
     57        the RootObject protects the JSObject, and unprotects it upon being invalidated.
     58            addNativeReference => RootObject::gcProtect
     59            removeNativeReference => RootObject::gcUnprotect
     60            ProtectCountSet::contains => RootObject::gcIsProtected
     61           
     62        I know we'll all be sad to see the word "native" go.
     63       
     64        * bindings/runtime_root.h: Added ref-counting support to RootObject, with
     65        all the standard accoutrements.
     66
     67        * bindings/c/c_utility.cpp:
     68        (KJS::Bindings::convertValueToNPVariant): If we can't find a valid RootObject,
     69        return void instead of just leaking.
     70
     71        * bindings/jni/jni_instance.cpp:
     72        (JavaInstance::JavaInstance): Don't take a RootObject in our constructor;
     73        be like other Instances and require the caller to call setRootObject. This
     74        reduces the number of ownership code paths.
     75        (JavaInstance::invokeMethod): Check RootObject for validity.
     76        * bindings/jni/jni_instance.h: Removed private no-arg constructor. Having
     77        an arg constructor accomplishes the same thing.
     78
     79        * bindings/jni/jni_jsobject.cpp:
     80        (JavaJSObject::invoke): No need to call findProtectCountSet, because finalize()
     81        checks for RootObject validity.
     82        (JavaJSObject::JavaJSObject): check RootObject for validity
     83        (JavaJSObject::call): ditto
     84        (JavaJSObject::eval): ditto
     85        (JavaJSObject::getMember): ditto
     86        (JavaJSObject::setMember): ditto
     87        (JavaJSObject::removeMember): ditto
     88        (JavaJSObject::getSlot): ditto
     89        (JavaJSObject::setSlot): ditto
     90        (JavaJSObject::toString): ditto
     91        (JavaJSObject::finalize): ditto
     92        (JavaJSObject::createNative): No need to tell the RootObject to protect
     93        the global object, since the RootObject already owns the interpreter.
     94
     95        * bindings/jni/jni_runtime.cpp:
     96        (JavaArray::JavaArray): Removed copy construcutor becaue it was unused.
     97        Dead code is dangerous code.
     98
     99        * bindings/objc/objc_runtime.mm: Added WebUndefined protocol. Previous use
     100        of WebScriptObject was bogus, because WebUndefined is not a subclass of
     101        WebScriptObject.
     102        (convertValueToObjcObject): If we can't find a valid RootObject,
     103        return nil instead of just leaking.
     104
     105        * bindings/objc/objc_utility.mm:
     106        (KJS::Bindings::convertValueToObjcValue): If we can't find a valid RootObject,
     107        return nil instead of just leaking.
     108
    11092007-01-27  Andrew Wellington  <[email protected]>
    2110
  • trunk/JavaScriptCore/JavaScriptCore.exp

    r18837 r19183  
    101101__NPN_SetProperty
    102102__NPN_UTF8FromIdentifier
    103 __Z23_NPN_CreateScriptObjectP4_NPPPN3KJS8JSObjectEPKNS1_8Bindings10RootObjectES7_
     103__Z23_NPN_CreateScriptObjectP4_NPPPN3KJS8JSObjectEN3WTF10PassRefPtrINS1_8Bindings10RootObjectEEES8_
    104104__Z25_NPN_CreateNoScriptObjectv
    105105__ZN3KJS10Identifier3addEPKNS_5UCharEi
     
    180180__ZN3KJS7UStringC1ERKS0_S2_
    181181__ZN3KJS7UStringaSEPKc
     182__ZN3KJS8Bindings10RootObject10invalidateEv
     183__ZN3KJS8Bindings10RootObject11gcUnprotectEPNS_8JSObjectE
    182184__ZN3KJS8Bindings10RootObject17_createRootObjectE
    183 __ZN3KJS8Bindings10RootObject19setCreateRootObjectEPFPS1_PvE
    184 __ZN3KJS8Bindings10RootObject7destroyEv
     185__ZN3KJS8Bindings10RootObject19setCreateRootObjectEPFN3WTF10PassRefPtrIS1_EEPvE
     186__ZN3KJS8Bindings10RootObject6createEPKvN3WTF10PassRefPtrINS_11InterpreterEEE
     187__ZN3KJS8Bindings10RootObject9gcProtectEPNS_8JSObjectE
     188__ZN3KJS8Bindings10RootObjectD1Ev
    185189__ZN3KJS8Bindings10throwErrorEPNS_9ExecStateENS_9ErrorTypeEP8NSString
    186 __ZN3KJS8Bindings18addNativeReferenceEPKNS0_10RootObjectEPNS_8JSObjectE
    187 __ZN3KJS8Bindings21removeNativeReferenceEPNS_8JSObjectE
    188190__ZN3KJS8Bindings23convertObjcValueToValueEPNS_9ExecStateEPvNS0_13ObjcValueTypeE
    189191__ZN3KJS8Bindings23convertValueToObjcValueEPNS_9ExecStateEPNS_7JSValueENS0_13ObjcValueTypeE
    190192__ZN3KJS8Bindings8Instance18didExecuteFunctionEv
    191193__ZN3KJS8Bindings8Instance21setDidExecuteFunctionEPFvPNS_9ExecStateEPNS_8JSObjectEE
    192 __ZN3KJS8Bindings8Instance32createBindingForLanguageInstanceENS1_15BindingLanguageEPvPKNS0_10RootObjectE
     194__ZN3KJS8Bindings8Instance32createBindingForLanguageInstanceENS1_15BindingLanguageEPvN3WTF10PassRefPtrINS0_10RootObjectEEE
    193195__ZN3KJS8Debugger12sourceUnusedEPNS_9ExecStateEi
    194196__ZN3KJS8Debugger6attachEPNS_11InterpreterE
     
    255257__ZNK3KJS7UString6is8BitEv
    256258__ZNK3KJS7UString8toUInt32EPb
     259__ZNK3KJS8Bindings10RootObject11interpreterEv
    257260__ZNK3KJS8JSObject11hasPropertyEPNS_9ExecStateERKNS_10IdentifierE
    258261__ZNK3KJS8JSObject12defaultValueEPNS_9ExecStateENS_6JSTypeE
  • trunk/JavaScriptCore/bindings/NP_jsobject.cpp

    r18461 r19183  
    4949}
    5050
    51 static void jsDeallocate(NPObject* obj)
    52 {
     51static void jsDeallocate(NPObject* npObj)
     52{
     53    JavaScriptObject* obj = (JavaScriptObject*)npObj;
     54
     55    if (obj->rootObject && obj->rootObject->isValid())
     56        obj->rootObject->gcUnprotect(obj->imp);
     57
     58    if (obj->rootObject)
     59        obj->rootObject->deref();
     60
     61    if (obj->originRootObject)
     62        obj->originRootObject->deref();
     63
    5364    free(obj);
    5465}
     
    6273static bool _isSafeScript(JavaScriptObject* obj)
    6374{
    64     if (obj->originRootObject) {
    65         Interpreter* originInterpreter = obj->originRootObject->interpreter();
    66         if (originInterpreter)
    67             return originInterpreter->isSafeScript(obj->rootObject->interpreter());
    68     }
    69     return true;
    70 }
    71 
    72 NPObject* _NPN_CreateScriptObject (NPP npp, JSObject* imp, const RootObject* originRootObject, const RootObject* rootObject)
     75    if (!obj->originRootObject || !obj->rootObject)
     76        return true;
     77   
     78    if (!obj->originRootObject->isValid() || !obj->rootObject->isValid())
     79        return false;
     80       
     81    return obj->originRootObject->interpreter()->isSafeScript(obj->rootObject->interpreter());
     82}
     83
     84NPObject* _NPN_CreateScriptObject(NPP npp, JSObject* imp, PassRefPtr<RootObject> originRootObject, PassRefPtr<RootObject> rootObject)
    7385{
    7486    JavaScriptObject* obj = (JavaScriptObject*)_NPN_CreateObject(npp, NPScriptObjectClass);
    7587
     88    obj->originRootObject = originRootObject.releaseRef();
     89    obj->rootObject = rootObject.releaseRef();
     90
     91    if (obj->rootObject)
     92        obj->rootObject->gcProtect(imp);
    7693    obj->imp = imp;
    77     obj->originRootObject = originRootObject;   
    78     obj->rootObject = rootObject;   
    79 
    80     addNativeReference(rootObject, imp);
    81 
    82     return (NPObject *)obj;
     94
     95    return (NPObject*)obj;
    8396}
    8497
     
    120133
    121134        // Lookup the function object.
    122         ExecState* exec = obj->rootObject->interpreter()->globalExec();
     135        RootObject* rootObject = obj->rootObject;
     136        if (!rootObject || !rootObject->isValid())
     137            return false;
     138
     139        ExecState* exec = rootObject->interpreter()->globalExec();
    123140        JSLock lock;
    124141        JSValue* func = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
     
    157174            return false;
    158175
    159         ExecState* exec = obj->rootObject->interpreter()->globalExec();
     176        RootObject* rootObject = obj->rootObject;
     177        if (!rootObject || !rootObject->isValid())
     178            return false;
     179
     180        ExecState* exec = rootObject->interpreter()->globalExec();
    160181       
    161182        JSLock lock;
     
    163184        unsigned int UTF16Length;
    164185        convertNPStringToUTF16(s, &scriptString, &UTF16Length); // requires free() of returned memory
    165         Completion completion = obj->rootObject->interpreter()->evaluate(UString(), 0, UString((const UChar*)scriptString,UTF16Length));
     186        Completion completion = rootObject->interpreter()->evaluate(UString(), 0, UString((const UChar*)scriptString,UTF16Length));
    166187        ComplType type = completion.complType();
    167188       
     
    192213            return false;
    193214
    194         ExecState* exec = obj->rootObject->interpreter()->globalExec();
     215        RootObject* rootObject = obj->rootObject;
     216        if (!rootObject || !rootObject->isValid())
     217            return false;
     218
     219        ExecState* exec = rootObject->interpreter()->globalExec();
    195220        PrivateIdentifier* i = (PrivateIdentifier*)propertyName;
    196221       
     
    231256            return false;
    232257
    233         ExecState* exec = obj->rootObject->interpreter()->globalExec();
     258        RootObject* rootObject = obj->rootObject;
     259        if (!rootObject || !rootObject->isValid())
     260            return false;
     261
     262        ExecState* exec = rootObject->interpreter()->globalExec();
    234263        JSLock lock;
    235264        PrivateIdentifier* i = (PrivateIdentifier*)propertyName;
     
    254283            return false;
    255284
    256         ExecState* exec = obj->rootObject->interpreter()->globalExec();
     285        RootObject* rootObject = obj->rootObject;
     286        if (!rootObject || !rootObject->isValid())
     287            return false;
     288
     289        ExecState* exec = rootObject->interpreter()->globalExec();
    257290        PrivateIdentifier* i = (PrivateIdentifier*)propertyName;
    258291        if (i->isString) {
     
    282315            return false;
    283316
    284         ExecState* exec = obj->rootObject->interpreter()->globalExec();
     317        RootObject* rootObject = obj->rootObject;
     318        if (!rootObject || !rootObject->isValid())
     319            return false;
     320
     321        ExecState* exec = rootObject->interpreter()->globalExec();
    285322        PrivateIdentifier* i = (PrivateIdentifier*)propertyName;
    286323        JSLock lock;
     
    307344            return false;
    308345
    309         ExecState* exec = obj->rootObject->interpreter()->globalExec();
     346        RootObject* rootObject = obj->rootObject;
     347        if (!rootObject || !rootObject->isValid())
     348            return false;
     349
     350        ExecState* exec = rootObject->interpreter()->globalExec();
    310351        JSLock lock;
    311352        JSValue* func = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
     
    323364    if (o->_class == NPScriptObjectClass) {
    324365        JavaScriptObject* obj = (JavaScriptObject*)o;
    325         ExecState* exec = obj->rootObject->interpreter()->globalExec();
     366        RootObject* rootObject = obj->rootObject;
     367        if (!rootObject || !rootObject->isValid())
     368            return;
     369
     370        ExecState* exec = rootObject->interpreter()->globalExec();
    326371        JSLock lock;
    327372        throwError(exec, GeneralError, message);
  • trunk/JavaScriptCore/bindings/NP_jsobject.h

    r18461 r19183  
    2828
    2929#include "npruntime.h"
     30#include <wtf/Forward.h>
    3031
    3132namespace KJS {
     
    4243    NPObject object;
    4344    KJS::JSObject* imp;
    44     const KJS::Bindings::RootObject* originRootObject;
    45     const KJS::Bindings::RootObject* rootObject;
     45    KJS::Bindings::RootObject* originRootObject;
     46    KJS::Bindings::RootObject* rootObject;
    4647};
    4748
    48 NPObject* _NPN_CreateScriptObject(NPP npp, KJS::JSObject*, const KJS::Bindings::RootObject* originRootObject, const KJS::Bindings::RootObject* rootObject);
     49NPObject* _NPN_CreateScriptObject(NPP npp, KJS::JSObject*, PassRefPtr<KJS::Bindings::RootObject> originRootObject, PassRefPtr<KJS::Bindings::RootObject> rootObject);
    4950NPObject* _NPN_CreateNoScriptObject(void);
    5051
  • trunk/JavaScriptCore/bindings/c/c_instance.cpp

    r18461 r19183  
    3232#include "list.h"
    3333#include "npruntime_impl.h"
     34#include "runtime_root.h"
     35#include <wtf/StringExtras.h>
    3436#include <wtf/Vector.h>
    35 #include <wtf/StringExtras.h>
    3637
    3738namespace KJS {
  • trunk/JavaScriptCore/bindings/c/c_utility.cpp

    r18811 r19183  
    104104    JSType type = value->type();
    105105   
     106    VOID_TO_NPVARIANT(*result);
     107
    106108    if (type == StringType) {
    107109        UString ustring = value->toString(exec);
     
    126128            OBJECT_TO_NPVARIANT(obj, *result);
    127129        } else {
    128             Interpreter *originInterpreter = exec->dynamicInterpreter();
    129             const Bindings::RootObject* originRootObject = findRootObject(originInterpreter);
     130            Interpreter* originInterpreter = exec->dynamicInterpreter();
     131            RootObject* originRootObject = findRootObject(originInterpreter);
    130132
    131             Interpreter *interpreter = 0;
     133            Interpreter* interpreter = 0;
    132134            if (originInterpreter->isGlobalObject(value)) {
    133135                interpreter = originInterpreter->interpreterForGlobalObject(value);
     
    137139                interpreter = originInterpreter;
    138140
    139             const RootObject* rootObject = findRootObject(interpreter);
    140             if (!rootObject) {
    141                 RootObject* newRootObject = new RootObject(0, interpreter);
    142                 rootObject = newRootObject;
     141            RootObject* rootObject = findRootObject(interpreter);
     142            if (rootObject) {
     143                NPObject* npObject = _NPN_CreateScriptObject(0, object, originRootObject, rootObject);
     144                OBJECT_TO_NPVARIANT(npObject, *result);
    143145            }
    144 
    145             NPObject* npObject = _NPN_CreateScriptObject(0, object, originRootObject, rootObject);
    146             OBJECT_TO_NPVARIANT(npObject, *result);
    147146        }
    148147    }
    149     else
    150         VOID_TO_NPVARIANT(*result);
    151148}
    152149
  • trunk/JavaScriptCore/bindings/jni/jni_instance.cpp

    r18461 r19183  
    4040}
    4141#endif
    42 
     42 
    4343using namespace KJS::Bindings;
    4444using namespace KJS;
    4545
    46 JavaInstance::JavaInstance (jobject instance, const RootObject *r)
     46JavaInstance::JavaInstance (jobject instance)
    4747{
    4848    _instance = new JObjectWrapper (instance);
    4949    _class = 0;
    50     setRootObject(r);
    5150}
    5251
     
    139138    }
    140139       
    141 
    142140    jvalue result;
    143141
     
    145143    // nornmal JNI.  The JNI dispatch abstraction allows the Java plugin
    146144    // to dispatch the call on the appropriate internal VM thread.
    147     const RootObject* rootObject = this->rootObject();
     145    RootObject* rootObject = this->rootObject();
     146    if (!rootObject)
     147        return jsUndefined();
     148
    148149    bool handled = false;
    149     if (rootObject && rootObject->nativeHandle()) {
     150    if (rootObject->nativeHandle()) {
    150151        jobject obj = _instance->_instance;
    151152        JSValue *exceptionDescription = NULL;
  • trunk/JavaScriptCore/bindings/jni/jni_instance.h

    r18657 r19183  
    6767{
    6868public:
    69     JavaInstance (jobject instance, const RootObject *r);
    70        
    71     ~JavaInstance ();
     69    JavaInstance(jobject instance);
     70    ~JavaInstance();
    7271   
    7372    virtual Class *getClass() const;
     
    8887       
    8988private:
    90     JavaInstance ();                         // prevent default construction
    9189    JavaInstance (JavaInstance &);           // prevent copying
    9290    JavaInstance &operator=(JavaInstance &); // prevent copying
  • trunk/JavaScriptCore/bindings/jni/jni_jsobject.cpp

    r18811 r19183  
    127127   
    128128                case Finalize: {
    129                     JSObject *imp = jlong_to_impptr(nativeHandle);
    130                     // We may have received a finalize method call from the VM
    131                     // AFTER removing our last reference to the Java instance.
    132                     if (findProtectCountSet(imp))
    133                         JavaJSObject(nativeHandle).finalize();
     129                    JavaJSObject(nativeHandle).finalize();
    134130                    break;
    135131                }
     
    151147    _imp = jlong_to_impptr(nativeJSObject);
    152148   
    153     // If we are unable to cast the nativeJSObject to an JSObject something is
    154     // terribly wrong.
    155     assert (_imp != 0);
    156    
     149    ASSERT(_imp);
    157150    _rootObject = findRootObject(_imp);
    158    
    159     // If we can't find the root for the object something is terribly wrong.
    160     assert (_rootObject != 0);
    161 }
    162 
     151    ASSERT(_rootObject);
     152}
     153
     154RootObject* JavaJSObject::rootObject() const
     155{
     156    return _rootObject && _rootObject->isValid() ? _rootObject.get() : 0;
     157}
    163158
    164159jobject JavaJSObject::call(jstring methodName, jobjectArray args) const
     
    166161    JS_LOG ("methodName = %s\n", JavaString(methodName).UTF8String());
    167162
     163    RootObject* rootObject = this->rootObject();
     164    if (!rootObject)
     165        return 0;
     166   
    168167    // Lookup the function object.
    169     ExecState* exec = _rootObject->interpreter()->globalExec();
     168    ExecState* exec = rootObject->interpreter()->globalExec();
    170169    JSLock lock;
    171170   
    172171    Identifier identifier(JavaString(methodName).ustring());
    173172    JSValue *func = _imp->get (exec, identifier);
    174     if (func->isUndefinedOrNull()) {
    175         // Maybe throw an exception here?
    176         return 0;
    177     }
     173    if (func->isUndefinedOrNull())
     174        return 0;
    178175
    179176    // Call the function object.
     
    195192    JSLock lock;
    196193   
    197     Completion completion = _rootObject->interpreter()->evaluate(UString(), 0, JavaString(script).ustring(),thisObj);
     194    RootObject* rootObject = this->rootObject();
     195    if (!rootObject)
     196        return 0;
     197
     198    Completion completion = rootObject->interpreter()->evaluate(UString(), 0, JavaString(script).ustring(),thisObj);
    198199    ComplType type = completion.complType();
    199200   
     
    212213    JS_LOG ("(%p) memberName = %s\n", _imp, JavaString(memberName).UTF8String());
    213214
    214     ExecState* exec = _rootObject->interpreter()->globalExec();
     215    RootObject* rootObject = this->rootObject();
     216    if (!rootObject)
     217        return 0;
     218
     219    ExecState* exec = rootObject->interpreter()->globalExec();
    215220   
    216221    JSLock lock;
     
    223228{
    224229    JS_LOG ("memberName = %s, value = %p\n", JavaString(memberName).UTF8String(), value);
    225     ExecState* exec = _rootObject->interpreter()->globalExec();
     230
     231    RootObject* rootObject = this->rootObject();
     232    if (!rootObject)
     233        return;
     234
     235    ExecState* exec = rootObject->interpreter()->globalExec();
    226236    JSLock lock;
    227237    _imp->put(exec, Identifier (JavaString(memberName).ustring()), convertJObjectToValue(value));
     
    233243    JS_LOG ("memberName = %s\n", JavaString(memberName).UTF8String());
    234244
    235     ExecState* exec = _rootObject->interpreter()->globalExec();
     245    RootObject* rootObject = this->rootObject();
     246    if (!rootObject)
     247        return;
     248
     249    ExecState* exec = rootObject->interpreter()->globalExec();
    236250    JSLock lock;
    237251    _imp->deleteProperty(exec, Identifier (JavaString(memberName).ustring()));
     
    247261#endif
    248262
    249     ExecState* exec = _rootObject->interpreter()->globalExec();
     263    RootObject* rootObject = this->rootObject();
     264    if (!rootObject)
     265        return 0;
     266
     267    ExecState* exec = rootObject->interpreter()->globalExec();
    250268
    251269    JSLock lock;
     
    264282#endif
    265283
    266     ExecState* exec = _rootObject->interpreter()->globalExec();
     284    RootObject* rootObject = this->rootObject();
     285    if (!rootObject)
     286        return;
     287
     288    ExecState* exec = rootObject->interpreter()->globalExec();
    267289    JSLock lock;
    268290    _imp->put(exec, (unsigned)index, convertJObjectToValue(value));
     
    274296    JS_LOG ("\n");
    275297   
     298    RootObject* rootObject = this->rootObject();
     299    if (!rootObject)
     300        return 0;
     301
    276302    JSLock lock;
    277303    JSObject *thisObj = const_cast<JSObject*>(_imp);
    278     ExecState* exec = _rootObject->interpreter()->globalExec();
     304    ExecState* exec = rootObject->interpreter()->globalExec();
    279305   
    280306    return (jstring)convertValueToJValue (exec, thisObj, object_type, "java.lang.String").l;
     
    283309void JavaJSObject::finalize() const
    284310{
    285     JS_LOG ("\n");
    286 
    287     removeNativeReference (_imp);
     311    if (RootObject* rootObject = this->rootObject())
     312        rootObject->gcUnprotect(_imp);
    288313}
    289314
     
    304329        return ptr_to_jlong(0);
    305330
    306     RootObject* rootObject = createRootObject(jlong_to_ptr(nativeHandle));
     331    RefPtr<RootObject> rootObject = createRootObject(jlong_to_ptr(nativeHandle));
     332
    307333    // If rootObject is !NULL We must have been called via netscape.javascript.JavaJSObject.getWindow(),
    308334    // otherwise we are being called after creating a JavaJSObject in
    309335    // JavaJSObject::convertValueToJObject().
    310     if (rootObject) {
    311         JSObject* globalObject = rootObject->interpreter()->globalObject();
    312         addNativeReference(rootObject, globalObject);
    313         return ptr_to_jlong(globalObject);
    314     }
     336    if (rootObject)
     337        return ptr_to_jlong(rootObject->interpreter()->globalObject());
    315338
    316339    return nativeHandle;
     
    319342jobject JavaJSObject::convertValueToJObject (JSValue *value) const
    320343{
    321     ExecState* exec = _rootObject->interpreter()->globalExec();
     344    RootObject* rootObject = this->rootObject();
     345    if (!rootObject)
     346        return 0;
     347
     348    ExecState* exec = rootObject->interpreter()->globalExec();
    322349    JNIEnv *env = getJNIEnv();
    323350    jobject result = 0;
     
    369396            else {
    370397                nativeHandle = ptr_to_jlong(imp);
    371                
    372                 // Bump our 'meta' reference count for the imp.  We maintain the reference
    373                 // until either finalize is called or the applet shuts down.
    374                 addNativeReference(_rootObject, imp);
     398                rootObject->gcProtect(imp);
    375399            }
    376400        }
     
    430454
    431455    JSLock lock;
    432     RuntimeObjectImp* newImp = new RuntimeObjectImp(new JavaInstance(theObject, _rootObject));
     456    JavaInstance* javaInstance = new JavaInstance(theObject);
     457    javaInstance->setRootObject(rootObject());
     458    RuntimeObjectImp* newImp = new RuntimeObjectImp(javaInstance);
    433459
    434460    return newImp;
  • trunk/JavaScriptCore/bindings/jni/jni_jsobject.h

    r18795 r19183  
    9292    List listFromJArray(jobjectArray) const;
    9393   
     94    RootObject* rootObject() const;
     95   
    9496private:
    95     const RootObject* _rootObject;
    96     JSObject *_imp;
     97    RefPtr<RootObject> _rootObject;
     98    JSObject* _imp;
    9799};
    98100
  • trunk/JavaScriptCore/bindings/jni/jni_runtime.cpp

    r18461 r19183  
    6666    _name = JavaString(env, fieldName);
    6767
    68     _field = new JavaInstance(aField, 0);
    69 }
    70 
    71 JSValue* JavaArray::convertJObjectToArray(ExecState* exec, jobject anObject, const char* type, const RootObject* r)
     68    _field = new JavaInstance(aField);
     69}
     70
     71JSValue* JavaArray::convertJObjectToArray(ExecState* exec, jobject anObject, const char* type, PassRefPtr<RootObject> rootObject)
    7272{
    7373    if (type[0] != '[')
    7474        return jsUndefined();
    7575
    76     return new RuntimeArray(exec, new JavaArray((jobject)anObject, type, r));
     76    return new RuntimeArray(exec, new JavaArray((jobject)anObject, type, rootObject));
    7777}
    7878
     
    9090        if ( mid != NULL )
    9191        {
    92             const RootObject* rootObject = instance->rootObject();
     92            RootObject* rootObject = instance->rootObject();
    9393            if (rootObject && rootObject->nativeHandle()) {
    9494                JSValue *exceptionDescription = NULL;
     
    171171        if ( mid != NULL )
    172172        {
    173             const RootObject* rootObject = instance->rootObject();
     173            RootObject* rootObject = instance->rootObject();
    174174            if (rootObject && rootObject->nativeHandle()) {
    175175                JSValue *exceptionDescription = NULL;
     
    365365
    366366
    367 JavaArray::JavaArray (jobject a, const char *t, const RootObject *r)
    368 {
    369     _array = new JObjectWrapper (a);
     367JavaArray::JavaArray(jobject array, const char* type, PassRefPtr<RootObject> rootObject)
     368{
     369    _array = new JObjectWrapper(array);
    370370    // Java array are fixed length, so we can cache length.
    371371    JNIEnv *env = getJNIEnv();
    372372    _length = env->GetArrayLength((jarray)_array->_instance);
    373     _type = strdup(t);
    374     _rootObject = r;
     373    _type = strdup(type);
     374    _rootObject = rootObject;
    375375}
    376376
     
    380380}
    381381
    382 
    383 JavaArray::JavaArray (const JavaArray &other) : Array()
    384 {
    385     _array = other._array;
    386     _type = strdup(other._type);
     382RootObject* JavaArray::rootObject() const
     383{
     384    return _rootObject && _rootObject->isValid() ? _rootObject.get() : 0;
    387385}
    388386
  • trunk/JavaScriptCore/bindings/jni/jni_runtime.h

    r18461 r19183  
    267267{
    268268public:
    269     JavaArray (jobject a, const char *type, const RootObject *r);
    270 
    271     JavaArray (const JavaArray &other);
    272 
    273     JavaArray &operator=(const JavaArray &other){
    274         if (this == &other)
    275             return *this;
    276        
    277         free ((void *)_type);
    278         _type = strdup(other._type);
    279         _rootObject = other._rootObject;
    280         _array = other._array;
    281        
    282         return *this;
    283     };
     269    JavaArray(jobject array, const char* type, PassRefPtr<RootObject>);
     270    virtual ~JavaArray();
     271
     272    RootObject* rootObject() const;
    284273
    285274    virtual void setValueAt(ExecState *exec, unsigned int index, JSValue *aValue) const;
     
    287276    virtual unsigned int getLength() const;
    288277   
    289     virtual ~JavaArray();
    290 
    291278    jobject javaArray() const { return _array->_instance; }
    292279
    293     static JSValue *convertJObjectToArray (ExecState *exec, jobject anObject, const char *type, const RootObject *r);
    294 
    295     const RootObject* rootObject() const { return _rootObject; }
    296    
    297 private:
     280    static JSValue* convertJObjectToArray (ExecState* exec, jobject anObject, const char* type, PassRefPtr<RootObject>);
     281
     282private:
     283    JavaArray(const JavaArray&);
     284    JavaArray& operator=(const JavaArray&);
     285
    298286    RefPtr<JObjectWrapper> _array;
    299287    unsigned int _length;
    300288    const char *_type;
    301     const RootObject *_rootObject;
     289    RefPtr<RootObject> _rootObject;
    302290};
    303291
  • trunk/JavaScriptCore/bindings/objc/WebScriptObject.h

    r18461 r19183  
    2929#include "runtime_root.h"
    3030
     31@class WebUndefined;
     32
    3133@protocol WebScriptObject
    3234+ (NSString *)webScriptNameForSelector:(SEL)aSelector;
     
    3537+ (BOOL)isKeyExcludedFromWebScript:(const char *)name;
    3638
    37 + (id)_convertValueToObjcValue:(KJS::JSValue *)value originRootObject:(const KJS::Bindings::RootObject*)originRootObject rootObject:(const KJS::Bindings::RootObject *)rootObject;
    38 - _initWithJSObject:(KJS::JSObject *)imp originRootObject:(const KJS::Bindings::RootObject*)originRootObject rootObject:(const KJS::Bindings::RootObject*)rootObject;
     39+ (id)_convertValueToObjcValue:(KJS::JSValue *)value originRootObject:(KJS::Bindings::RootObject*)originRootObject rootObject:(KJS::Bindings::RootObject*)rootObject;
     40- _initWithJSObject:(KJS::JSObject*)imp originRootObject:(PassRefPtr<KJS::Bindings::RootObject>)originRootObject rootObject:(PassRefPtr<KJS::Bindings::RootObject>)rootObject;
    3941- (KJS::JSObject *)_imp;
    4042@end
     43
     44@protocol WebUndefined
     45+ (WebUndefined *)undefined;
     46@end
  • trunk/JavaScriptCore/bindings/objc/objc_runtime.mm

    r18811 r19183  
    4343extern ClassStructPtr KJS::Bindings::webUndefinedClass()
    4444{
    45     static ClassStructPtr<WebScriptObject> webUndefinedClass = NSClassFromString(@"WebUndefined");
     45    static ClassStructPtr<WebUndefined> webUndefinedClass = NSClassFromString(@"WebUndefined");
    4646    return webUndefinedClass;
    4747}
     
    142142static id convertValueToObjcObject(ExecState* exec, JSValue* value)
    143143{
    144     const RootObject* rootObject = findRootObject(exec->dynamicInterpreter());
    145     if (!rootObject) {
    146         RootObject* newRootObject = new RootObject(0, exec->dynamicInterpreter());
    147         rootObject = newRootObject;
    148     }
    149     return [webScriptObjectClass() _convertValueToObjcValue:value originRootObject:rootObject rootObject:rootObject ];
     144    RefPtr<RootObject> rootObject = findRootObject(exec->dynamicInterpreter());
     145    if (!rootObject)
     146        return nil;
     147    return [webScriptObjectClass() _convertValueToObjcValue:value originRootObject:rootObject.get() rootObject:rootObject.get()];
    150148}
    151149
  • trunk/JavaScriptCore/bindings/objc/objc_utility.mm

    r18811 r19183  
    137137        case ObjcObjectType: {
    138138            Interpreter *originInterpreter = exec->dynamicInterpreter();
    139             const RootObject* originRootObject = findRootObject(originInterpreter);
     139            RootObject* originRootObject = findRootObject(originInterpreter);
    140140
    141141            Interpreter *interpreter = 0;
     
    146146                interpreter = originInterpreter;
    147147               
    148             const RootObject* rootObject = findRootObject(interpreter);
    149             if (!rootObject) {
    150                 RootObject* newRootObject = new RootObject(0, interpreter);
    151                 rootObject = newRootObject;
    152             }
    153 
    154             result.objectValue = [webScriptObjectClass() _convertValueToObjcValue:value originRootObject:originRootObject rootObject:rootObject];
     148            RootObject* rootObject = findRootObject(interpreter);
     149            result.objectValue =  rootObject
     150                ? [webScriptObjectClass() _convertValueToObjcValue:value originRootObject:originRootObject rootObject:rootObject]
     151                : nil;
    155152        }
    156153        break;
  • trunk/JavaScriptCore/bindings/runtime.cpp

    r18657 r19183  
    3030#include "NP_jsobject.h"
    3131#include "c_instance.h"
     32#include "runtime_object.h"
     33#include "runtime_root.h"
     34
    3235#if HAVE(JNI)
    3336#include "jni_instance.h"
     
    3942#include "qt_instance.h"
    4043#endif
    41 #include "runtime_object.h"
    4244
    4345namespace KJS { namespace Bindings {
     
    9597
    9698Instance::Instance()
    97     : _rootObject(0)
    98     , _refCount(0)
     99    : _refCount(0)
     100{
     101}
     102
     103Instance::~Instance()
    99104{
    100105}
     
    115120}
    116121
    117 Instance* Instance::createBindingForLanguageInstance(BindingLanguage language, void* nativeInstance, const RootObject* rootObject)
     122Instance* Instance::createBindingForLanguageInstance(BindingLanguage language, void* nativeInstance, PassRefPtr<RootObject> rootObject)
    118123{
    119124    Instance *newInstance = 0;
     
    122127#if HAVE(JNI)
    123128        case Instance::JavaLanguage: {
    124             newInstance = new Bindings::JavaInstance((jobject)nativeInstance, rootObject);
     129            newInstance = new Bindings::JavaInstance((jobject)nativeInstance);
    125130            break;
    126131        }
     
    152157}
    153158
    154 JSObject* Instance::createRuntimeObject(BindingLanguage language, void* nativeInstance, const RootObject* rootObject)
     159JSObject* Instance::createRuntimeObject(BindingLanguage language, void* nativeInstance, PassRefPtr<RootObject> rootObject)
    155160{
    156     Instance* interfaceObject = Instance::createBindingForLanguageInstance(language, nativeInstance, rootObject);
     161    Instance* instance = Instance::createBindingForLanguageInstance(language, nativeInstance, rootObject);
    157162   
    158163    JSLock lock;
    159     return new RuntimeObjectImp(interfaceObject);
     164    return new RuntimeObjectImp(instance);
     165}
     166
     167void Instance::setRootObject(PassRefPtr<RootObject> rootObject)
     168{
     169    _rootObject = rootObject;
     170}
     171
     172RootObject* Instance::rootObject() const
     173{
     174    return _rootObject && _rootObject->isValid() ? _rootObject.get() : 0;
    160175}
    161176
  • trunk/JavaScriptCore/bindings/runtime.h

    r18461 r19183  
    142142    static KJSDidExecuteFunctionPtr didExecuteFunction();
    143143   
    144     static Instance* createBindingForLanguageInstance(BindingLanguage, void* nativeInstance, const RootObject* = 0);
    145     static JSObject* createRuntimeObject(BindingLanguage, void* nativeInstance, const RootObject* = 0);
     144    static Instance* createBindingForLanguageInstance(BindingLanguage, void* nativeInstance, PassRefPtr<RootObject> = 0);
     145    static JSObject* createRuntimeObject(BindingLanguage, void* nativeInstance, PassRefPtr<RootObject> = 0);
    146146
    147147    void ref() { _refCount++; }
     
    175175    virtual JSValue* valueOf() const { return jsString(getClass()->name()); }
    176176   
    177     void setRootObject(const RootObject* r) { _rootObject = r; }
    178     const RootObject* rootObject() const { return _rootObject; }
    179    
    180     virtual ~Instance() {}
     177    void setRootObject(PassRefPtr<RootObject>);
     178    RootObject* rootObject() const;
     179   
     180    virtual ~Instance();
    181181
    182182protected:
    183     const RootObject* _rootObject;
     183    RefPtr<RootObject> _rootObject;
    184184    unsigned _refCount;
    185185
  • trunk/JavaScriptCore/bindings/runtime_root.cpp

    r18811 r19183  
    2828#include "runtime_root.h"
    2929#include <wtf/HashCountedSet.h>
     30#include <wtf/HashSet.h>
    3031
    3132namespace KJS { namespace Bindings {
    3233
    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
     39typedef HashSet<RootObject*> RootObjectSet;
     40
     41static RootObjectSet* rootObjectSet()
     42{
     43    static RootObjectSet staticRootObjectSet;
     44    return &staticRootObjectSet;
    7045}
    7146
     
    7348// fix them by adding a JSObject to RootObject dictionary.
    7449
    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    
     50RootObject* 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    }
    9057    return 0;
    9158}
    9259
    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    
     60RootObject* 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    }
    10367    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 already
    125     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);
    13468}
    13569
     
    256190    CFRunLoopAddSource(RootObject::_runLoop, RootObject::_performJavaScriptSource, kCFRunLoopDefaultMode);
    257191}
     192
    258193#endif
    259194
    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;
     195PassRefPtr<RootObject> RootObject::create(const void* nativeHandle, PassRefPtr<Interpreter> interpreter)
     196{
     197    return new RootObject(nativeHandle, interpreter);
     198}
     199
     200RootObject::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
     210RootObject::~RootObject()
     211{
     212    if (m_isValid)
     213        invalidate();
     214}
     215
     216void 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
     236void 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
     247void 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
     261bool RootObject::gcIsProtected(JSObject* jsObject)
     262{
     263    ASSERT(m_isValid);
     264    return m_protectCountSet.contains(jsObject);
     265}
     266
     267const void* RootObject::nativeHandle() const
     268{
     269    ASSERT(m_isValid);
     270    return m_nativeHandle;
     271}
     272
     273Interpreter* RootObject::interpreter() const
     274{
     275    ASSERT(m_isValid);
     276    return m_interpreter.get();
    276277}
    277278
  • trunk/JavaScriptCore/bindings/runtime_root.h

    r18811 r19183  
    3939class RootObject;
    4040
    41 typedef RootObject* (*CreateRootObjectFunction)(void* nativeHandle);
     41typedef PassRefPtr<RootObject> (*CreateRootObjectFunction)(void* nativeHandle);
    4242typedef HashCountedSet<JSObject*> ProtectCountSet;
    4343
    44 extern ProtectCountSet* findProtectCountSet(JSObject*);
    45 extern const RootObject* findRootObject(JSObject*);
    46 extern const RootObject* findRootObject(Interpreter*);
    47 extern void addNativeReference(const RootObject*, JSObject*);
    48 extern void removeNativeReference(JSObject*);
     44extern RootObject* findRootObject(JSObject*);
     45extern RootObject* findRootObject(Interpreter*);
    4946
    5047class RootObject
     
    5249friend class JavaJSObject;
    5350public:
    54     RootObject(const void* nativeHandle, PassRefPtr<Interpreter> interpreter)
    55         : m_nativeHandle(nativeHandle)
    56         , m_interpreter(interpreter)
     51    static PassRefPtr<RootObject> create(const void* nativeHandle, PassRefPtr<Interpreter> interpreter);
     52
     53    void ref() { m_refCount++; }
     54    void deref()
    5755    {
     56        if (--m_refCount == 0)
     57            delete this;
    5858    }
     59
     60    bool isValid() { return m_isValid; }
     61    void invalidate();
    5962   
    60     const void *nativeHandle() const { return m_nativeHandle; }
    61     Interpreter *interpreter() const { return m_interpreter.get(); }
     63    void gcProtect(JSObject*);
     64    void gcUnprotect(JSObject*);
     65    bool gcIsProtected(JSObject*);
    6266
    63     void destroy();
     67    const void* nativeHandle() const;
     68    Interpreter* interpreter() const;
    6469
    6570#if PLATFORM(MAC)
     
    7782
    7883private:
     84    RootObject(const void* nativeHandle, PassRefPtr<Interpreter> interpreter);
     85    ~RootObject();
     86   
     87    // Uncopyable
     88    RootObject(const RootObject&);
     89    RootObject& operator=(const RootObject&);
     90   
     91    unsigned m_refCount;
     92    bool m_isValid;
     93   
    7994    const void* m_nativeHandle;
    8095    RefPtr<Interpreter> m_interpreter;
     96    ProtectCountSet m_protectCountSet;
    8197
    8298#if PLATFORM(MAC)
Note: See TracChangeset for help on using the changeset viewer.