DEBUG_WrapperChecker(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, void *arg) { XPCWrappedNative* wrapper = (XPCWrappedNative*)((JSDHashEntryStub*)hdr)->key; NS_ASSERTION(!wrapper->IsValid(), "found a 'valid' wrapper!"); ++ *((int*)arg); return JS_DHASH_NEXT; }
static JSDHashOperator WrappedNativeShutdownEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32_t number, void *arg) { ShutdownData* data = (ShutdownData*) arg; XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value; if (wrapper->IsValid()) { wrapper->SystemIsBeingShutDown(); data->wrapperCount++; } return JS_DHASH_REMOVE; }
/* static */ void XPCWrappedNative::Trace(JSTracer* trc, JSObject* obj) { const js::Class* clazz = js::GetObjectClass(obj); if (clazz->flags & JSCLASS_DOM_GLOBAL) { mozilla::dom::TraceProtoAndIfaceCache(trc, obj); } MOZ_ASSERT(IS_WN_CLASS(clazz)); XPCWrappedNative* wrapper = XPCWrappedNative::Get(obj); if (wrapper && wrapper->IsValid()) wrapper->TraceInside(trc); }
WrappedNativeShutdownEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, void *arg) { ShutdownData* data = (ShutdownData*) arg; XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value; if(wrapper->IsValid()) { if(wrapper->HasProto() && !wrapper->HasSharedProto()) data->nonSharedProtoCount++; wrapper->SystemIsBeingShutDown(data->cx); data->wrapperCount++; } return JS_DHASH_REMOVE; }
//static void XPCWrappedNativeScope::SystemIsBeingShutDown() { int liveScopeCount = 0; XPCWrappedNativeScope* cur; // First move all the scopes to the dying list. cur = gScopes; while (cur) { XPCWrappedNativeScope* next = cur->mNext; cur->mNext = gDyingScopes; gDyingScopes = cur; cur = next; liveScopeCount++; } gScopes = nullptr; // We're forcibly killing scopes, rather than allowing them to go away // when they're ready. As such, we need to do some cleanup before they // can safely be destroyed. for (cur = gDyingScopes; cur; cur = cur->mNext) { // Give the Components object a chance to try to clean up. if (cur->mComponents) cur->mComponents->SystemIsBeingShutDown(); // Walk the protos first. Wrapper shutdown can leave dangling // proto pointers in the proto map. for (auto i = cur->mWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) { auto entry = static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(i.Get()); entry->value->SystemIsBeingShutDown(); i.Remove(); } for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) { auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get()); XPCWrappedNative* wrapper = entry->value; if (wrapper->IsValid()) { wrapper->SystemIsBeingShutDown(); } i.Remove(); } } // Now it is safe to kill all the scopes. KillDyingScopes(); }
WrappedNativeSuspecter(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, void *arg) { SuspectClosure* closure = static_cast<SuspectClosure*>(arg); XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value; XPCWrappedNativeProto* proto = wrapper->GetProto(); if(proto && proto->ClassIsMainThreadOnly() && wrapper->IsValid()) { NS_ASSERTION(NS_IsMainThread(), "Suspecting wrapped natives from non-main thread"); #ifndef DEBUG_CC // Only record objects that might be part of a cycle as roots. if(!JS_IsAboutToBeFinalized(closure->cx, wrapper->GetFlatJSObject())) return JS_DHASH_NEXT; #endif closure->cb.NoteRoot(nsIProgrammingLanguage::JAVASCRIPT, wrapper->GetFlatJSObject(), nsXPConnect::GetXPConnect()); } return JS_DHASH_NEXT; }
static bool ResolveNativeProperty(JSContext *cx, JSObject *wrapper, JSObject *holder, jsid id, bool set, JSPropertyDescriptor *desc) { desc->obj = NULL; NS_ASSERTION(holder->getJSClass() == &HolderClass, "expected a native property holder object"); JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder); XPCWrappedNative *wn = GetWrappedNative(wnObject); // This will do verification and the method lookup for us. XPCCallContext ccx(JS_CALLER, cx, wnObject, nsnull, id); // There are no native numeric properties, so we can shortcut here. We will not // find the property. if (!JSID_IS_ATOM(id)) { /* Not found */ return true; } XPCNativeInterface *iface; XPCNativeMember *member; if (ccx.GetWrapper() != wn || !wn->IsValid() || !(iface = ccx.GetInterface()) || !(member = ccx.GetMember())) { /* Not found */ return true; } desc->obj = holder; desc->attrs = JSPROP_ENUMERATE; desc->getter = NULL; desc->setter = NULL; desc->shortid = 0; desc->value = JSVAL_VOID; jsval fval = JSVAL_VOID; if (member->IsConstant()) { if (!member->GetConstantValue(ccx, iface, &desc->value)) { JS_ReportError(cx, "Failed to convert constant native property to JS value"); return false; } } else if (member->IsAttribute()) { // This is a getter/setter. Clone a function for it. if (!member->NewFunctionObject(ccx, iface, wrapper, &fval)) { JS_ReportError(cx, "Failed to clone function object for native getter/setter"); return false; } desc->attrs |= JSPROP_GETTER; if (member->IsWritableAttribute()) desc->attrs |= JSPROP_SETTER; // Make the property shared on the holder so no slot is allocated // for it. This avoids keeping garbage alive through that slot. desc->attrs |= JSPROP_SHARED; } else { // This is a method. Clone a function for it. if (!member->NewFunctionObject(ccx, iface, wrapper, &desc->value)) { JS_ReportError(cx, "Failed to clone function object for native function"); return false; } // Without a wrapper the function would live on the prototype. Since we // don't have one, we have to avoid calling the scriptable helper's // GetProperty method for this property, so stub out the getter and // setter here explicitly. desc->getter = JS_PropertyStub; desc->setter = JS_StrictPropertyStub; } if (!JS_WrapValue(cx, &desc->value) || !JS_WrapValue(cx, &fval)) return false; if (desc->attrs & JSPROP_GETTER) desc->getter = CastAsJSPropertyOp(JSVAL_TO_OBJECT(fval)); if (desc->attrs & JSPROP_SETTER) desc->setter = CastAsJSStrictPropertyOp(JSVAL_TO_OBJECT(fval)); // Define the property. return JS_DefinePropertyById(cx, holder, id, desc->value, desc->getter, desc->setter, desc->attrs); }