예제 #1
0
void
Promise::Then(JSContext* aCx,
              // aCalleeGlobal may not be in the compartment of aCx, when called over
              // Xrays.
              JS::Handle<JSObject*> aCalleeGlobal,
              AnyCallback* aResolveCallback, AnyCallback* aRejectCallback,
              JS::MutableHandle<JS::Value> aRetval,
              ErrorResult& aRv)
{
  NS_ASSERT_OWNINGTHREAD(Promise);

  // Let's hope this does the right thing with Xrays...  Ensure everything is
  // just in the caller compartment; that ought to do the trick.  In theory we
  // should consider aCalleeGlobal, but in practice our only caller is
  // DOMRequest::Then, which is not working with a Promise subclass, so things
  // should be OK.
  JS::Rooted<JSObject*> promise(aCx, PromiseObj());
  if (!JS_WrapObject(aCx, &promise)) {
    aRv.NoteJSContextException(aCx);
    return;
  }

  JS::Rooted<JSObject*> resolveCallback(aCx);
  if (aResolveCallback) {
    resolveCallback = aResolveCallback->CallbackOrNull();
    if (!JS_WrapObject(aCx, &resolveCallback)) {
      aRv.NoteJSContextException(aCx);
      return;
    }
  }

  JS::Rooted<JSObject*> rejectCallback(aCx);
  if (aRejectCallback) {
    rejectCallback = aRejectCallback->CallbackOrNull();
    if (!JS_WrapObject(aCx, &rejectCallback)) {
      aRv.NoteJSContextException(aCx);
      return;
    }
  }

  JS::Rooted<JSObject*> retval(aCx);
  retval = JS::CallOriginalPromiseThen(aCx, promise, resolveCallback,
                                       rejectCallback);
  if (!retval) {
    aRv.NoteJSContextException(aCx);
    return;
  }

  aRetval.setObject(*retval);
}
예제 #2
0
bool
WrapperFactory::WaiveXrayAndWrap(JSContext *cx, MutableHandleObject argObj)
{
    MOZ_ASSERT(argObj);
    RootedObject obj(cx, js::UncheckedUnwrap(argObj));
    MOZ_ASSERT(!js::IsInnerObject(obj));
    if (js::IsObjectInContextCompartment(obj, cx)) {
        argObj.set(obj);
        return true;
    }

    // Even though waivers have no effect on access by scopes that don't subsume
    // the underlying object, good defense-in-depth dictates that we should avoid
    // handing out waivers to callers that can't use them. The transitive waiving
    // machinery unconditionally calls WaiveXrayAndWrap on return values from
    // waived functions, even though the return value might be not be same-origin
    // with the function. So if we find ourselves trying to create a waiver for
    // |cx|, we should check whether the caller has any business with waivers
    // to things in |obj|'s compartment.
    JSCompartment *target = js::GetContextCompartment(cx);
    JSCompartment *origin = js::GetObjectCompartment(obj);
    obj = AccessCheck::subsumes(target, origin) ? WaiveXray(cx, obj) : obj;
    if (!obj)
        return false;

    if (!JS_WrapObject(cx, &obj))
        return false;
    argObj.set(obj);
    return true;
}
예제 #3
0
void
WorkerDebuggerGlobalScope::CreateSandbox(JSContext* aCx, const nsAString& aName,
                                         JS::Handle<JSObject*> aPrototype,
                                         JS::MutableHandle<JSObject*> aResult,
                                         ErrorResult& aRv)
{
  mWorkerPrivate->AssertIsOnWorkerThread();

  aResult.set(nullptr);

  JS::Rooted<JS::Value> protoVal(aCx);
  protoVal.setObjectOrNull(aPrototype);
  JS::Rooted<JSObject*> sandbox(aCx,
    SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox,
                               protoVal));

  if (!sandbox) {
    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    return;
  }

  if (!JS_WrapObject(aCx, &sandbox)) {
    aRv.NoteJSContextException(aCx);
    return;
  }

  aResult.set(sandbox);
}
NS_IMETHODIMP
xpcJSWeakReference::Get(JSContext* aCx, JS::Value* aRetval)
{
    *aRetval = JSVAL_NULL;

    if (!mWrappedJSObject) {
        return NS_OK;
    }

    nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryReferent(mWrappedJSObject);
    if (!wrappedObj) {
        return NS_OK;
    }

    JSObject *obj;
    wrappedObj->GetJSObject(&obj);
    if (!obj) {
        return NS_OK;
    }

    // Most users of XPCWrappedJS don't need to worry about
    // re-wrapping because things are implicitly rewrapped by
    // xpcconvert. However, because we're doing this directly
    // through the native call context, we need to call
    // JS_WrapObject().
    if (!JS_WrapObject(aCx, &obj)) {
        return NS_ERROR_FAILURE;
    }

    *aRetval = OBJECT_TO_JSVAL(obj);
    return NS_OK;
}
예제 #5
0
static bool
bootstrap_coverage(GjsCoverage *coverage)
{
    GjsCoveragePrivate *priv = (GjsCoveragePrivate *) gjs_coverage_get_instance_private(coverage);

    JSContext *context = (JSContext *) gjs_context_get_native_context(priv->context);
    JSAutoRequest ar(context);

    JSObject *debuggee = gjs_get_import_global(context);
    JS::RootedObject debugger_compartment(context,
                                          gjs_create_global_object(context));
    {
        JSAutoCompartment compartment(context, debugger_compartment);
        JS::RootedObject debuggeeWrapper(context, debuggee);
        if (!JS_WrapObject(context, &debuggeeWrapper))
            return false;

        JS::RootedValue debuggeeWrapperValue(context, JS::ObjectValue(*debuggeeWrapper));
        if (!JS_SetProperty(context, debugger_compartment, "debuggee",
                            debuggeeWrapperValue) ||
            !gjs_define_global_properties(context, debugger_compartment,
                                          "coverage"))
            return false;

        /* Add a tracer, as suggested by jdm on #jsapi */
        JS_AddExtraGCRootsTracer(context, coverage_tracer, coverage);

        priv->compartment = debugger_compartment;
    }

    return true;
}
예제 #6
0
static JSObject*
GetDataStoresStructuredCloneCallbacksRead(JSContext* aCx,
                                          JSStructuredCloneReader* aReader,
                                          uint32_t aTag,
                                          uint32_t aData,
                                          void* aClosure)
{
  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
  MOZ_ASSERT(workerPrivate);
  workerPrivate->AssertIsOnWorkerThread();

  if (aTag != WORKER_DATA_STORES_TAG) {
    MOZ_ASSERT(false, "aTag must be WORKER_DATA_STORES_TAG!");
    return nullptr;
  }

  NS_ASSERTION(!aData, "aData should be empty");

  // Read the holder from the buffer, which points to the data store.
  nsMainThreadPtrHolder<DataStore>* dataStoreholder;
  if (!JS_ReadBytes(aReader, &dataStoreholder, sizeof(dataStoreholder))) {
    MOZ_ASSERT(false, "cannot read bytes for dataStoreholder!");
    return nullptr;
  }

  // Protect workerStoreObj from moving GC during ~nsRefPtr.
  JS::Rooted<JSObject*> workerStoreObj(aCx, nullptr);
  {
    nsRefPtr<WorkerDataStore> workerStore =
      new WorkerDataStore(workerPrivate->GlobalScope());
    nsMainThreadPtrHandle<DataStore> backingStore(dataStoreholder);

    // When we're on the worker thread, prepare a DataStoreChangeEventProxy.
    nsRefPtr<DataStoreChangeEventProxy> eventProxy =
      new DataStoreChangeEventProxy(workerPrivate, workerStore);

    // Add the DataStoreChangeEventProxy as an event listener on the main thread.
    nsRefPtr<DataStoreAddEventListenerRunnable> runnable =
      new DataStoreAddEventListenerRunnable(workerPrivate,
                                            backingStore,
                                            eventProxy);
    runnable->Dispatch(aCx);

    // Point WorkerDataStore to DataStore.
    workerStore->SetBackingDataStore(backingStore);

    JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
    if (!global) {
      MOZ_ASSERT(false, "cannot get global!");
    } else {
      workerStoreObj = workerStore->WrapObject(aCx);
      if (!JS_WrapObject(aCx, &workerStoreObj)) {
        MOZ_ASSERT(false, "cannot wrap object for workerStoreObj!");
        workerStoreObj = nullptr;
      }
    }
  }

  return workerStoreObj;
}
예제 #7
0
static JSObject*
wrap(JSContext* cx, JS::HandleObject toWrap, JS::HandleObject target)
{
    JSAutoCompartment ac(cx, target);
    JS::RootedObject wrapper(cx, toWrap);
    if (!JS_WrapObject(cx, &wrapper))
        return nullptr;
    return wrapper;
}
예제 #8
0
static JSObject *
wrap(JSContext *cx, JS::HandleObject toWrap, JS::HandleObject target)
{
    JSAutoCompartment ac(cx, target);
    JS::RootedObject wrapper(cx, toWrap);
    if (!JS_WrapObject(cx, wrapper.address()))
        return NULL;
    return wrapper;
}
예제 #9
0
static JSObject *
wrap(JSContext *cx, JSObject *toWrap, JSObject *target)
{
    JSAutoEnterCompartment ac;
    if (!ac.enter(cx, target))
        return NULL;

    JSObject *wrapper = toWrap;
    if (!JS_WrapObject(cx, &wrapper))
        return NULL;
    return wrapper;
}
예제 #10
0
JSObject *
WrapperFactory::WaiveXray(JSContext *cx, JSObject *obj)
{
    obj = UnwrapObject(obj);

    // We have to make sure that if we're wrapping an outer window, that
    // the .wrappedJSObject also wraps the outer window.
    obj = GetCurrentOuter(cx, obj);

    {
        // See if we already have a waiver wrapper for this object.
        CompartmentPrivate *priv =
            (CompartmentPrivate *)JS_GetCompartmentPrivate(js::GetObjectCompartment(obj));
        JSObject *wobj = nsnull;
        if (priv && priv->waiverWrapperMap) {
            wobj = priv->waiverWrapperMap->Find(obj);
            xpc_UnmarkGrayObject(wobj);
        }

        // No wrapper yet, make one.
        if (!wobj) {
            JSObject *proto = js::GetObjectProto(obj);
            if (proto && !(proto = WaiveXray(cx, proto)))
                return nsnull;

            JSAutoEnterCompartment ac;
            if (!ac.enter(cx, obj) || !JS_WrapObject(cx, &proto))
                return nsnull;
            wobj = Wrapper::New(cx, obj, proto, JS_GetGlobalForObject(cx, obj),
                                &WaiveXrayWrapperWrapper);
            if (!wobj)
                return nsnull;

            // Add the new wrapper so we find it next time.
            if (priv) {
                if (!priv->waiverWrapperMap) {
                    priv->waiverWrapperMap = JSObject2JSObjectMap::newMap(XPC_WRAPPER_MAP_SIZE);
                    if (!priv->waiverWrapperMap)
                        return nsnull;
                }
                if (!priv->waiverWrapperMap->Add(obj, wobj))
                    return nsnull;
            }
        }

        obj = wobj;
    }

    return obj;
}
예제 #11
0
NS_IMETHODIMP
xpcJSWeakReference::Get(JSContext* aCx, JS::Value* aRetval)
{
    *aRetval = JSVAL_NULL;

    if (!mReferent) {
        return NS_OK;
    }

    nsCOMPtr<nsISupports> supports = do_QueryReferent(mReferent);
    if (!supports) {
        return NS_OK;
    }

    nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(supports);
    if (!wrappedObj) {
        // We have a generic XPCOM object that supports weak references here.
        // Wrap it and pass it out.
        JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
        return nsContentUtils::WrapNative(aCx, global,
                                          supports, &NS_GET_IID(nsISupports),
                                          aRetval);
    }

    JS::RootedObject obj(aCx, wrappedObj->GetJSObject());
    if (!obj) {
        return NS_OK;
    }

    // Most users of XPCWrappedJS don't need to worry about
    // re-wrapping because things are implicitly rewrapped by
    // xpcconvert. However, because we're doing this directly
    // through the native call context, we need to call
    // JS_WrapObject().
    if (!JS_WrapObject(aCx, obj.address())) {
        return NS_ERROR_FAILURE;
    }

    *aRetval = OBJECT_TO_JSVAL(obj);
    return NS_OK;
}
예제 #12
0
JSObject* newCCW(JS::HandleObject sourceZone, JS::HandleObject destZone)
{
    /*
     * Now ensure that this zone will be swept first by adding a cross
     * compartment wrapper to a new objct in the same zone as the
     * delegate obejct.
     */
    JS::RootedObject object(cx);
    {
        JSAutoCompartment ac(cx, destZone);
        object = JS_NewPlainObject(cx);
        if (!object)
            return nullptr;
    }
    {
        JSAutoCompartment ac(cx, sourceZone);
        if (!JS_WrapObject(cx, &object))
            return nullptr;
    }
    return object;
}
예제 #13
0
// static
already_AddRefed<Promise>
Promise::All(const GlobalObject& aGlobal,
             const nsTArray<RefPtr<Promise>>& aPromiseList, ErrorResult& aRv)
{
  nsCOMPtr<nsIGlobalObject> global;
  global = do_QueryInterface(aGlobal.GetAsSupports());
  if (!global) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return nullptr;
  }

  JSContext* cx = aGlobal.Context();

  JS::AutoObjectVector promises(cx);
  if (!promises.reserve(aPromiseList.Length())) {
    aRv.NoteJSContextException(cx);
    return nullptr;
  }

  for (auto& promise : aPromiseList) {
    JS::Rooted<JSObject*> promiseObj(cx, promise->PromiseObj());
    // Just in case, make sure these are all in the context compartment.
    if (!JS_WrapObject(cx, &promiseObj)) {
      aRv.NoteJSContextException(cx);
      return nullptr;
    }
    promises.infallibleAppend(promiseObj);
  }

  JS::Rooted<JSObject*> result(cx, JS::GetWaitForAllPromise(cx, promises));
  if (!result) {
    aRv.NoteJSContextException(cx);
    return nullptr;
  }

  return CreateFromExisting(global, result);
}
예제 #14
0
nsresult
nsXBLProtoImplMethod::InstallMember(JSContext* aCx,
                                    JSObject* aTargetClassObject)
{
  NS_PRECONDITION(IsCompiled(),
                  "Should not be installing an uncompiled method");
  MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));

  JSObject* globalObject = JS_GetGlobalForObject(aCx, aTargetClassObject);
  JSObject* scopeObject = xpc::GetXBLScope(aCx, globalObject);

  // now we want to reevaluate our property using aContext and the script object for this window...
  if (mJSMethodObject) {
    nsDependentString name(mName);

    // First, make the function in the compartment of the scope object.
    JSAutoCompartment ac(aCx, scopeObject);
    JSObject * method = ::JS_CloneFunctionObject(aCx, mJSMethodObject, scopeObject);
    if (!method) {
      return NS_ERROR_OUT_OF_MEMORY;
    }

    // Then, enter the content compartment, wrap the method pointer, and define
    // the wrapped version on the class object.
    JSAutoCompartment ac2(aCx, aTargetClassObject);
    if (!JS_WrapObject(aCx, &method) ||
        !::JS_DefineUCProperty(aCx, aTargetClassObject,
                               static_cast<const jschar*>(mName),
                               name.Length(), OBJECT_TO_JSVAL(method),
                               NULL, NULL,
                               JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
      return NS_ERROR_OUT_OF_MEMORY;
    }
  }
  return NS_OK;
}
예제 #15
0
JSObject *
WrapperFactory::CreateXrayWaiver(JSContext *cx, HandleObject obj)
{
    // The caller is required to have already done a lookup.
    // NB: This implictly performs the assertions of GetXrayWaiver.
    MOZ_ASSERT(!GetXrayWaiver(obj));
    XPCWrappedNativeScope *scope = GetObjectScope(obj);

    // Get a waiver for the proto.
    JSObject *proto;
    if (!js::GetObjectProto(cx, obj, &proto))
        return nullptr;
    if (proto && !(proto = WaiveXray(cx, proto)))
        return nullptr;

    // Create the waiver.
    JSAutoCompartment ac(cx, obj);
    if (!JS_WrapObject(cx, &proto))
        return nullptr;
    JSObject *waiver = Wrapper::New(cx, obj, proto,
                                    JS_GetGlobalForObject(cx, obj),
                                    &XrayWaiver);
    if (!waiver)
        return nullptr;

    // Add the new waiver to the map. It's important that we only ever have
    // one waiver for the lifetime of the target object.
    if (!scope->mWaiverWrapperMap) {
        scope->mWaiverWrapperMap =
          JSObject2JSObjectMap::newMap(XPC_WRAPPER_MAP_SIZE);
        MOZ_ASSERT(scope->mWaiverWrapperMap);
    }
    if (!scope->mWaiverWrapperMap->Add(obj, waiver))
        return nullptr;
    return waiver;
}
예제 #16
0
nsresult
nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
{
  NS_PRECONDITION(IsCompiled(), "Can't execute uncompiled method");
  
  if (!mJSMethodObject) {
    // Nothing to do here
    return NS_OK;
  }

  // Get the script context the same way
  // nsXBLProtoImpl::InstallImplementation does.
  nsIDocument* document = aBoundElement->OwnerDoc();

  nsIScriptGlobalObject* global = document->GetScriptGlobalObject();
  if (!global) {
    return NS_OK;
  }

  nsCOMPtr<nsIScriptContext> context = global->GetContext();
  if (!context) {
    return NS_OK;
  }

  nsAutoMicroTask mt;

  JSContext* cx = context->GetNativeContext();

  JSObject* globalObject = global->GetGlobalJSObject();

  nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
  jsval v;
  nsresult rv =
    nsContentUtils::WrapNative(cx, globalObject, aBoundElement, &v,
                               getter_AddRefs(wrapper));
  NS_ENSURE_SUCCESS(rv, rv);

  // Use nsCxPusher to make sure we call ScriptEvaluated when we're done.
  //
  // Make sure to do this before entering the compartment, since pushing Push()
  // may call JS_SaveFrameChain(), which puts us back in an unentered state.
  nsCxPusher pusher;
  NS_ENSURE_STATE(pusher.Push(aBoundElement));
  MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());

  JSObject* thisObject = JSVAL_TO_OBJECT(v);
  JSObject* scopeObject = xpc::GetXBLScope(cx, globalObject);

  JSAutoRequest ar(cx);
  JSAutoCompartment ac(cx, scopeObject);
  if (!JS_WrapObject(cx, &thisObject))
      return NS_ERROR_OUT_OF_MEMORY;

  // Clone the function object, using thisObject as the parent so "this" is in
  // the scope chain of the resulting function (for backwards compat to the
  // days when this was an event handler).
  JSObject* method = ::JS_CloneFunctionObject(cx, mJSMethodObject, thisObject);
  if (!method)
    return NS_ERROR_OUT_OF_MEMORY;

  // Now call the method

  // Check whether it's OK to call the method.
  rv = nsContentUtils::GetSecurityManager()->CheckFunctionAccess(cx, method,
                                                                 thisObject);

  JSBool ok = JS_TRUE;
  if (NS_SUCCEEDED(rv)) {
    jsval retval;
    ok = ::JS_CallFunctionValue(cx, thisObject, OBJECT_TO_JSVAL(method),
                                0 /* argc */, nullptr /* argv */, &retval);
  }

  if (!ok) {
    // If a constructor or destructor threw an exception, it doesn't stop
    // anything else.  We just report it.  Note that we need to set aside the
    // frame chain here, since the constructor invocation is not related to
    // whatever is on the stack right now, really.
    JSBool saved = JS_SaveFrameChain(cx);
    JS_ReportPendingException(cx);
    if (saved)
        JS_RestoreFrameChain(cx);
    return NS_ERROR_FAILURE;
  }

  return NS_OK;
}
예제 #17
0
// static
JSObject*
SimpleGlobalObject::Create(GlobalType globalType, JS::Handle<JS::Value> proto)
{
    // We can't root our return value with our AutoJSAPI because the rooting
    // analysis thinks ~AutoJSAPI can GC.  So we need to root in a scope outside
    // the lifetime of the AutoJSAPI.
    JS::Rooted<JSObject*> global(RootingCx());

    {   // Scope to ensure the AutoJSAPI destructor runs before we end up returning
        AutoJSAPI jsapi;
        jsapi.Init();
        JSContext* cx = jsapi.cx();

        JS::CompartmentOptions options;
        options.creationOptions()
        .setInvisibleToDebugger(true)
        // Put our SimpleGlobalObjects in the system zone, so we won't create
        // lots of zones for what are probably very short-lived
        // compartments.  This should help them be GCed quicker and take up
        // less memory before they're GCed.
        .setZone(JS::SystemZone);

        if (NS_IsMainThread()) {
            nsCOMPtr<nsIPrincipal> principal = nsNullPrincipal::Create();
            options.creationOptions().setTrace(xpc::TraceXPCGlobal);
            global = xpc::CreateGlobalObject(cx, js::Jsvalify(&SimpleGlobalClass),
                                             nsJSPrincipals::get(principal),
                                             options);
        } else {
            global = JS_NewGlobalObject(cx, js::Jsvalify(&SimpleGlobalClass),
                                        nullptr,
                                        JS::DontFireOnNewGlobalHook, options);
        }

        if (!global) {
            jsapi.ClearException();
            return nullptr;
        }

        JSAutoCompartment ac(cx, global);

        // It's important to create the nsIGlobalObject for our new global before we
        // start trying to wrap things like the prototype into its compartment,
        // because the wrap operation relies on the global having its
        // nsIGlobalObject already.
        RefPtr<SimpleGlobalObject> globalObject =
            new SimpleGlobalObject(global, globalType);

        // Pass on ownership of globalObject to |global|.
        JS_SetPrivate(global, globalObject.forget().take());

        if (proto.isObjectOrNull()) {
            JS::Rooted<JSObject*> protoObj(cx, proto.toObjectOrNull());
            if (!JS_WrapObject(cx, &protoObj)) {
                jsapi.ClearException();
                return nullptr;
            }

            if (!JS_SplicePrototype(cx, global, protoObj)) {
                jsapi.ClearException();
                return nullptr;
            }
        } else if (!proto.isUndefined()) {
            // Bogus proto.
            return nullptr;
        }

        JS_FireOnNewGlobalObject(cx, global);
    }

    return global;
}
예제 #18
0
/* static */
bool WebIDLGlobalNameHash::DefineIfEnabled(
    JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aId,
    JS::MutableHandle<JS::PropertyDescriptor> aDesc, bool* aFound) {
  MOZ_ASSERT(JSID_IS_STRING(aId), "Check for string id before calling this!");

  const WebIDLNameTableEntry* entry;
  { entry = GetEntry(JSID_TO_FLAT_STRING(aId)); }

  if (!entry) {
    *aFound = false;
    return true;
  }

  *aFound = true;

  ConstructorEnabled checkEnabledForScope = entry->mEnabled;
  // We do the enabled check on the current Realm of aCx, but for the
  // actual object we pass in the underlying object in the Xray case.  That
  // way the callee can decide whether to allow access based on the caller
  // or the window being touched.
  //
  // Using aCx to represent the current Realm for CheckedUnwrapDynamic
  // purposes is OK here, because that's the Realm where we plan to do
  // our property-defining.
  JS::Rooted<JSObject*> global(
      aCx,
      js::CheckedUnwrapDynamic(aObj, aCx, /* stopAtWindowProxy = */ false));
  if (!global) {
    return Throw(aCx, NS_ERROR_DOM_SECURITY_ERR);
  }

  {
    // It's safe to pass "&global" here, because we've already unwrapped it, but
    // for general sanity better to not have debug code even having the
    // appearance of mutating things that opt code uses.
#ifdef DEBUG
    JS::Rooted<JSObject*> temp(aCx, global);
    DebugOnly<nsGlobalWindowInner*> win;
    MOZ_ASSERT(NS_SUCCEEDED(
        UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT(Window, &temp, win, aCx)));
#endif
  }

  if (checkEnabledForScope && !checkEnabledForScope(aCx, global)) {
    return true;
  }

  // The DOM constructor resolve machinery interacts with Xrays in tricky
  // ways, and there are some asymmetries that are important to understand.
  //
  // In the regular (non-Xray) case, we only want to resolve constructors
  // once (so that if they're deleted, they don't reappear). We do this by
  // stashing the constructor in a slot on the global, such that we can see
  // during resolve whether we've created it already. This is rather
  // memory-intensive, so we don't try to maintain these semantics when
  // manipulating a global over Xray (so the properties just re-resolve if
  // they've been deleted).
  //
  // Unfortunately, there's a bit of an impedance-mismatch between the Xray
  // and non-Xray machinery. The Xray machinery wants an API that returns a
  // JS::PropertyDescriptor, so that the resolve hook doesn't have to get
  // snared up with trying to define a property on the Xray holder. At the
  // same time, the DefineInterface callbacks are set up to define things
  // directly on the global.  And re-jiggering them to return property
  // descriptors is tricky, because some DefineInterface callbacks define
  // multiple things (like the Image() alias for HTMLImageElement).
  //
  // So the setup is as-follows:
  //
  // * The resolve function takes a JS::PropertyDescriptor, but in the
  //   non-Xray case, callees may define things directly on the global, and
  //   set the value on the property descriptor to |undefined| to indicate
  //   that there's nothing more for the caller to do. We assert against
  //   this behavior in the Xray case.
  //
  // * We make sure that we do a non-Xray resolve first, so that all the
  //   slots are set up. In the Xray case, this means unwrapping and doing
  //   a non-Xray resolve before doing the Xray resolve.
  //
  // This all could use some grand refactoring, but for now we just limp
  // along.
  if (xpc::WrapperFactory::IsXrayWrapper(aObj)) {
    JS::Rooted<JSObject*> constructor(aCx);
    {
      JSAutoRealm ar(aCx, global);
      constructor = FindNamedConstructorForXray(aCx, aId, entry);
    }
    if (NS_WARN_IF(!constructor)) {
      return Throw(aCx, NS_ERROR_FAILURE);
    }
    if (!JS_WrapObject(aCx, &constructor)) {
      return Throw(aCx, NS_ERROR_FAILURE);
    }

    FillPropertyDescriptor(aDesc, aObj, 0, JS::ObjectValue(*constructor));
    return true;
  }

  JS::Rooted<JSObject*> interfaceObject(
      aCx,
      GetPerInterfaceObjectHandle(aCx, entry->mConstructorId, entry->mCreate,
                                  /* aDefineOnGlobal = */ true));
  if (NS_WARN_IF(!interfaceObject)) {
    return Throw(aCx, NS_ERROR_FAILURE);
  }

  // We've already defined the property.  We indicate this to the caller
  // by filling a property descriptor with JS::UndefinedValue() as the
  // value.  We still have to fill in a property descriptor, though, so
  // that the caller knows the property is in fact on this object.  It
  // doesn't matter what we pass for the "readonly" argument here.
  FillPropertyDescriptor(aDesc, aObj, JS::UndefinedValue(), false);

  return true;
}