// static void XPCWrappedNativeScope::DebugDumpAllScopes(int16_t depth) { #ifdef DEBUG depth-- ; // get scope count. int count = 0; XPCWrappedNativeScope* cur; for (cur = gScopes; cur; cur = cur->mNext) count++ ; XPC_LOG_ALWAYS(("chain of %d XPCWrappedNativeScope(s)", count)); XPC_LOG_INDENT(); XPC_LOG_ALWAYS(("gDyingScopes @ %x", gDyingScopes)); if (depth) for (cur = gScopes; cur; cur = cur->mNext) cur->DebugDump(depth); XPC_LOG_OUTDENT(); #endif }
// static XPCWrappedNativeScope* XPCWrappedNativeScope::GetNewOrUsed(XPCCallContext& ccx, JSObject* aGlobal) { XPCWrappedNativeScope* scope = FindInJSObjectScope(ccx, aGlobal, true); if (!scope) scope = new XPCWrappedNativeScope(ccx, aGlobal); else { // We need to call SetGlobal in order to refresh our cached // mPrototypeJSObject and to clear mPrototypeNoHelper (so we get a new // new one if requested in the new scope) in the case where the global // object is being reused (JS_ClearScope has been called). NOTE: We are // only called by nsXPConnect::InitClasses. scope->SetGlobal(ccx, aGlobal); } if (js::GetObjectClass(aGlobal)->flags & JSCLASS_XPCONNECT_GLOBAL) JS_ALWAYS_TRUE(JS_SetReservedSlot(ccx, aGlobal, JSCLASS_GLOBAL_SLOT_COUNT, PRIVATE_TO_JSVAL(scope))); return scope; }
bool InterposeCall(JSContext* cx, JS::HandleObject target, const JS::CallArgs& args, bool* done) { *done = false; XPCWrappedNativeScope* scope = ObjectScope(CurrentGlobalOrNull(cx)); MOZ_ASSERT(scope->HasInterposition()); nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition(); RootedObject unwrappedTarget(cx, UncheckedUnwrap(target)); XPCWrappedNativeScope* targetScope = ObjectScope(unwrappedTarget); bool hasInterpostion = targetScope->HasCallInterposition(); if (!hasInterpostion) return true; // If there is a call interpostion, we don't want to propogate the // call to Base: *done = true; JSAddonId* addonId = AddonIdOfObject(target); RootedValue addonIdValue(cx, StringValue(StringOfAddonId(addonId))); RootedValue targetValue(cx, ObjectValue(*target)); RootedValue thisValue(cx, args.thisv()); RootedObject argsArray(cx, ConvertArgsToArray(cx, args)); if (!argsArray) return false; RootedValue argsVal(cx, ObjectValue(*argsArray)); RootedValue returnVal(cx); nsresult rv = interp->InterposeCall(addonIdValue, targetValue, thisValue, argsVal, args.rval()); if (NS_FAILED(rv)) { xpc::Throw(cx, rv); return false; } return true; }
/* void initClasses (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */ NS_IMETHODIMP nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj) { MOZ_ASSERT(aJSContext, "bad param"); MOZ_ASSERT(aGlobalJSObj, "bad param"); RootedObject globalJSObj(aJSContext, aGlobalJSObj); JSAutoCompartment ac(aJSContext, globalJSObj); XPCWrappedNativeScope* scope = XPCWrappedNativeScope::GetNewOrUsed(aJSContext, globalJSObj); if (!scope) return UnexpectedFailure(NS_ERROR_FAILURE); scope->RemoveWrappedNativeProtos(); if (!XPCNativeWrapper::AttachNewConstructorObject(aJSContext, globalJSObj)) return UnexpectedFailure(NS_ERROR_FAILURE); return NS_OK; }
XPCWrappedNativeScope::XPCWrappedNativeScope(XPCCallContext& ccx, JSObject* aGlobal, nsISupports* aNative) : mRuntime(ccx.GetRuntime()), mWrappedNativeMap(Native2WrappedNativeMap::newMap(XPC_NATIVE_MAP_SIZE)), mWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_SIZE)), mMainThreadWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_SIZE)), mComponents(nsnull), mNext(nsnull), mGlobalJSObject(nsnull), mPrototypeJSObject(nsnull), mPrototypeNoHelper(nsnull), mScriptObjectPrincipal(nsnull), mNewDOMBindingsEnabled(ccx.GetRuntime()->NewDOMBindingsEnabled()), mExperimentalBindingsEnabled(ccx.GetRuntime()->ExperimentalBindingsEnabled()) { // add ourselves to the scopes list { // scoped lock XPCAutoLock lock(mRuntime->GetMapLock()); #ifdef DEBUG for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) NS_ASSERTION(aGlobal != cur->GetGlobalJSObject(), "dup object"); #endif mNext = gScopes; gScopes = this; // Grab the XPCContext associated with our context. mContext = XPCContext::GetXPCContext(ccx.GetJSContext()); mContext->AddScope(this); } if (aGlobal) SetGlobal(ccx, aGlobal, aNative); DEBUG_TrackNewScope(this); MOZ_COUNT_CTOR(XPCWrappedNativeScope); }
XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext *cx, JSObject* aGlobal) : mWrappedNativeMap(Native2WrappedNativeMap::newMap(XPC_NATIVE_MAP_SIZE)), mWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_SIZE)), mMainThreadWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_SIZE)), mComponents(nullptr), mNext(nullptr), mGlobalJSObject(nullptr), mPrototypeNoHelper(nullptr), mExperimentalBindingsEnabled(XPCJSRuntime::Get()->ExperimentalBindingsEnabled()) { // add ourselves to the scopes list { // scoped lock XPCAutoLock lock(XPCJSRuntime::Get()->GetMapLock()); #ifdef DEBUG for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) MOZ_ASSERT(aGlobal != cur->GetGlobalJSObjectPreserveColor(), "dup object"); #endif mNext = gScopes; gScopes = this; // Grab the XPCContext associated with our context. mContext = XPCContext::GetXPCContext(cx); mContext->AddScope(this); } if (aGlobal) SetGlobal(cx, aGlobal); DEBUG_TrackNewScope(this); MOZ_COUNT_CTOR(XPCWrappedNativeScope); // Attach ourselves to the compartment private. CompartmentPrivate *priv = EnsureCompartmentPrivate(aGlobal); priv->scope = this; }
XPCWrappedNativeScope::XPCWrappedNativeScope(XPCCallContext& ccx, JSObject* aGlobal) : mRuntime(ccx.GetRuntime()), mWrappedNativeMap(Native2WrappedNativeMap::newMap(XPC_NATIVE_MAP_SIZE)), mWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_SIZE)), mWrapperMap(WrappedNative2WrapperMap::newMap(XPC_WRAPPER_MAP_SIZE)), mComponents(nsnull), mNext(nsnull), mGlobalJSObject(nsnull), mPrototypeJSObject(nsnull), mPrototypeJSFunction(nsnull), mPrototypeNoHelper(nsnull) { // add ourselves to the scopes list { // scoped lock XPCAutoLock lock(mRuntime->GetMapLock()); #ifdef DEBUG for(XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) NS_ASSERTION(aGlobal != cur->GetGlobalJSObject(), "dup object"); #endif mNext = gScopes; gScopes = this; // Grab the XPCContext associated with our context. mContext = mRuntime->GetContextMap()->Find(ccx.GetJSContext()); NS_ASSERTION(mContext, "Context map is not synchronized"); mContext->AddScope(this); } if(aGlobal) SetGlobal(ccx, aGlobal); DEBUG_TrackNewScope(this); MOZ_COUNT_CTOR(XPCWrappedNativeScope); }
static void XPC_XOW_Finalize(JSContext *cx, JSObject *obj) { JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { return; } jsval flags = GetFlags(cx, obj); if (HAS_FLAGS(flags, FLAG_IS_CACHED)) { // We know that it's safe to access our wrapped object. XPCWrappedNativeWithXOW *wnxow = static_cast<XPCWrappedNativeWithXOW *>(xpc_GetJSPrivate(wrappedObj)); wnxow->SetXOW(nsnull); JS_SetReservedSlot(cx, obj, sWrappedObjSlot, JSVAL_VOID); SetFlags(cx, obj, RemoveFlags(flags, FLAG_IS_CACHED)); } // Get our scope. jsval scopeVal; if (!JS_GetReservedSlot(cx, obj, XPC_XOW_ScopeSlot, &scopeVal)) { return; } // Now that we have our scope, see if it's going away. If it is, // then our work here is going to be done when we destroy the scope // entirely. Scope can be null if we're an enumerating XOW. XPCWrappedNativeScope *scope = reinterpret_cast<XPCWrappedNativeScope *> (JSVAL_TO_PRIVATE(scopeVal)); if (!scope) { return; } // Remove ourselves from the map. scope->GetWrapperMap()->Remove(wrappedObj); }
JSObject* xpc::GetAddonScope(JSContext* cx, JS::HandleObject contentScope, JSAddonId* addonId) { MOZ_RELEASE_ASSERT(!IsInAddonScope(contentScope)); if (!addonId || !CompartmentPerAddon()) { return js::GetGlobalForObjectCrossCompartment(contentScope); } JSAutoCompartment ac(cx, contentScope); XPCWrappedNativeScope* nativeScope = CompartmentPrivate::Get(contentScope)->scope; if (nativeScope->GetPrincipal() != nsXPConnect::SystemPrincipal()) { // This can happen if, for example, Jetpack loads an unprivileged HTML // page from the add-on. It's not clear what to do there, so we just use // the normal global. return js::GetGlobalForObjectCrossCompartment(contentScope); } JSObject* scope = nativeScope->EnsureAddonScope(cx, addonId); NS_ENSURE_TRUE(scope, nullptr); scope = js::UncheckedUnwrap(scope); JS::ExposeObjectToActiveJS(scope); return scope; }
void XPCWrappedNativeScope::AddSizeOfAllScopesIncludingThis(ScopeSizeInfo* scopeSizeInfo) { for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) cur->AddSizeOfIncludingThis(scopeSizeInfo); }
XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext* cx, JS::HandleObject aGlobal) : mWrappedNativeMap(Native2WrappedNativeMap::newMap(XPC_NATIVE_MAP_LENGTH)), mWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_LENGTH)), mComponents(nullptr), mNext(nullptr), mGlobalJSObject(aGlobal), mHasCallInterpositions(false), mIsContentXBLScope(false), mIsAddonScope(false) { // add ourselves to the scopes list { MOZ_ASSERT(aGlobal); DebugOnly<const js::Class*> clasp = js::GetObjectClass(aGlobal); MOZ_ASSERT(clasp->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_HAS_PRIVATE) || mozilla::dom::IsDOMClass(clasp)); #ifdef DEBUG for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) MOZ_ASSERT(aGlobal != cur->GetGlobalJSObjectPreserveColor(), "dup object"); #endif mNext = gScopes; gScopes = this; } MOZ_COUNT_CTOR(XPCWrappedNativeScope); // Create the compartment private. JSCompartment* c = js::GetObjectCompartment(aGlobal); MOZ_ASSERT(!JS_GetCompartmentPrivate(c)); CompartmentPrivate* priv = new CompartmentPrivate(c); JS_SetCompartmentPrivate(c, priv); // Attach ourselves to the compartment private. priv->scope = this; // Determine whether we would allow an XBL scope in this situation. // In addition to being pref-controlled, we also disable XBL scopes for // remote XUL domains, _except_ if we have an additional pref override set. nsIPrincipal* principal = GetPrincipal(); mAllowContentXBLScope = !RemoteXULForbidsXBLScope(principal, aGlobal); // Determine whether to use an XBL scope. mUseContentXBLScope = mAllowContentXBLScope; if (mUseContentXBLScope) { const js::Class* clasp = js::GetObjectClass(mGlobalJSObject); mUseContentXBLScope = !strcmp(clasp->name, "Window"); } if (mUseContentXBLScope) { mUseContentXBLScope = principal && !nsContentUtils::IsSystemPrincipal(principal); } JSAddonId* addonId = JS::AddonIdOfObject(aGlobal); if (gInterpositionMap) { bool isSystem = nsContentUtils::IsSystemPrincipal(principal); bool waiveInterposition = priv->waiveInterposition; InterpositionMap::Ptr interposition = gInterpositionMap->lookup(addonId); if (!waiveInterposition && interposition) { MOZ_RELEASE_ASSERT(isSystem); mInterposition = interposition->value(); } // We also want multiprocessCompatible add-ons to have a default interposition. if (!mInterposition && addonId && isSystem) { bool interpositionEnabled = mozilla::Preferences::GetBool( "extensions.interposition.enabled", false); if (interpositionEnabled) { mInterposition = do_GetService("@mozilla.org/addons/default-addon-shims;1"); MOZ_ASSERT(mInterposition); UpdateInterpositionWhitelist(cx, mInterposition); } } } }
bool UseContentXBLScope(JSCompartment* c) { XPCWrappedNativeScope* scope = CompartmentPrivate::Get(c)->scope; return scope && scope->UseContentXBLScope(); }
JSBool WrapObject(JSContext *cx, JSObject *scope, jsval v, jsval *vp) { // This might be redundant if called from XPC_SJOW_Construct, but it should // be cheap in that case. JSObject *objToWrap = UnsafeUnwrapSecurityWrapper(cx, JSVAL_TO_OBJECT(v)); if (!objToWrap || JS_TypeOfValue(cx, OBJECT_TO_JSVAL(objToWrap)) == JSTYPE_XML) { return ThrowException(NS_ERROR_INVALID_ARG, cx); } // Prevent script created Script objects from ever being wrapped // with XPCSafeJSObjectWrapper, and never let the eval function // object be directly wrapped. if (objToWrap->getClass() == &js_ScriptClass || (JS_ObjectIsFunction(cx, objToWrap) && JS_GetFunctionFastNative(cx, JS_ValueToFunction(cx, v)) == XPCWrapper::sEvalNative)) { return ThrowException(NS_ERROR_INVALID_ARG, cx); } XPCWrappedNativeScope *xpcscope = XPCWrappedNativeScope::FindInJSObjectScope(cx, scope); NS_ASSERTION(xpcscope, "what crazy scope are we in?"); XPCWrappedNative *wrappedNative; WrapperType type = xpcscope->GetWrapperFor(cx, objToWrap, SJOW, &wrappedNative); // NB: We allow XOW here because we're as restrictive as it is (and we know // we're same origin here). if (type != NONE && type != XOW && !(type & SJOW)) { return ThrowException(NS_ERROR_INVALID_ARG, cx); } SLIM_LOG_WILL_MORPH(cx, objToWrap); if (IS_SLIM_WRAPPER(objToWrap) && !MorphSlimWrapper(cx, objToWrap)) { return ThrowException(NS_ERROR_FAILURE, cx); } XPCWrappedNative *wn = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, objToWrap); if (wn) { CheckWindow(wn); } JSObject *wrapperObj = JS_NewObjectWithGivenProto(cx, js::Jsvalify(&SJOWClass), nsnull, scope); if (!wrapperObj) { // JS_NewObjectWithGivenProto already threw. return JS_FALSE; } *vp = OBJECT_TO_JSVAL(wrapperObj); if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, OBJECT_TO_JSVAL(objToWrap)) || !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO)) { return JS_FALSE; } return JS_TRUE; }
bool InterposeProperty(JSContext* cx, HandleObject target, const nsIID* iid, HandleId id, MutableHandle<JSPropertyDescriptor> descriptor) { // We only want to do interpostion on DOM instances and // wrapped natives. RootedObject unwrapped(cx, UncheckedUnwrap(target)); const js::Class* clasp = js::GetObjectClass(unwrapped); bool isCPOW = jsipc::IsWrappedCPOW(unwrapped); if (!mozilla::dom::IsDOMClass(clasp) && !IS_WN_CLASS(clasp) && !IS_PROTO_CLASS(clasp) && clasp != &OuterWindowProxyClass && !isCPOW) { return true; } XPCWrappedNativeScope* scope = ObjectScope(CurrentGlobalOrNull(cx)); MOZ_ASSERT(scope->HasInterposition()); nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition(); InterpositionWhitelist* wl = XPCWrappedNativeScope::GetInterpositionWhitelist(interp); // We do InterposeProperty only if the id is on the whitelist of the interpostion // or if the target is a CPOW. if ((!wl || !wl->has(JSID_BITS(id.get()))) && !isCPOW) return true; JSAddonId* addonId = AddonIdOfObject(target); RootedValue addonIdValue(cx, StringValue(StringOfAddonId(addonId))); RootedValue prop(cx, IdToValue(id)); RootedValue targetValue(cx, ObjectValue(*target)); RootedValue descriptorVal(cx); nsresult rv = interp->InterposeProperty(addonIdValue, targetValue, iid, prop, &descriptorVal); if (NS_FAILED(rv)) { xpc::Throw(cx, rv); return false; } if (!descriptorVal.isObject()) return true; // We need to be careful parsing descriptorVal. |cx| is in the compartment // of the add-on and the descriptor is in the compartment of the // interposition. We could wrap the descriptor in the add-on's compartment // and then parse it. However, parsing the descriptor fetches properties // from it, and we would try to interpose on those property accesses. So // instead we parse in the interposition's compartment and then wrap the // descriptor. { JSAutoCompartment ac(cx, &descriptorVal.toObject()); if (!JS::ObjectToCompletePropertyDescriptor(cx, target, descriptorVal, descriptor)) return false; } // Always make the property non-configurable regardless of what the // interposition wants. descriptor.setAttributes(descriptor.attributes() | JSPROP_PERMANENT); if (!JS_WrapPropertyDescriptor(cx, descriptor)) return false; return true; }
bool AllowXBLScope(JSCompartment *c) { XPCWrappedNativeScope *scope = EnsureCompartmentPrivate(c)->scope; return scope && scope->AllowXBLScope(); }
XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext *cx, JS::HandleObject aGlobal) : mWrappedNativeMap(Native2WrappedNativeMap::newMap(XPC_NATIVE_MAP_LENGTH)), mWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_LENGTH)), mComponents(nullptr), mNext(nullptr), mGlobalJSObject(aGlobal), mIsContentXBLScope(false), mIsAddonScope(false) { // add ourselves to the scopes list { MOZ_ASSERT(aGlobal); DebugOnly<const js::Class*> clasp = js::GetObjectClass(aGlobal); MOZ_ASSERT(clasp->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_HAS_PRIVATE) || mozilla::dom::IsDOMClass(clasp)); #ifdef DEBUG for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) MOZ_ASSERT(aGlobal != cur->GetGlobalJSObjectPreserveColor(), "dup object"); #endif mNext = gScopes; gScopes = this; } MOZ_COUNT_CTOR(XPCWrappedNativeScope); // Create the compartment private. JSCompartment *c = js::GetObjectCompartment(aGlobal); MOZ_ASSERT(!JS_GetCompartmentPrivate(c)); CompartmentPrivate *priv = new CompartmentPrivate(c); JS_SetCompartmentPrivate(c, priv); // Attach ourselves to the compartment private. priv->scope = this; // Determine whether we would allow an XBL scope in this situation. // In addition to being pref-controlled, we also disable XBL scopes for // remote XUL domains, _except_ if we have an additional pref override set. nsIPrincipal *principal = GetPrincipal(); mAllowContentXBLScope = !RemoteXULForbidsXBLScope(principal, aGlobal); // Determine whether to use an XBL scope. mUseContentXBLScope = mAllowContentXBLScope; if (mUseContentXBLScope) { const js::Class *clasp = js::GetObjectClass(mGlobalJSObject); mUseContentXBLScope = !strcmp(clasp->name, "Window") || !strcmp(clasp->name, "ChromeWindow") || !strcmp(clasp->name, "ModalContentWindow"); } if (mUseContentXBLScope) { mUseContentXBLScope = principal && !nsContentUtils::IsSystemPrincipal(principal); } JSAddonId *addonId = JS::AddonIdOfObject(aGlobal); if (gInterpositionMap) { if (InterpositionMap::Ptr p = gInterpositionMap->lookup(addonId)) { MOZ_RELEASE_ASSERT(nsContentUtils::IsSystemPrincipal(principal)); mInterposition = p->value(); } } }
// static XPCWrappedNativeScope* XPCWrappedNativeScope::FindInJSObjectScope(JSContext* cx, JSObject* obj, JSBool OKIfNotInitialized, XPCJSRuntime* runtime) { XPCWrappedNativeScope* scope; if (!obj) return nsnull; // If this object is itself a wrapped native then we can get the // scope directly. scope = GetScopeOfObject(obj); if (scope) return scope; // Else we'll have to look up the parent chain to get the scope JSAutoEnterCompartment ac; ac.enterAndIgnoreErrors(cx, obj); #ifdef DEBUG JSObject *startingObj = obj; #endif obj = JS_GetGlobalForObject(cx, obj); if (js::GetObjectClass(obj)->flags & JSCLASS_XPCONNECT_GLOBAL) { scope = XPCWrappedNativeScope::GetNativeScope(cx, obj); if (scope) return scope; } if (!runtime) { runtime = nsXPConnect::GetRuntimeInstance(); NS_ASSERTION(runtime, "This should never be null!"); } // XXX We are assuming that the scope count is low enough that traversing // the linked list is more reasonable then doing a hashtable lookup. XPCWrappedNativeScope* found = nsnull; { // scoped lock XPCAutoLock lock(runtime->GetMapLock()); DEBUG_TrackScopeTraversal(); for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) { if (obj == cur->GetGlobalJSObject()) { found = cur; break; } } } if (found) { // This cannot be called within the map lock! DEBUG_CheckForComponentsInScope(cx, obj, startingObj, OKIfNotInitialized, runtime); return found; } // Failure to find the scope is only OK if the caller told us it might fail. // This flag would only be set in the call from // XPCWrappedNativeScope::GetNewOrUsed NS_ASSERTION(OKIfNotInitialized, "No scope has this global object!"); return nsnull; }
JSBool XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp, XPCWrappedNative* wn) { NS_ASSERTION(XPCPerThreadData::IsMainThread(cx), "Can't do this off the main thread!"); // Our argument should be a wrapped native object, but the caller may have // passed it in as an optimization. JSObject *wrappedObj; if (!JSVAL_IS_OBJECT(*vp) || !(wrappedObj = JSVAL_TO_OBJECT(*vp)) || STOBJ_GET_CLASS(wrappedObj) == &sXPC_XOW_JSClass.base) { return JS_TRUE; } if (!wn && !(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, wrappedObj))) { return JS_TRUE; } XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance(); // The parent must be the inner global object for its scope. parent = JS_GetGlobalForObject(cx, parent); JSClass *clasp = STOBJ_GET_CLASS(parent); if (clasp->flags & JSCLASS_IS_EXTENDED) { JSExtendedClass *xclasp = reinterpret_cast<JSExtendedClass *>(clasp); if (xclasp->innerObject) { parent = xclasp->innerObject(cx, parent); if (!parent) { return JS_FALSE; } } } XPCWrappedNativeScope *parentScope = XPCWrappedNativeScope::FindInJSObjectScope(cx, parent, nsnull, rt); #ifdef DEBUG_mrbkap_off printf("Wrapping object at %p (%s) [%p]\n", (void *)wrappedObj, STOBJ_GET_CLASS(wrappedObj)->name, (void *)parentScope); #endif JSObject *outerObj = nsnull; WrappedNative2WrapperMap *map = parentScope->GetWrapperMap(); outerObj = map->Find(wrappedObj); if (outerObj) { NS_ASSERTION(STOBJ_GET_CLASS(outerObj) == &sXPC_XOW_JSClass.base, "What crazy object are we getting here?"); #ifdef DEBUG_mrbkap_off printf("But found a wrapper in the map %p!\n", (void *)outerObj); #endif *vp = OBJECT_TO_JSVAL(outerObj); return JS_TRUE; } outerObj = JS_NewObjectWithGivenProto(cx, &sXPC_XOW_JSClass.base, nsnull, parent); if (!outerObj) { return JS_FALSE; } if (!JS_SetReservedSlot(cx, outerObj, XPCWrapper::sWrappedObjSlot, *vp) || !JS_SetReservedSlot(cx, outerObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO) || !JS_SetReservedSlot(cx, outerObj, XPC_XOW_ScopeSlot, PRIVATE_TO_JSVAL(parentScope))) { return JS_FALSE; } *vp = OBJECT_TO_JSVAL(outerObj); map->Add(wn->GetScope()->GetWrapperMap(), wrappedObj, outerObj); return JS_TRUE; }
JSBool WrapObject(JSContext *cx, JSObject *parent, jsval *vp, XPCWrappedNative* wn) { NS_ASSERTION(XPCPerThreadData::IsMainThread(cx), "Can't do this off the main thread!"); // Our argument should be a wrapped native object, but the caller may have // passed it in as an optimization. JSObject *wrappedObj; if (JSVAL_IS_PRIMITIVE(*vp) || !(wrappedObj = JSVAL_TO_OBJECT(*vp)) || wrappedObj->getClass() == &XOWClass) { return JS_TRUE; } if (!wn && !(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, wrappedObj))) { return JS_TRUE; } CheckWindow(wn); // The parent must be the inner global object for its scope. parent = JS_GetGlobalForObject(cx, parent); OBJ_TO_INNER_OBJECT(cx, parent); if (!parent) { return JS_FALSE; } XPCWrappedNativeWithXOW *wnxow = nsnull; if (wn->NeedsXOW()) { JSObject *innerWrappedObj = wrappedObj; OBJ_TO_INNER_OBJECT(cx, innerWrappedObj); if (!innerWrappedObj) { return JS_FALSE; } if (innerWrappedObj == parent) { wnxow = static_cast<XPCWrappedNativeWithXOW *>(wn); JSObject *xow = wnxow->GetXOW(); if (xow) { *vp = OBJECT_TO_JSVAL(xow); return JS_TRUE; } } } XPCWrappedNative *parentwn = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, parent); XPCWrappedNativeScope *parentScope; if (NS_LIKELY(parentwn)) { parentScope = parentwn->GetScope(); } else { parentScope = XPCWrappedNativeScope::FindInJSObjectScope(cx, parent); } JSObject *outerObj = nsnull; WrappedNative2WrapperMap *map = parentScope->GetWrapperMap(); outerObj = map->Find(wrappedObj); if (outerObj) { NS_ASSERTION(outerObj->getClass() == &XOWClass, "What crazy object are we getting here?"); *vp = OBJECT_TO_JSVAL(outerObj); if (wnxow) { // NB: wnxow->GetXOW() must have returned false. SetFlags(cx, outerObj, AddFlags(GetFlags(cx, outerObj), FLAG_IS_CACHED)); wnxow->SetXOW(outerObj); } return JS_TRUE; } outerObj = JS_NewObjectWithGivenProto(cx, js::Jsvalify(&XOWClass), nsnull, parent); if (!outerObj) { return JS_FALSE; } jsval flags = INT_TO_JSVAL(wnxow ? FLAG_IS_CACHED : 0); if (!JS_SetReservedSlot(cx, outerObj, sWrappedObjSlot, *vp) || !JS_SetReservedSlot(cx, outerObj, sFlagsSlot, flags) || !JS_SetReservedSlot(cx, outerObj, XPC_XOW_ScopeSlot, PRIVATE_TO_JSVAL(parentScope))) { return JS_FALSE; } *vp = OBJECT_TO_JSVAL(outerObj); map->Add(wn->GetScope()->GetWrapperMap(), wrappedObj, outerObj); if(wnxow) { wnxow->SetXOW(outerObj); } return JS_TRUE; }