// static nsresult nsXPCWrappedJS::GetNewOrUsed(JS::HandleObject jsObj, REFNSIID aIID, nsXPCWrappedJS** wrapperResult) { // Do a release-mode assert against accessing nsXPCWrappedJS off-main-thread. if (!MOZ_LIKELY(NS_IsMainThread())) MOZ_CRASH(); AutoJSContext cx; XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); JSObject2WrappedJSMap* map = rt->GetWrappedJSMap(); if (!map) { MOZ_ASSERT(map,"bad map"); return NS_ERROR_FAILURE; } nsRefPtr<nsXPCWrappedJSClass> clasp = nsXPCWrappedJSClass::GetNewOrUsed(cx, aIID); if (!clasp) return NS_ERROR_FAILURE; JS::RootedObject rootJSObj(cx, clasp->GetRootJSObject(cx, jsObj)); if (!rootJSObj) return NS_ERROR_FAILURE; nsRefPtr<nsXPCWrappedJS> root = map->Find(rootJSObj); if (root) { nsRefPtr<nsXPCWrappedJS> wrapper = root->FindOrFindInherited(aIID); if (wrapper) { wrapper.forget(wrapperResult); return NS_OK; } } else if (rootJSObj != jsObj) { // Make a new root wrapper, because there is no existing // root wrapper, and the wrapper we are trying to make isn't // a root. nsRefPtr<nsXPCWrappedJSClass> rootClasp = nsXPCWrappedJSClass::GetNewOrUsed(cx, NS_GET_IID(nsISupports)); if (!rootClasp) return NS_ERROR_FAILURE; root = new nsXPCWrappedJS(cx, rootJSObj, rootClasp, nullptr); } nsRefPtr<nsXPCWrappedJS> wrapper = new nsXPCWrappedJS(cx, jsObj, clasp, root); wrapper.forget(wrapperResult); return NS_OK; }
// static nsresult nsXPCWrappedJS::GetNewOrUsed(JS::HandleObject jsObj, REFNSIID aIID, nsISupports* aOuter, nsXPCWrappedJS** wrapperResult) { // Do a release-mode assert against accessing nsXPCWrappedJS off-main-thread. if (!MOZ_LIKELY(NS_IsMainThread())) MOZ_CRASH(); AutoJSContext cx; JSObject2WrappedJSMap* map; nsXPCWrappedJS* root = nullptr; nsXPCWrappedJS* wrapper = nullptr; nsXPCWrappedJSClass* clazz = nullptr; XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); bool release_root = false; map = rt->GetWrappedJSMap(); if (!map) { MOZ_ASSERT(map,"bad map"); return NS_ERROR_FAILURE; } nsXPCWrappedJSClass::GetNewOrUsed(cx, aIID, &clazz); if (!clazz) return NS_ERROR_FAILURE; // from here on we need to return through 'return_wrapper' // always find the root JSObject JS::RootedObject rootJSObj(cx, clazz->GetRootJSObject(cx, jsObj)); if (!rootJSObj) goto return_wrapper; root = map->Find(rootJSObj); if (root) { if ((nullptr != (wrapper = root->Find(aIID))) || (nullptr != (wrapper = root->FindInherited(aIID)))) { NS_ADDREF(wrapper); goto return_wrapper; } } if (!root) { // build the root wrapper if (rootJSObj == jsObj) { // the root will do double duty as the interface wrapper wrapper = root = new nsXPCWrappedJS(cx, jsObj, clazz, nullptr, aOuter); if (!root) goto return_wrapper; map->Add(cx, root); goto return_wrapper; } else { // just a root wrapper nsXPCWrappedJSClass* rootClazz = nullptr; nsXPCWrappedJSClass::GetNewOrUsed(cx, NS_GET_IID(nsISupports), &rootClazz); if (!rootClazz) goto return_wrapper; root = new nsXPCWrappedJS(cx, rootJSObj, rootClazz, nullptr, aOuter); NS_RELEASE(rootClazz); if (!root) goto return_wrapper; release_root = true; map->Add(cx, root); } } // at this point we have a root and may need to build the specific wrapper MOZ_ASSERT(root,"bad root"); MOZ_ASSERT(clazz,"bad clazz"); if (!wrapper) { wrapper = new nsXPCWrappedJS(cx, jsObj, clazz, root, aOuter); if (!wrapper) goto return_wrapper; } wrapper->mNext = root->mNext; root->mNext = wrapper; return_wrapper: if (clazz) NS_RELEASE(clazz); if (release_root) NS_RELEASE(root); if (!wrapper) return NS_ERROR_FAILURE; *wrapperResult = wrapper; return NS_OK; }
// static nsresult nsXPCWrappedJS::GetNewOrUsed(XPCCallContext& ccx, JSObject* aJSObj, REFNSIID aIID, nsISupports* aOuter, nsXPCWrappedJS** wrapperResult) { JSObject2WrappedJSMap* map; JSObject* rootJSObj; nsXPCWrappedJS* root = nsnull; nsXPCWrappedJS* wrapper = nsnull; nsXPCWrappedJSClass* clazz = nsnull; XPCJSRuntime* rt = ccx.GetRuntime(); JSBool release_root = JS_FALSE; map = rt->GetWrappedJSMap(); if (!map) { NS_ASSERTION(map,"bad map"); return NS_ERROR_FAILURE; } nsXPCWrappedJSClass::GetNewOrUsed(ccx, aIID, &clazz); if (!clazz) return NS_ERROR_FAILURE; // from here on we need to return through 'return_wrapper' // always find the root JSObject rootJSObj = clazz->GetRootJSObject(ccx, aJSObj); if (!rootJSObj) goto return_wrapper; // look for the root wrapper, and if found, hold the map lock until // we've added our ref to prevent another thread from destroying it // under us { // scoped lock XPCAutoLock lock(rt->GetMapLock()); root = map->Find(rootJSObj); if (root) { if ((nsnull != (wrapper = root->Find(aIID))) || (nsnull != (wrapper = root->FindInherited(aIID)))) { NS_ADDREF(wrapper); goto return_wrapper; } } } if (!root) { // build the root wrapper if (rootJSObj == aJSObj) { // the root will do double duty as the interface wrapper wrapper = root = new nsXPCWrappedJS(ccx, aJSObj, clazz, nsnull, aOuter); if (!root) goto return_wrapper; { // scoped lock #if DEBUG_xpc_leaks printf("Created nsXPCWrappedJS %p, JSObject is %p\n", (void*)wrapper, (void*)aJSObj); #endif XPCAutoLock lock(rt->GetMapLock()); map->Add(root); } if (!CheckMainThreadOnly(root)) { XPCAutoLock lock(rt->GetMapLock()); map->Remove(root); wrapper = NULL; } goto return_wrapper; } else { // just a root wrapper nsXPCWrappedJSClass* rootClazz = nsnull; nsXPCWrappedJSClass::GetNewOrUsed(ccx, NS_GET_IID(nsISupports), &rootClazz); if (!rootClazz) goto return_wrapper; root = new nsXPCWrappedJS(ccx, rootJSObj, rootClazz, nsnull, aOuter); NS_RELEASE(rootClazz); if (!root) goto return_wrapper; release_root = JS_TRUE; { // scoped lock #if DEBUG_xpc_leaks printf("Created nsXPCWrappedJS %p, JSObject is %p\n", (void*)root, (void*)rootJSObj); #endif XPCAutoLock lock(rt->GetMapLock()); map->Add(root); } if (!CheckMainThreadOnly(root)) { XPCAutoLock lock(rt->GetMapLock()); map->Remove(root); goto return_wrapper; } } } // at this point we have a root and may need to build the specific wrapper NS_ASSERTION(root,"bad root"); NS_ASSERTION(clazz,"bad clazz"); if (!wrapper) { wrapper = new nsXPCWrappedJS(ccx, aJSObj, clazz, root, aOuter); if (!wrapper) goto return_wrapper; #if DEBUG_xpc_leaks printf("Created nsXPCWrappedJS %p, JSObject is %p\n", (void*)wrapper, (void*)aJSObj); #endif } wrapper->mNext = root->mNext; root->mNext = wrapper; return_wrapper: if (clazz) NS_RELEASE(clazz); if (release_root) NS_RELEASE(root); if (!wrapper) return NS_ERROR_FAILURE; *wrapperResult = wrapper; return NS_OK; }
// static nsresult nsXPCWrappedJS::GetNewOrUsed(JS::HandleObject jsObj, REFNSIID aIID, nsISupports* aOuter, nsXPCWrappedJS** wrapperResult) { // Do a release-mode assert against accessing nsXPCWrappedJS off-main-thread. if (!MOZ_LIKELY(NS_IsMainThread() || NS_IsCycleCollectorThread())) MOZ_CRASH(); AutoJSContext cx; JSObject2WrappedJSMap* map; nsXPCWrappedJS* root = nullptr; nsXPCWrappedJS* wrapper = nullptr; nsXPCWrappedJSClass* clazz = nullptr; XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); bool release_root = false; map = rt->GetWrappedJSMap(); if (!map) { NS_ASSERTION(map,"bad map"); return NS_ERROR_FAILURE; } nsXPCWrappedJSClass::GetNewOrUsed(cx, aIID, &clazz); if (!clazz) return NS_ERROR_FAILURE; // from here on we need to return through 'return_wrapper' // always find the root JSObject JS::RootedObject rootJSObj(cx, clazz->GetRootJSObject(cx, jsObj)); if (!rootJSObj) goto return_wrapper; // look for the root wrapper, and if found, hold the map lock until // we've added our ref to prevent another thread from destroying it // under us { // scoped lock XPCAutoLock lock(rt->GetMapLock()); root = map->Find(rootJSObj); if (root) { if ((nullptr != (wrapper = root->Find(aIID))) || (nullptr != (wrapper = root->FindInherited(aIID)))) { NS_ADDREF(wrapper); goto return_wrapper; } } } if (!root) { // build the root wrapper if (rootJSObj == jsObj) { // the root will do double duty as the interface wrapper wrapper = root = new nsXPCWrappedJS(cx, jsObj, clazz, nullptr, aOuter); if (!root) goto return_wrapper; { // scoped lock #if DEBUG_xpc_leaks printf("Created nsXPCWrappedJS %p, JSObject is %p\n", (void*)wrapper, (void*)jsObj); #endif XPCAutoLock lock(rt->GetMapLock()); map->Add(cx, root); } if (!CheckMainThreadOnly(root)) { XPCAutoLock lock(rt->GetMapLock()); map->Remove(root); wrapper = NULL; } goto return_wrapper; } else { // just a root wrapper nsXPCWrappedJSClass* rootClazz = nullptr; nsXPCWrappedJSClass::GetNewOrUsed(cx, NS_GET_IID(nsISupports), &rootClazz); if (!rootClazz) goto return_wrapper; root = new nsXPCWrappedJS(cx, rootJSObj, rootClazz, nullptr, aOuter); NS_RELEASE(rootClazz); if (!root) goto return_wrapper; release_root = true; { // scoped lock #if DEBUG_xpc_leaks printf("Created nsXPCWrappedJS %p, JSObject is %p\n", (void*)root, (void*)rootJSObj); #endif XPCAutoLock lock(rt->GetMapLock()); map->Add(cx, root); } if (!CheckMainThreadOnly(root)) { XPCAutoLock lock(rt->GetMapLock()); map->Remove(root); goto return_wrapper; } } } // at this point we have a root and may need to build the specific wrapper NS_ASSERTION(root,"bad root"); NS_ASSERTION(clazz,"bad clazz"); if (!wrapper) { wrapper = new nsXPCWrappedJS(cx, jsObj, clazz, root, aOuter); if (!wrapper) goto return_wrapper; #if DEBUG_xpc_leaks printf("Created nsXPCWrappedJS %p, JSObject is %p\n", (void*)wrapper, (void*)jsObj); #endif } wrapper->mNext = root->mNext; root->mNext = wrapper; return_wrapper: if (clazz) NS_RELEASE(clazz); if (release_root) NS_RELEASE(root); if (!wrapper) return NS_ERROR_FAILURE; *wrapperResult = wrapper; return NS_OK; }