Mercurial > JSWeakRef
diff components/src/nsJSWeakRef.cpp @ 0:7180966f48bf
Origination.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Thu, 16 Apr 2009 15:23:22 -0700 |
parents | |
children | 496cd9ab2298 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/components/src/nsJSWeakRef.cpp Thu Apr 16 15:23:22 2009 -0700 @@ -0,0 +1,178 @@ +#include "nsJSWeakRef.h" + +#include "jsapi.h" +#include "nsIXPConnect.h" +#include "nsAXPCNativeCallContext.h" +#include "nsServiceManagerUtils.h" +#include "nsComponentManagerUtils.h" + +class nsJSWeakRefListNode { +public: + nsJSWeakRef *data; + nsJSWeakRefListNode *next; +}; + +class nsJSWeakRefImpl { +public: + JSObject *weakRef; + JSContext *weakCx; + nsJSWeakRefListNode *node; +}; + +static nsJSWeakRefListNode *gList; +static JSGCCallback gOldJSGCCallback; + +void processGarbage() { + nsJSWeakRefListNode *node = gList; + nsJSWeakRefListNode *prevNode = nsnull; + nsJSWeakRefListNode *nextNode = nsnull; + while (node) { + nextNode = node->next; + if (node->data) { + if (JS_IsAboutToBeFinalized(node->data->impl->weakCx, + node->data->impl->weakRef)) { + // Tell the weak reference holder that its target no longer exists. + node->data->impl->weakRef = nsnull; + node->data->impl->weakCx = nsnull; + node->data->impl->node = nsnull; + + // Delete this node. + if (prevNode) + prevNode->next = nextNode; + else + gList = nextNode; + delete node; + } else + // This is our general case; just move on to the next node. + prevNode = node; + } else { + // The weak reference holder went away, so just delete this node. + if (prevNode) + prevNode->next = nextNode; + else + gList = nextNode; + delete node; + } + node = nextNode; + } +} + +static JSBool XPCCycleCollectGCCallback(JSContext *cx, JSGCStatus status) { + if (status == JSGC_MARK_END) + processGarbage(); + return gOldJSGCCallback ? gOldJSGCCallback(cx, status) : JS_TRUE; +} + +nsJSWeakRef::nsJSWeakRef() +{ + this->impl = new nsJSWeakRefImpl(); + this->impl->weakRef = nsnull; + this->impl->weakCx = nsnull; + this->impl->node = nsnull; +} + +nsJSWeakRef::~nsJSWeakRef() +{ + if (this->impl->node) + // Tell the GC callback to remove our node from the list next time around. + this->impl->node->data = nsnull; + + delete this->impl; + this->impl = nsnull; +} + +NS_IMETHODIMP nsJSWeakRef::Set() +{ + nsresult rv = NS_OK; + nsCOMPtr<nsIXPConnect> xpc = do_GetService( + "@mozilla.org/js/xpc/XPConnect;1", + &rv + ); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + // get the xpconnect native call context + nsAXPCNativeCallContext *cc = nsnull; + xpc->GetCurrentNativeCallContext(&cc); + if(!cc) + return NS_ERROR_FAILURE; + + // Get JSContext of current call + JSContext* cx; + rv = cc->GetJSContext(&cx); + if(NS_FAILED(rv) || !cx) + return NS_ERROR_FAILURE; + + // get place for return value + jsval *rval = nsnull; + rv = cc->GetRetValPtr(&rval); + if(NS_FAILED(rv) || !rval) + return NS_ERROR_FAILURE; + + // get argc and argv and verify arg count + PRUint32 argc; + rv = cc->GetArgc(&argc); + if(NS_FAILED(rv)) + return rv; + + if (argc < 1) + return NS_ERROR_XPC_NOT_ENOUGH_ARGS; + + jsval *argv; + rv = cc->GetArgvPtr(&argv); + if (NS_FAILED(rv)) + return rv; + + if (!JSVAL_IS_OBJECT(argv[0])) + return NS_ERROR_ILLEGAL_VALUE; + + this->impl->weakRef = JSVAL_TO_OBJECT(argv[0]); + this->impl->weakCx = cx; + + // Insert a new node at the head of the global list. + nsJSWeakRefListNode *newNode = new nsJSWeakRefListNode(); + newNode->data = this; + newNode->next = gList; + this->impl->node = newNode; + gList = newNode; + + // TODO: Note that this is never removed. + if (!gOldJSGCCallback) + gOldJSGCCallback = JS_SetGCCallback(cx, XPCCycleCollectGCCallback); + + return NS_OK; +} + +NS_IMETHODIMP nsJSWeakRef::Get() +{ + nsresult rv = NS_OK; + nsCOMPtr<nsIXPConnect> xpc = do_GetService( + "@mozilla.org/js/xpc/XPConnect;1", + &rv + ); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + // get the xpconnect native call context + nsAXPCNativeCallContext *cc = nsnull; + xpc->GetCurrentNativeCallContext(&cc); + if(!cc) + return NS_ERROR_FAILURE; + + // get place for return value + jsval *rval = nsnull; + rv = cc->GetRetValPtr(&rval); + if(NS_FAILED(rv) || !rval) + return NS_ERROR_FAILURE; + + // TODO: Do we have to increase the reference count of the object + // or anything? + + // This automatically is set to JSVAL_NULL if weakRef is nsnull. + *rval = OBJECT_TO_JSVAL(this->impl->weakRef); + cc->SetReturnValueWasSet(PR_TRUE); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS1(nsJSWeakRef, nsIJSWeakRef);