зеркало из https://github.com/mozilla/gecko-dev.git
Reference-count XBL JSClass structs, and LRU-cache unreferenced ones up to some quota, to avoid bloat and shutdown crashes due to unavoidable manual delete/last-use misorder (42530, r=hyatt).
This commit is contained in:
Родитель
d70a4ed2b5
Коммит
b864716baa
|
@ -19,7 +19,7 @@
|
||||||
*
|
*
|
||||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s): Brendan Eich (brendan@mozilla.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
@ -118,16 +118,43 @@ NS_IMPL_ISUPPORTS1(nsXBLAttributeEntry, nsIXBLAttributeEntry)
|
||||||
PR_STATIC_CALLBACK(void)
|
PR_STATIC_CALLBACK(void)
|
||||||
XBLFinalize(JSContext *cx, JSObject *obj)
|
XBLFinalize(JSContext *cx, JSObject *obj)
|
||||||
{
|
{
|
||||||
nsJSUtils::nsGenericFinalize(cx, obj);
|
nsXBLJSClass* c = NS_STATIC_CAST(nsXBLJSClass*, ::JS_GetClass(cx, obj));
|
||||||
|
c->Drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
nsXBLJSClass::nsXBLJSClass(const nsCString& aClassName)
|
||||||
// XULElement constructor
|
|
||||||
//
|
|
||||||
PR_STATIC_CALLBACK(JSBool)
|
|
||||||
XBLBindingCtor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
||||||
{
|
{
|
||||||
return JS_FALSE;
|
memset(this, 0, sizeof(nsXBLJSClass));
|
||||||
|
next = prev = NS_STATIC_CAST(JSCList*, this);
|
||||||
|
name = nsXPIDLCString::Copy(aClassName);
|
||||||
|
addProperty = delProperty = setProperty = getProperty = ::JS_PropertyStub;
|
||||||
|
enumerate = ::JS_EnumerateStub;
|
||||||
|
resolve = ::JS_ResolveStub;
|
||||||
|
convert = ::JS_ConvertStub;
|
||||||
|
finalize = XBLFinalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsrefcnt
|
||||||
|
nsXBLJSClass::Destroy()
|
||||||
|
{
|
||||||
|
NS_ASSERTION(next == prev && prev == NS_STATIC_CAST(JSCList*, this),
|
||||||
|
"referenced nsXBLJSClass is on LRU list already!?");
|
||||||
|
|
||||||
|
if (nsXBLService::gClassLRUListLength >= nsXBLService::gClassLRUListQuota) {
|
||||||
|
// Over LRU list quota, just unhash and delete this class.
|
||||||
|
if (nsXBLService::gClassTable) {
|
||||||
|
nsStringKey key(name);
|
||||||
|
(nsXBLService::gClassTable)->Remove(&key);
|
||||||
|
}
|
||||||
|
delete this;
|
||||||
|
} else {
|
||||||
|
// Put this most-recently-used class on end of the LRU-sorted freelist.
|
||||||
|
JSCList* mru = NS_STATIC_CAST(JSCList*, this);
|
||||||
|
JS_APPEND_LINK(mru, &nsXBLService::gClassLRUList);
|
||||||
|
nsXBLService::gClassLRUListLength++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static initialization
|
// Static initialization
|
||||||
|
@ -216,10 +243,10 @@ NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding)
|
||||||
|
|
||||||
// Constructors/Destructors
|
// Constructors/Destructors
|
||||||
nsXBLBinding::nsXBLBinding(void)
|
nsXBLBinding::nsXBLBinding(void)
|
||||||
: mAttributeTable(nsnull),
|
: mFirstHandler(nsnull),
|
||||||
mInsertionPointTable(nsnull),
|
|
||||||
mIsStyleBinding(PR_TRUE),
|
mIsStyleBinding(PR_TRUE),
|
||||||
mFirstHandler(nsnull)
|
mAttributeTable(nsnull),
|
||||||
|
mInsertionPointTable(nsnull)
|
||||||
{
|
{
|
||||||
NS_INIT_REFCNT();
|
NS_INIT_REFCNT();
|
||||||
gRefCnt++;
|
gRefCnt++;
|
||||||
|
@ -955,7 +982,7 @@ nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool
|
||||||
if (!aRemoveFlag) {
|
if (!aRemoveFlag) {
|
||||||
// Construct a new text node and insert it.
|
// Construct a new text node and insert it.
|
||||||
nsAutoString value;
|
nsAutoString value;
|
||||||
nsresult result = mBoundElement->GetAttribute(aNameSpaceID, aAttribute, value);
|
mBoundElement->GetAttribute(aNameSpaceID, aAttribute, value);
|
||||||
if (!value.IsEmpty()) {
|
if (!value.IsEmpty()) {
|
||||||
nsCOMPtr<nsIDOMText> textNode;
|
nsCOMPtr<nsIDOMText> textNode;
|
||||||
nsCOMPtr<nsIDocument> doc;
|
nsCOMPtr<nsIDocument> doc;
|
||||||
|
@ -1018,9 +1045,9 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
|
||||||
// XXX Sanity check to make sure our class name matches
|
// XXX Sanity check to make sure our class name matches
|
||||||
// Pull ourselves out of the proto chain.
|
// Pull ourselves out of the proto chain.
|
||||||
JSContext* jscontext = (JSContext*)context->GetNativeContext();
|
JSContext* jscontext = (JSContext*)context->GetNativeContext();
|
||||||
JSObject* ourProto = JS_GetPrototype(jscontext, scriptObject);
|
JSObject* ourProto = ::JS_GetPrototype(jscontext, scriptObject);
|
||||||
JSObject* grandProto = JS_GetPrototype(jscontext, ourProto);
|
JSObject* grandProto = ::JS_GetPrototype(jscontext, ourProto);
|
||||||
JS_SetPrototype(jscontext, scriptObject, grandProto);
|
::JS_SetPrototype(jscontext, scriptObject, grandProto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1065,69 +1092,84 @@ nsXBLBinding::InitClass(const nsCString& aClassName, nsIScriptContext* aContext,
|
||||||
|
|
||||||
// First ensure our JS class is initialized.
|
// First ensure our JS class is initialized.
|
||||||
JSContext* jscontext = (JSContext*)aContext->GetNativeContext();
|
JSContext* jscontext = (JSContext*)aContext->GetNativeContext();
|
||||||
JSObject* proto = nsnull;
|
JSObject* global = ::JS_GetGlobalObject(jscontext);
|
||||||
JSObject* constructor = nsnull;
|
|
||||||
JSObject* parent_proto = nsnull;
|
|
||||||
JSObject* global = JS_GetGlobalObject(jscontext);
|
|
||||||
jsval vp;
|
jsval vp;
|
||||||
|
JSObject* proto;
|
||||||
|
|
||||||
if ((PR_TRUE != JS_LookupProperty(jscontext, global, aClassName, &vp)) ||
|
if ((! ::JS_LookupProperty(jscontext, global, aClassName, &vp)) ||
|
||||||
!JSVAL_IS_OBJECT(vp) ||
|
JSVAL_IS_PRIMITIVE(vp)) {
|
||||||
((constructor = JSVAL_TO_OBJECT(vp)) == nsnull) ||
|
|
||||||
(PR_TRUE != JS_LookupProperty(jscontext, JSVAL_TO_OBJECT(vp), "prototype", &vp)) ||
|
|
||||||
!JSVAL_IS_OBJECT(vp)) {
|
|
||||||
// We need to initialize the class.
|
// We need to initialize the class.
|
||||||
|
|
||||||
JSClass* c;
|
nsXBLJSClass* c;
|
||||||
void* classObject;
|
void* classObject;
|
||||||
nsStringKey key(aClassName);
|
nsStringKey key(aClassName);
|
||||||
classObject = (nsXBLService::gClassTable)->Get(&key);
|
classObject = (nsXBLService::gClassTable)->Get(&key);
|
||||||
|
|
||||||
if (classObject)
|
if (classObject) {
|
||||||
c = (JSClass*)classObject;
|
c = NS_STATIC_CAST(nsXBLJSClass*, classObject);
|
||||||
else {
|
|
||||||
// We need to create a struct for this class.
|
// If c is on the LRU list (i.e., not linked to itself), remove it now!
|
||||||
c = new JSClass;
|
JSCList* link = NS_STATIC_CAST(JSCList*, c);
|
||||||
memset(c, 0, sizeof(JSClass));
|
if (c->next != link) {
|
||||||
c->name = nsXPIDLCString::Copy(aClassName);
|
JS_REMOVE_AND_INIT_LINK(link);
|
||||||
c->flags = JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS;
|
nsXBLService::gClassLRUListLength--;
|
||||||
c->addProperty = c->delProperty = c->setProperty = c->getProperty = JS_PropertyStub;
|
}
|
||||||
c->enumerate = JS_EnumerateStub;
|
} else {
|
||||||
c->resolve = JS_ResolveStub;
|
if (JS_CLIST_IS_EMPTY(&nsXBLService::gClassLRUList)) {
|
||||||
c->convert = JS_ConvertStub;
|
// We need to create a struct for this class.
|
||||||
c->finalize = XBLFinalize;
|
c = new nsXBLJSClass(aClassName);
|
||||||
|
if (!c)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
} else {
|
||||||
|
// Pull the least recently used class struct off the list.
|
||||||
|
JSCList* lru = (nsXBLService::gClassLRUList).next;
|
||||||
|
JS_REMOVE_AND_INIT_LINK(lru);
|
||||||
|
nsXBLService::gClassLRUListLength--;
|
||||||
|
|
||||||
|
// Remove any mapping from the old name to the class struct.
|
||||||
|
c = NS_STATIC_CAST(nsXBLJSClass*, lru);
|
||||||
|
nsStringKey oldKey(c->name);
|
||||||
|
(nsXBLService::gClassTable)->Remove(&oldKey);
|
||||||
|
|
||||||
|
// Change the class name and we're done.
|
||||||
|
nsMemory::Free(c->name);
|
||||||
|
c->name = nsXPIDLCString::Copy(aClassName);
|
||||||
|
}
|
||||||
|
|
||||||
// Add c to our table.
|
// Add c to our table.
|
||||||
(nsXBLService::gClassTable)->Put(&key, (void*)c);
|
(nsXBLService::gClassTable)->Put(&key, (void*)c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the current prototype for the JS object.
|
// Retrieve the current prototype of the JS object.
|
||||||
parent_proto = JS_GetPrototype(jscontext, object);
|
JSObject* parent_proto = ::JS_GetPrototype(jscontext, object);
|
||||||
proto = JS_InitClass(jscontext, // context
|
|
||||||
global, // global object
|
// Make a new object prototyped by parent_proto and parented by global.
|
||||||
parent_proto, // parent proto
|
proto = ::JS_InitClass(jscontext, // context
|
||||||
c, // JSClass
|
global, // global object
|
||||||
XBLBindingCtor, // JSNative ctor
|
parent_proto, // parent proto
|
||||||
0, // ctor args
|
c, // JSClass
|
||||||
nsnull, // proto props
|
NULL, // JSNative ctor
|
||||||
nsnull, // proto funcs
|
0, // ctor args
|
||||||
nsnull, // ctor props (static)
|
nsnull, // proto props
|
||||||
nsnull); // ctor funcs (static)
|
nsnull, // proto funcs
|
||||||
if (nsnull == proto) {
|
nsnull, // ctor props (static)
|
||||||
return NS_ERROR_FAILURE;
|
nsnull); // ctor funcs (static)
|
||||||
|
if (!proto) {
|
||||||
|
(nsXBLService::gClassTable)->Remove(&key);
|
||||||
|
delete c;
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The prototype holds a strong reference to its class struct.
|
||||||
|
c->Hold();
|
||||||
*aClassObject = (void*)proto;
|
*aClassObject = (void*)proto;
|
||||||
}
|
}
|
||||||
else if ((nsnull != constructor) && JSVAL_IS_OBJECT(vp)) {
|
|
||||||
proto = JSVAL_TO_OBJECT(vp);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
return NS_ERROR_FAILURE;
|
proto = JSVAL_TO_OBJECT(vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the prototype of our object to be the new class.
|
// Set the prototype of our object to be the new class.
|
||||||
JS_SetPrototype(jscontext, object, proto);
|
::JS_SetPrototype(jscontext, object, proto);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
*
|
*
|
||||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s): Brendan Eich (brendan@mozilla.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
@ -674,7 +674,7 @@ nsXBLEventHandler::RemoveEventHandlers()
|
||||||
PRBool mouse = nsXBLBinding::IsMouseHandler(type);
|
PRBool mouse = nsXBLBinding::IsMouseHandler(type);
|
||||||
PRBool key = nsXBLBinding::IsKeyHandler(type);
|
PRBool key = nsXBLBinding::IsKeyHandler(type);
|
||||||
PRBool focus = nsXBLBinding::IsFocusHandler(type);
|
PRBool focus = nsXBLBinding::IsFocusHandler(type);
|
||||||
PRBool xul = nsXBLBinding::IsXULHandler(type);
|
// XXX not used: PRBool xul = nsXBLBinding::IsXULHandler(type);
|
||||||
PRBool scroll = nsXBLBinding::IsScrollHandler(type);
|
PRBool scroll = nsXBLBinding::IsScrollHandler(type);
|
||||||
|
|
||||||
// Remove the event listener.
|
// Remove the event listener.
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
*
|
*
|
||||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s): Brendan Eich (brendan@mozilla.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
@ -122,6 +122,10 @@ nsINameSpaceManager* nsXBLService::gNameSpaceManager = nsnull;
|
||||||
|
|
||||||
nsHashtable* nsXBLService::gClassTable = nsnull;
|
nsHashtable* nsXBLService::gClassTable = nsnull;
|
||||||
|
|
||||||
|
JSCList nsXBLService::gClassLRUList = JS_INIT_STATIC_CLIST(&nsXBLService::gClassLRUList);
|
||||||
|
PRUint32 nsXBLService::gClassLRUListLength = 0;
|
||||||
|
PRUint32 nsXBLService::gClassLRUListQuota = 64;
|
||||||
|
|
||||||
nsIAtom* nsXBLService::kExtendsAtom = nsnull;
|
nsIAtom* nsXBLService::kExtendsAtom = nsnull;
|
||||||
nsIAtom* nsXBLService::kHasChildrenAtom = nsnull;
|
nsIAtom* nsXBLService::kHasChildrenAtom = nsnull;
|
||||||
nsIAtom* nsXBLService::kURIAtom = nsnull;
|
nsIAtom* nsXBLService::kURIAtom = nsnull;
|
||||||
|
@ -175,14 +179,6 @@ nsXBLService::nsXBLService(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PRBool PR_CALLBACK DeleteClasses(nsHashKey* aKey, void* aValue, void* closure)
|
|
||||||
{
|
|
||||||
JSClass* c = (JSClass*)aValue;
|
|
||||||
nsMemory::Free(c->name);
|
|
||||||
delete c;
|
|
||||||
return PR_TRUE; // return PR_TRUE to continue for nsHashtable enumerator
|
|
||||||
}
|
|
||||||
|
|
||||||
nsXBLService::~nsXBLService(void)
|
nsXBLService::~nsXBLService(void)
|
||||||
{
|
{
|
||||||
gRefCnt--;
|
gRefCnt--;
|
||||||
|
@ -197,10 +193,23 @@ nsXBLService::~nsXBLService(void)
|
||||||
NS_RELEASE(kHasChildrenAtom);
|
NS_RELEASE(kHasChildrenAtom);
|
||||||
NS_RELEASE(kURIAtom);
|
NS_RELEASE(kURIAtom);
|
||||||
|
|
||||||
// Walk the hashtable and delete the JSClasses
|
// Walk the LRU list removing and deleting the nsXBLJSClasses.
|
||||||
if (gClassTable)
|
while (!JS_CLIST_IS_EMPTY(&gClassLRUList)) {
|
||||||
gClassTable->Enumerate(DeleteClasses);
|
JSCList* lru = gClassLRUList.next;
|
||||||
|
JS_REMOVE_AND_INIT_LINK(lru);
|
||||||
|
nsXBLJSClass* c = NS_STATIC_CAST(nsXBLJSClass*, lru);
|
||||||
|
delete c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any straggling nsXBLJSClass instances held by unfinalized JS objects
|
||||||
|
// created for bindings will be deleted when those objects are finalized
|
||||||
|
// (and not put on gClassLRUList, because length >= quota).
|
||||||
|
gClassLRUListLength = gClassLRUListQuota = 0;
|
||||||
|
|
||||||
|
// At this point, the only hash table entries should be for referenced
|
||||||
|
// XBL class structs held by unfinalized JS binding objects.
|
||||||
delete gClassTable;
|
delete gClassTable;
|
||||||
|
gClassTable = nsnull;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,13 +19,16 @@
|
||||||
*
|
*
|
||||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s): Brendan Eich (brendan@mozilla.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "nsIXBLService.h"
|
#include "nsIXBLService.h"
|
||||||
|
|
||||||
|
#include "jsapi.h" // nsXBLJSClass derives from JSClass
|
||||||
|
#include "jsclist.h" // nsXBLJSClass derives from JSCList
|
||||||
|
|
||||||
class nsIXBLBinding;
|
class nsIXBLBinding;
|
||||||
class nsINameSpaceManager;
|
class nsINameSpaceManager;
|
||||||
class nsIContent;
|
class nsIContent;
|
||||||
|
@ -36,7 +39,7 @@ class nsIURI;
|
||||||
class nsSupportsHashtable;
|
class nsSupportsHashtable;
|
||||||
class nsHashtable;
|
class nsHashtable;
|
||||||
|
|
||||||
class nsXBLService: public nsIXBLService
|
class nsXBLService : public nsIXBLService
|
||||||
{
|
{
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
|
@ -52,10 +55,10 @@ class nsXBLService: public nsIXBLService
|
||||||
|
|
||||||
// For a given element, returns a flat list of all the anonymous children that need
|
// For a given element, returns a flat list of all the anonymous children that need
|
||||||
// frames built.
|
// frames built.
|
||||||
NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement,
|
NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement,
|
||||||
PRBool* aMultipleInsertionPoints);
|
PRBool* aMultipleInsertionPoints);
|
||||||
|
|
||||||
// Gets the object's base class type.
|
// Gets the object's base class type.
|
||||||
NS_IMETHOD ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID, nsIAtom** aResult);
|
NS_IMETHOD ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID, nsIAtom** aResult);
|
||||||
|
|
||||||
NS_IMETHOD AllowScripts(nsIContent* aContent, PRBool* aAllowScripts);
|
NS_IMETHOD AllowScripts(nsIContent* aContent, PRBool* aAllowScripts);
|
||||||
|
@ -78,8 +81,8 @@ public:
|
||||||
NS_IMETHOD StripWhitespaceNodes(nsIContent* aContent);
|
NS_IMETHOD StripWhitespaceNodes(nsIContent* aContent);
|
||||||
|
|
||||||
// MEMBER VARIABLES
|
// MEMBER VARIABLES
|
||||||
public:
|
public:
|
||||||
static nsSupportsHashtable* mBindingTable; // This is a table of all the bindings files
|
static nsSupportsHashtable* mBindingTable; // This is a table of all the bindings files
|
||||||
// we have loaded
|
// we have loaded
|
||||||
// during this session.
|
// during this session.
|
||||||
static nsSupportsHashtable* mScriptAccessTable; // Can the doc's bindings access scripts
|
static nsSupportsHashtable* mScriptAccessTable; // Can the doc's bindings access scripts
|
||||||
|
@ -89,12 +92,30 @@ public:
|
||||||
static PRUint32 gRefCnt; // A count of XBLservice instances.
|
static PRUint32 gRefCnt; // A count of XBLservice instances.
|
||||||
|
|
||||||
static PRBool gDisableChromeCache;
|
static PRBool gDisableChromeCache;
|
||||||
|
|
||||||
static nsHashtable* gClassTable; // A table of JSClass objects.
|
static nsHashtable* gClassTable; // A table of nsXBLJSClass objects.
|
||||||
|
|
||||||
|
static JSCList gClassLRUList; // LRU list of cached classes.
|
||||||
|
static PRUint32 gClassLRUListLength; // Number of classes on LRU list.
|
||||||
|
static PRUint32 gClassLRUListQuota; // Quota on class LRU list.
|
||||||
|
|
||||||
// XBL Atoms
|
// XBL Atoms
|
||||||
static nsIAtom* kExtendsAtom;
|
static nsIAtom* kExtendsAtom;
|
||||||
static nsIAtom* kHasChildrenAtom;
|
static nsIAtom* kHasChildrenAtom;
|
||||||
static nsIAtom* kURIAtom;
|
static nsIAtom* kURIAtom;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class nsXBLJSClass : public JSCList, public JSClass
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
nsrefcnt mRefCnt;
|
||||||
|
nsrefcnt Destroy();
|
||||||
|
|
||||||
|
public:
|
||||||
|
nsXBLJSClass(const nsCString& aClassName);
|
||||||
|
~nsXBLJSClass() { nsMemory::Free(name); }
|
||||||
|
|
||||||
|
nsrefcnt Hold() { return ++mRefCnt; }
|
||||||
|
nsrefcnt Drop() { return --mRefCnt ? mRefCnt : Destroy(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
*
|
*
|
||||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s): Brendan Eich (brendan@mozilla.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
@ -118,16 +118,43 @@ NS_IMPL_ISUPPORTS1(nsXBLAttributeEntry, nsIXBLAttributeEntry)
|
||||||
PR_STATIC_CALLBACK(void)
|
PR_STATIC_CALLBACK(void)
|
||||||
XBLFinalize(JSContext *cx, JSObject *obj)
|
XBLFinalize(JSContext *cx, JSObject *obj)
|
||||||
{
|
{
|
||||||
nsJSUtils::nsGenericFinalize(cx, obj);
|
nsXBLJSClass* c = NS_STATIC_CAST(nsXBLJSClass*, ::JS_GetClass(cx, obj));
|
||||||
|
c->Drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
nsXBLJSClass::nsXBLJSClass(const nsCString& aClassName)
|
||||||
// XULElement constructor
|
|
||||||
//
|
|
||||||
PR_STATIC_CALLBACK(JSBool)
|
|
||||||
XBLBindingCtor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
||||||
{
|
{
|
||||||
return JS_FALSE;
|
memset(this, 0, sizeof(nsXBLJSClass));
|
||||||
|
next = prev = NS_STATIC_CAST(JSCList*, this);
|
||||||
|
name = nsXPIDLCString::Copy(aClassName);
|
||||||
|
addProperty = delProperty = setProperty = getProperty = ::JS_PropertyStub;
|
||||||
|
enumerate = ::JS_EnumerateStub;
|
||||||
|
resolve = ::JS_ResolveStub;
|
||||||
|
convert = ::JS_ConvertStub;
|
||||||
|
finalize = XBLFinalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsrefcnt
|
||||||
|
nsXBLJSClass::Destroy()
|
||||||
|
{
|
||||||
|
NS_ASSERTION(next == prev && prev == NS_STATIC_CAST(JSCList*, this),
|
||||||
|
"referenced nsXBLJSClass is on LRU list already!?");
|
||||||
|
|
||||||
|
if (nsXBLService::gClassLRUListLength >= nsXBLService::gClassLRUListQuota) {
|
||||||
|
// Over LRU list quota, just unhash and delete this class.
|
||||||
|
if (nsXBLService::gClassTable) {
|
||||||
|
nsStringKey key(name);
|
||||||
|
(nsXBLService::gClassTable)->Remove(&key);
|
||||||
|
}
|
||||||
|
delete this;
|
||||||
|
} else {
|
||||||
|
// Put this most-recently-used class on end of the LRU-sorted freelist.
|
||||||
|
JSCList* mru = NS_STATIC_CAST(JSCList*, this);
|
||||||
|
JS_APPEND_LINK(mru, &nsXBLService::gClassLRUList);
|
||||||
|
nsXBLService::gClassLRUListLength++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static initialization
|
// Static initialization
|
||||||
|
@ -216,10 +243,10 @@ NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding)
|
||||||
|
|
||||||
// Constructors/Destructors
|
// Constructors/Destructors
|
||||||
nsXBLBinding::nsXBLBinding(void)
|
nsXBLBinding::nsXBLBinding(void)
|
||||||
: mAttributeTable(nsnull),
|
: mFirstHandler(nsnull),
|
||||||
mInsertionPointTable(nsnull),
|
|
||||||
mIsStyleBinding(PR_TRUE),
|
mIsStyleBinding(PR_TRUE),
|
||||||
mFirstHandler(nsnull)
|
mAttributeTable(nsnull),
|
||||||
|
mInsertionPointTable(nsnull)
|
||||||
{
|
{
|
||||||
NS_INIT_REFCNT();
|
NS_INIT_REFCNT();
|
||||||
gRefCnt++;
|
gRefCnt++;
|
||||||
|
@ -955,7 +982,7 @@ nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool
|
||||||
if (!aRemoveFlag) {
|
if (!aRemoveFlag) {
|
||||||
// Construct a new text node and insert it.
|
// Construct a new text node and insert it.
|
||||||
nsAutoString value;
|
nsAutoString value;
|
||||||
nsresult result = mBoundElement->GetAttribute(aNameSpaceID, aAttribute, value);
|
mBoundElement->GetAttribute(aNameSpaceID, aAttribute, value);
|
||||||
if (!value.IsEmpty()) {
|
if (!value.IsEmpty()) {
|
||||||
nsCOMPtr<nsIDOMText> textNode;
|
nsCOMPtr<nsIDOMText> textNode;
|
||||||
nsCOMPtr<nsIDocument> doc;
|
nsCOMPtr<nsIDocument> doc;
|
||||||
|
@ -1018,9 +1045,9 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
|
||||||
// XXX Sanity check to make sure our class name matches
|
// XXX Sanity check to make sure our class name matches
|
||||||
// Pull ourselves out of the proto chain.
|
// Pull ourselves out of the proto chain.
|
||||||
JSContext* jscontext = (JSContext*)context->GetNativeContext();
|
JSContext* jscontext = (JSContext*)context->GetNativeContext();
|
||||||
JSObject* ourProto = JS_GetPrototype(jscontext, scriptObject);
|
JSObject* ourProto = ::JS_GetPrototype(jscontext, scriptObject);
|
||||||
JSObject* grandProto = JS_GetPrototype(jscontext, ourProto);
|
JSObject* grandProto = ::JS_GetPrototype(jscontext, ourProto);
|
||||||
JS_SetPrototype(jscontext, scriptObject, grandProto);
|
::JS_SetPrototype(jscontext, scriptObject, grandProto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1065,69 +1092,84 @@ nsXBLBinding::InitClass(const nsCString& aClassName, nsIScriptContext* aContext,
|
||||||
|
|
||||||
// First ensure our JS class is initialized.
|
// First ensure our JS class is initialized.
|
||||||
JSContext* jscontext = (JSContext*)aContext->GetNativeContext();
|
JSContext* jscontext = (JSContext*)aContext->GetNativeContext();
|
||||||
JSObject* proto = nsnull;
|
JSObject* global = ::JS_GetGlobalObject(jscontext);
|
||||||
JSObject* constructor = nsnull;
|
|
||||||
JSObject* parent_proto = nsnull;
|
|
||||||
JSObject* global = JS_GetGlobalObject(jscontext);
|
|
||||||
jsval vp;
|
jsval vp;
|
||||||
|
JSObject* proto;
|
||||||
|
|
||||||
if ((PR_TRUE != JS_LookupProperty(jscontext, global, aClassName, &vp)) ||
|
if ((! ::JS_LookupProperty(jscontext, global, aClassName, &vp)) ||
|
||||||
!JSVAL_IS_OBJECT(vp) ||
|
JSVAL_IS_PRIMITIVE(vp)) {
|
||||||
((constructor = JSVAL_TO_OBJECT(vp)) == nsnull) ||
|
|
||||||
(PR_TRUE != JS_LookupProperty(jscontext, JSVAL_TO_OBJECT(vp), "prototype", &vp)) ||
|
|
||||||
!JSVAL_IS_OBJECT(vp)) {
|
|
||||||
// We need to initialize the class.
|
// We need to initialize the class.
|
||||||
|
|
||||||
JSClass* c;
|
nsXBLJSClass* c;
|
||||||
void* classObject;
|
void* classObject;
|
||||||
nsStringKey key(aClassName);
|
nsStringKey key(aClassName);
|
||||||
classObject = (nsXBLService::gClassTable)->Get(&key);
|
classObject = (nsXBLService::gClassTable)->Get(&key);
|
||||||
|
|
||||||
if (classObject)
|
if (classObject) {
|
||||||
c = (JSClass*)classObject;
|
c = NS_STATIC_CAST(nsXBLJSClass*, classObject);
|
||||||
else {
|
|
||||||
// We need to create a struct for this class.
|
// If c is on the LRU list (i.e., not linked to itself), remove it now!
|
||||||
c = new JSClass;
|
JSCList* link = NS_STATIC_CAST(JSCList*, c);
|
||||||
memset(c, 0, sizeof(JSClass));
|
if (c->next != link) {
|
||||||
c->name = nsXPIDLCString::Copy(aClassName);
|
JS_REMOVE_AND_INIT_LINK(link);
|
||||||
c->flags = JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS;
|
nsXBLService::gClassLRUListLength--;
|
||||||
c->addProperty = c->delProperty = c->setProperty = c->getProperty = JS_PropertyStub;
|
}
|
||||||
c->enumerate = JS_EnumerateStub;
|
} else {
|
||||||
c->resolve = JS_ResolveStub;
|
if (JS_CLIST_IS_EMPTY(&nsXBLService::gClassLRUList)) {
|
||||||
c->convert = JS_ConvertStub;
|
// We need to create a struct for this class.
|
||||||
c->finalize = XBLFinalize;
|
c = new nsXBLJSClass(aClassName);
|
||||||
|
if (!c)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
} else {
|
||||||
|
// Pull the least recently used class struct off the list.
|
||||||
|
JSCList* lru = (nsXBLService::gClassLRUList).next;
|
||||||
|
JS_REMOVE_AND_INIT_LINK(lru);
|
||||||
|
nsXBLService::gClassLRUListLength--;
|
||||||
|
|
||||||
|
// Remove any mapping from the old name to the class struct.
|
||||||
|
c = NS_STATIC_CAST(nsXBLJSClass*, lru);
|
||||||
|
nsStringKey oldKey(c->name);
|
||||||
|
(nsXBLService::gClassTable)->Remove(&oldKey);
|
||||||
|
|
||||||
|
// Change the class name and we're done.
|
||||||
|
nsMemory::Free(c->name);
|
||||||
|
c->name = nsXPIDLCString::Copy(aClassName);
|
||||||
|
}
|
||||||
|
|
||||||
// Add c to our table.
|
// Add c to our table.
|
||||||
(nsXBLService::gClassTable)->Put(&key, (void*)c);
|
(nsXBLService::gClassTable)->Put(&key, (void*)c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the current prototype for the JS object.
|
// Retrieve the current prototype of the JS object.
|
||||||
parent_proto = JS_GetPrototype(jscontext, object);
|
JSObject* parent_proto = ::JS_GetPrototype(jscontext, object);
|
||||||
proto = JS_InitClass(jscontext, // context
|
|
||||||
global, // global object
|
// Make a new object prototyped by parent_proto and parented by global.
|
||||||
parent_proto, // parent proto
|
proto = ::JS_InitClass(jscontext, // context
|
||||||
c, // JSClass
|
global, // global object
|
||||||
XBLBindingCtor, // JSNative ctor
|
parent_proto, // parent proto
|
||||||
0, // ctor args
|
c, // JSClass
|
||||||
nsnull, // proto props
|
NULL, // JSNative ctor
|
||||||
nsnull, // proto funcs
|
0, // ctor args
|
||||||
nsnull, // ctor props (static)
|
nsnull, // proto props
|
||||||
nsnull); // ctor funcs (static)
|
nsnull, // proto funcs
|
||||||
if (nsnull == proto) {
|
nsnull, // ctor props (static)
|
||||||
return NS_ERROR_FAILURE;
|
nsnull); // ctor funcs (static)
|
||||||
|
if (!proto) {
|
||||||
|
(nsXBLService::gClassTable)->Remove(&key);
|
||||||
|
delete c;
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The prototype holds a strong reference to its class struct.
|
||||||
|
c->Hold();
|
||||||
*aClassObject = (void*)proto;
|
*aClassObject = (void*)proto;
|
||||||
}
|
}
|
||||||
else if ((nsnull != constructor) && JSVAL_IS_OBJECT(vp)) {
|
|
||||||
proto = JSVAL_TO_OBJECT(vp);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
return NS_ERROR_FAILURE;
|
proto = JSVAL_TO_OBJECT(vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the prototype of our object to be the new class.
|
// Set the prototype of our object to be the new class.
|
||||||
JS_SetPrototype(jscontext, object, proto);
|
::JS_SetPrototype(jscontext, object, proto);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
*
|
*
|
||||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s): Brendan Eich (brendan@mozilla.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
@ -674,7 +674,7 @@ nsXBLEventHandler::RemoveEventHandlers()
|
||||||
PRBool mouse = nsXBLBinding::IsMouseHandler(type);
|
PRBool mouse = nsXBLBinding::IsMouseHandler(type);
|
||||||
PRBool key = nsXBLBinding::IsKeyHandler(type);
|
PRBool key = nsXBLBinding::IsKeyHandler(type);
|
||||||
PRBool focus = nsXBLBinding::IsFocusHandler(type);
|
PRBool focus = nsXBLBinding::IsFocusHandler(type);
|
||||||
PRBool xul = nsXBLBinding::IsXULHandler(type);
|
// XXX not used: PRBool xul = nsXBLBinding::IsXULHandler(type);
|
||||||
PRBool scroll = nsXBLBinding::IsScrollHandler(type);
|
PRBool scroll = nsXBLBinding::IsScrollHandler(type);
|
||||||
|
|
||||||
// Remove the event listener.
|
// Remove the event listener.
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
*
|
*
|
||||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s): Brendan Eich (brendan@mozilla.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
@ -122,6 +122,10 @@ nsINameSpaceManager* nsXBLService::gNameSpaceManager = nsnull;
|
||||||
|
|
||||||
nsHashtable* nsXBLService::gClassTable = nsnull;
|
nsHashtable* nsXBLService::gClassTable = nsnull;
|
||||||
|
|
||||||
|
JSCList nsXBLService::gClassLRUList = JS_INIT_STATIC_CLIST(&nsXBLService::gClassLRUList);
|
||||||
|
PRUint32 nsXBLService::gClassLRUListLength = 0;
|
||||||
|
PRUint32 nsXBLService::gClassLRUListQuota = 64;
|
||||||
|
|
||||||
nsIAtom* nsXBLService::kExtendsAtom = nsnull;
|
nsIAtom* nsXBLService::kExtendsAtom = nsnull;
|
||||||
nsIAtom* nsXBLService::kHasChildrenAtom = nsnull;
|
nsIAtom* nsXBLService::kHasChildrenAtom = nsnull;
|
||||||
nsIAtom* nsXBLService::kURIAtom = nsnull;
|
nsIAtom* nsXBLService::kURIAtom = nsnull;
|
||||||
|
@ -175,14 +179,6 @@ nsXBLService::nsXBLService(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PRBool PR_CALLBACK DeleteClasses(nsHashKey* aKey, void* aValue, void* closure)
|
|
||||||
{
|
|
||||||
JSClass* c = (JSClass*)aValue;
|
|
||||||
nsMemory::Free(c->name);
|
|
||||||
delete c;
|
|
||||||
return PR_TRUE; // return PR_TRUE to continue for nsHashtable enumerator
|
|
||||||
}
|
|
||||||
|
|
||||||
nsXBLService::~nsXBLService(void)
|
nsXBLService::~nsXBLService(void)
|
||||||
{
|
{
|
||||||
gRefCnt--;
|
gRefCnt--;
|
||||||
|
@ -197,10 +193,23 @@ nsXBLService::~nsXBLService(void)
|
||||||
NS_RELEASE(kHasChildrenAtom);
|
NS_RELEASE(kHasChildrenAtom);
|
||||||
NS_RELEASE(kURIAtom);
|
NS_RELEASE(kURIAtom);
|
||||||
|
|
||||||
// Walk the hashtable and delete the JSClasses
|
// Walk the LRU list removing and deleting the nsXBLJSClasses.
|
||||||
if (gClassTable)
|
while (!JS_CLIST_IS_EMPTY(&gClassLRUList)) {
|
||||||
gClassTable->Enumerate(DeleteClasses);
|
JSCList* lru = gClassLRUList.next;
|
||||||
|
JS_REMOVE_AND_INIT_LINK(lru);
|
||||||
|
nsXBLJSClass* c = NS_STATIC_CAST(nsXBLJSClass*, lru);
|
||||||
|
delete c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any straggling nsXBLJSClass instances held by unfinalized JS objects
|
||||||
|
// created for bindings will be deleted when those objects are finalized
|
||||||
|
// (and not put on gClassLRUList, because length >= quota).
|
||||||
|
gClassLRUListLength = gClassLRUListQuota = 0;
|
||||||
|
|
||||||
|
// At this point, the only hash table entries should be for referenced
|
||||||
|
// XBL class structs held by unfinalized JS binding objects.
|
||||||
delete gClassTable;
|
delete gClassTable;
|
||||||
|
gClassTable = nsnull;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,13 +19,16 @@
|
||||||
*
|
*
|
||||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s): Brendan Eich (brendan@mozilla.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "nsIXBLService.h"
|
#include "nsIXBLService.h"
|
||||||
|
|
||||||
|
#include "jsapi.h" // nsXBLJSClass derives from JSClass
|
||||||
|
#include "jsclist.h" // nsXBLJSClass derives from JSCList
|
||||||
|
|
||||||
class nsIXBLBinding;
|
class nsIXBLBinding;
|
||||||
class nsINameSpaceManager;
|
class nsINameSpaceManager;
|
||||||
class nsIContent;
|
class nsIContent;
|
||||||
|
@ -36,7 +39,7 @@ class nsIURI;
|
||||||
class nsSupportsHashtable;
|
class nsSupportsHashtable;
|
||||||
class nsHashtable;
|
class nsHashtable;
|
||||||
|
|
||||||
class nsXBLService: public nsIXBLService
|
class nsXBLService : public nsIXBLService
|
||||||
{
|
{
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
|
@ -52,10 +55,10 @@ class nsXBLService: public nsIXBLService
|
||||||
|
|
||||||
// For a given element, returns a flat list of all the anonymous children that need
|
// For a given element, returns a flat list of all the anonymous children that need
|
||||||
// frames built.
|
// frames built.
|
||||||
NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement,
|
NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement,
|
||||||
PRBool* aMultipleInsertionPoints);
|
PRBool* aMultipleInsertionPoints);
|
||||||
|
|
||||||
// Gets the object's base class type.
|
// Gets the object's base class type.
|
||||||
NS_IMETHOD ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID, nsIAtom** aResult);
|
NS_IMETHOD ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID, nsIAtom** aResult);
|
||||||
|
|
||||||
NS_IMETHOD AllowScripts(nsIContent* aContent, PRBool* aAllowScripts);
|
NS_IMETHOD AllowScripts(nsIContent* aContent, PRBool* aAllowScripts);
|
||||||
|
@ -78,8 +81,8 @@ public:
|
||||||
NS_IMETHOD StripWhitespaceNodes(nsIContent* aContent);
|
NS_IMETHOD StripWhitespaceNodes(nsIContent* aContent);
|
||||||
|
|
||||||
// MEMBER VARIABLES
|
// MEMBER VARIABLES
|
||||||
public:
|
public:
|
||||||
static nsSupportsHashtable* mBindingTable; // This is a table of all the bindings files
|
static nsSupportsHashtable* mBindingTable; // This is a table of all the bindings files
|
||||||
// we have loaded
|
// we have loaded
|
||||||
// during this session.
|
// during this session.
|
||||||
static nsSupportsHashtable* mScriptAccessTable; // Can the doc's bindings access scripts
|
static nsSupportsHashtable* mScriptAccessTable; // Can the doc's bindings access scripts
|
||||||
|
@ -89,12 +92,30 @@ public:
|
||||||
static PRUint32 gRefCnt; // A count of XBLservice instances.
|
static PRUint32 gRefCnt; // A count of XBLservice instances.
|
||||||
|
|
||||||
static PRBool gDisableChromeCache;
|
static PRBool gDisableChromeCache;
|
||||||
|
|
||||||
static nsHashtable* gClassTable; // A table of JSClass objects.
|
static nsHashtable* gClassTable; // A table of nsXBLJSClass objects.
|
||||||
|
|
||||||
|
static JSCList gClassLRUList; // LRU list of cached classes.
|
||||||
|
static PRUint32 gClassLRUListLength; // Number of classes on LRU list.
|
||||||
|
static PRUint32 gClassLRUListQuota; // Quota on class LRU list.
|
||||||
|
|
||||||
// XBL Atoms
|
// XBL Atoms
|
||||||
static nsIAtom* kExtendsAtom;
|
static nsIAtom* kExtendsAtom;
|
||||||
static nsIAtom* kHasChildrenAtom;
|
static nsIAtom* kHasChildrenAtom;
|
||||||
static nsIAtom* kURIAtom;
|
static nsIAtom* kURIAtom;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class nsXBLJSClass : public JSCList, public JSClass
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
nsrefcnt mRefCnt;
|
||||||
|
nsrefcnt Destroy();
|
||||||
|
|
||||||
|
public:
|
||||||
|
nsXBLJSClass(const nsCString& aClassName);
|
||||||
|
~nsXBLJSClass() { nsMemory::Free(name); }
|
||||||
|
|
||||||
|
nsrefcnt Hold() { return ++mRefCnt; }
|
||||||
|
nsrefcnt Drop() { return --mRefCnt ? mRefCnt : Destroy(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче