// static JSObject* DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj) { MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object"); JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO); if (v.isUndefined()) { return nullptr; } if (v.isObject()) { js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, UndefinedValue()); xpc::GetObjectScope(obj)->RemoveDOMExpandoObject(obj); } else { js::ExpandoAndGeneration* expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); v = expandoAndGeneration->expando; if (v.isUndefined()) { return nullptr; } expandoAndGeneration->expando = UndefinedValue(); } return &v.toObject(); }
void HostReleaseTopLevelScript(const JS::Value& aPrivate) { // Decrement the reference count of a LoadedScript object that was pointed to // by a JSScript. The reference count was originally incremented by // HostAddRefTopLevelScript() above. auto script = static_cast<LoadedScript*>(aPrivate.toPrivate()); CheckModuleScriptPrivate(script, aPrivate); script->Release(); }
/** * Extract the FinalizationEvent from an instance of FinalizationWitness * and clear the slot containing the FinalizationEvent. */ already_AddRefed<FinalizationEvent> ExtractFinalizationEvent(JSObject *objSelf) { JS::Value slotEvent = JS_GetReservedSlot(objSelf, WITNESS_SLOT_EVENT); if (slotEvent.isUndefined()) { // Forget() has been called return nullptr; } JS_SetReservedSlot(objSelf, WITNESS_SLOT_EVENT, JS::UndefinedValue()); return dont_AddRef(static_cast<FinalizationEvent*>(slotEvent.toPrivate())); }
void ShadowingDOMProxyHandler::trace(JSTracer* trc, JSObject* proxy) const { DOMProxyHandler::trace(trc, proxy); MOZ_ASSERT(IsDOMProxy(proxy), "expected a DOM proxy object"); JS::Value v = js::GetProxyPrivate(proxy); MOZ_ASSERT(!v.isObject(), "Should not have expando object directly!"); // The proxy's private slot is set when we allocate the proxy, // so it cannot be |undefined|. MOZ_ASSERT(!v.isUndefined()); js::ExpandoAndGeneration* expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); JS::TraceEdge(trc, &expandoAndGeneration->expando, "Shadowing DOM proxy expando"); }
// static JSObject* DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JS::Handle<JSObject*> obj) { NS_ASSERTION(IsDOMProxy(obj), "expected a DOM proxy object"); JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO); if (v.isObject()) { return &v.toObject(); } js::ExpandoAndGeneration* expandoAndGeneration; if (!v.isUndefined()) { expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); if (expandoAndGeneration->expando.isObject()) { return &expandoAndGeneration->expando.toObject(); } } else { expandoAndGeneration = nullptr; } JS::Rooted<JSObject*> expando(cx, JS_NewObjectWithGivenProto(cx, nullptr, nullptr, js::GetObjectParent(obj))); if (!expando) { return nullptr; } nsISupports* native = UnwrapDOMObject<nsISupports>(obj); nsWrapperCache* cache; CallQueryInterface(native, &cache); if (expandoAndGeneration) { cache->PreserveWrapper(native); expandoAndGeneration->expando.setObject(*expando); return expando; } XPCWrappedNativeScope* scope = xpc::GetObjectScope(obj); if (!scope->RegisterDOMExpandoObject(obj)) { return nullptr; } cache->SetPreservingWrapper(true); js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando)); return expando; }
//static JSObject * DOMProxyHandler::GetExpandoObject(JSObject *obj) { MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object"); JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO); if (v.isObject()) { return &v.toObject(); } if (v.isUndefined()) { return nullptr; } js::ExpandoAndGeneration* expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); v = expandoAndGeneration->expando; return v.isUndefined() ? nullptr : &v.toObject(); }
// static JSObject* DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JS::Handle<JSObject*> obj) { CheckDOMProxy(obj); JS::Value v = js::GetProxyPrivate(obj); if (v.isObject()) { CheckExpandoObject(obj, v); return &v.toObject(); } js::ExpandoAndGeneration* expandoAndGeneration; if (!v.isUndefined()) { expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); CheckExpandoAndGeneration(obj, expandoAndGeneration); if (expandoAndGeneration->expando.isObject()) { return &expandoAndGeneration->expando.toObject(); } } else { expandoAndGeneration = nullptr; } JS::Rooted<JSObject*> expando( cx, JS_NewObjectWithGivenProto(cx, nullptr, nullptr)); if (!expando) { return nullptr; } nsISupports* native = UnwrapDOMObject<nsISupports>(obj); nsWrapperCache* cache; CallQueryInterface(native, &cache); cache->PreserveWrapper(native); if (expandoAndGeneration) { expandoAndGeneration->expando.setObject(*expando); return expando; } js::SetProxyPrivate(obj, ObjectValue(*expando)); return expando; }
// static JSObject* DOMProxyHandler::GetExpandoObject(JSObject* obj) { CheckDOMProxy(obj); JS::Value v = js::GetProxyPrivate(obj); if (v.isObject()) { CheckExpandoObject(obj, v); return &v.toObject(); } if (v.isUndefined()) { return nullptr; } js::ExpandoAndGeneration* expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); CheckExpandoAndGeneration(obj, expandoAndGeneration); v = expandoAndGeneration->expando; return v.isUndefined() ? nullptr : &v.toObject(); }
// static JSObject* DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj) { MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object"); JS::Value v = js::GetProxyPrivate(obj); if (v.isUndefined()) { return nullptr; } if (v.isObject()) { js::SetProxyPrivate(obj, UndefinedValue()); } else { js::ExpandoAndGeneration* expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); v = expandoAndGeneration->expando; if (v.isUndefined()) { return nullptr; } // We have to expose v to active JS here. The reason for that is that we // might be in the middle of a GC right now. If our proxy hasn't been // traced yet, when it _does_ get traced it won't trace the expando, since // we're breaking that link. But the Rooted we're presumably being placed // into is also not going to trace us, because Rooted marking is done at // the very beginning of the GC. In that situation, we need to manually // mark the expando as live here. JS::ExposeValueToActiveJS will do just // that for us. // // We don't need to do this in the non-expandoAndGeneration case, because // in that case our value is stored in a slot and slots will already mark // the old thing live when the value in the slot changes. JS::ExposeValueToActiveJS(v); expandoAndGeneration->expando = UndefinedValue(); } return &v.toObject(); }
// static JSObject* DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj) { CheckDOMProxy(obj); JS::Value v = js::GetProxyPrivate(obj); if (v.isUndefined()) { return nullptr; } if (v.isObject()) { js::SetProxyPrivate(obj, UndefinedValue()); } else { js::ExpandoAndGeneration* expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); v = expandoAndGeneration->expando; if (v.isUndefined()) { return nullptr; } expandoAndGeneration->expando = UndefinedValue(); } CheckExpandoObject(obj, v); return &v.toObject(); }
// Define a shadowing property on |this| for the XBL field defined by the // contents of the callee's reserved slots. If the property was defined, // *installed will be true, and idp will be set to the property name that was // defined. static bool InstallXBLField(JSContext* cx, JS::Handle<JSObject*> callee, JS::Handle<JSObject*> thisObj, JS::MutableHandle<jsid> idp, bool* installed) { *installed = false; // First ensure |this| is a reasonable XBL bound node. // // FieldAccessorGuard already determined whether |thisObj| was acceptable as // |this| in terms of not throwing a TypeError. Assert this for good measure. MOZ_ASSERT(ValueHasISupportsPrivate(JS::ObjectValue(*thisObj))); // But there are some cases where we must accept |thisObj| but not install a // property on it, or otherwise touch it. Hence this split of |this|-vetting // duties. nsISupports* native = nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, thisObj); if (!native) { // Looks like whatever |thisObj| is it's not our nsIContent. It might well // be the proto our binding installed, however, where the private is the // nsXBLDocumentInfo, so just baul out quietly. Do NOT throw an exception // here. // // We could make this stricter by checking the class maybe, but whatever. return true; } nsCOMPtr<nsIContent> xblNode = do_QueryInterface(native); if (!xblNode) { xpc::Throw(cx, NS_ERROR_UNEXPECTED); return false; } // Now that |this| is okay, actually install the field. // Because of the possibility (due to XBL binding inheritance, because each // XBL binding lives in its own global object) that |this| might be in a // different compartment from the callee (not to mention that this method can // be called with an arbitrary |this| regardless of how insane XBL is), and // because in this method we've entered |this|'s compartment (see in // Field[GS]etter where we attempt a cross-compartment call), we must enter // the callee's compartment to access its reserved slots. nsXBLPrototypeBinding* protoBinding; nsDependentJSString fieldName; { JSAutoCompartment ac(cx, callee); JS::Rooted<JSObject*> xblProto(cx); xblProto = &js::GetFunctionNativeReserved(callee, XBLPROTO_SLOT).toObject(); JS::Rooted<JS::Value> name(cx, js::GetFunctionNativeReserved(callee, FIELD_SLOT)); JSFlatString* fieldStr = JS_ASSERT_STRING_IS_FLAT(name.toString()); fieldName.init(fieldStr); MOZ_ALWAYS_TRUE(JS_ValueToId(cx, name, idp.address())); // If a separate XBL scope is being used, the callee is not same-compartment // with the xbl prototype, and the object is a cross-compartment wrapper. xblProto = js::UncheckedUnwrap(xblProto); JSAutoCompartment ac2(cx, xblProto); JS::Value slotVal = ::JS_GetReservedSlot(xblProto, 0); protoBinding = static_cast<nsXBLPrototypeBinding*>(slotVal.toPrivate()); MOZ_ASSERT(protoBinding); } nsXBLProtoImplField* field = protoBinding->FindField(fieldName); MOZ_ASSERT(field); // This mirrors code in nsXBLProtoImpl::InstallImplementation nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(xblNode->OwnerDoc()->GetWindow()); if (!global) { return true; } nsCOMPtr<nsIScriptContext> context = global->GetContext(); if (!context) { return true; } nsresult rv = field->InstallField(context, thisObj, protoBinding->DocURI(), installed); if (NS_SUCCEEDED(rv)) { return true; } if (!::JS_IsExceptionPending(cx)) { xpc::Throw(cx, rv); } return false; }