/* THIS FILE IS AUTOGENERATED FROM AddonManager.webidl BY Codegen.py - DO NOT EDIT */

#include <type_traits>
#include "AddonManagerBinding.h"
#include "AtomList.h"
#include "EventTargetBinding.h"
#include "MainThreadUtils.h"
#include "WrapperFactory.h"
#include "js/CallAndConstruct.h"
#include "js/Exception.h"
#include "js/MapAndSet.h"
#include "js/Object.h"
#include "js/PropertyAndElement.h"
#include "js/PropertyDescriptor.h"
#include "js/experimental/JitInfo.h"
#include "mozilla/AddonManagerWebAPI.h"
#include "mozilla/Atomics.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/ProfilerLabels.h"
#include "mozilla/dom/BindingCallContext.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/DOMJSClass.h"
#include "mozilla/dom/NonRefcountedDOMObject.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/dom/PrimitiveConversions.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/SimpleGlobalObject.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/XrayExpandoClass.h"
#include "nsContentUtils.h"
#include "nsIGlobalObject.h"

namespace mozilla::dom {

namespace binding_detail {}; // Just to make sure it's known as a namespace
using namespace mozilla::dom::binding_detail;



addonInstallOptions::addonInstallOptions()
{
  // Safe to pass a null context if we pass a null value
  Init(nullptr, JS::NullHandleValue);
}




bool
addonInstallOptions::InitIds(JSContext* cx, addonInstallOptionsAtoms* atomsCache)
{
  MOZ_ASSERT(reinterpret_cast<jsid*>(atomsCache)->isVoid());

  // Initialize these in reverse order so that any failure leaves the first one
  // uninitialized.
  if (!atomsCache->url_id.init(cx, "url") ||
      !atomsCache->hash_id.init(cx, "hash")) {
    return false;
  }
  return true;
}

bool
addonInstallOptions::Init(BindingCallContext& cx, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
{
  // Passing a null JSContext is OK only if we're initing from null,
  // Since in that case we will not have to do any property gets
  // Also evaluate isNullOrUndefined in order to avoid false-positive
  // checkers by static analysis tools
  MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
  addonInstallOptionsAtoms* atomsCache = nullptr;
  if (cx) {
    atomsCache = GetAtomCache<addonInstallOptionsAtoms>(cx);
    if (reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
        !InitIds(cx, atomsCache)) {
      return false;
    }
  }

  if (!IsConvertibleToDictionary(val)) {
    return cx.ThrowErrorMessage<MSG_CONVERSION_ERROR>(sourceDescription, "dictionary");
  }

  bool isNull = val.isNullOrUndefined();
  // We only need these if !isNull, in which case we have |cx|.
  Maybe<JS::Rooted<JSObject *> > object;
  Maybe<JS::Rooted<JS::Value> > temp;
  if (!isNull) {
    MOZ_ASSERT(cx);
    object.emplace(cx, &val.toObject());
    temp.emplace(cx);
  }
  if (!isNull) {
    if (!JS_GetPropertyById(cx, *object, atomsCache->hash_id, temp.ptr())) {
      return false;
    }
  }
  if (!isNull && !temp->isUndefined()) {
    if (!ConvertJSValueToString(cx, temp.ref(), eNull, eNull, mHash)) {
      return false;
    }
  } else {
    mHash.SetIsVoid(true);
  }
  mIsAnyMemberPresent = true;

  if (!isNull) {
    if (!JS_GetPropertyById(cx, *object, atomsCache->url_id, temp.ptr())) {
      return false;
    }
  }
  if (!isNull && !temp->isUndefined()) {
    if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, mUrl)) {
      return false;
    }
    mIsAnyMemberPresent = true;
  } else if (cx) {
    // Don't error out if we have no cx.  In that
    // situation the caller is default-constructing us and we'll
    // just assume they know what they're doing.
    return cx.ThrowErrorMessage<MSG_MISSING_REQUIRED_DICTIONARY_MEMBER>("'url' member of addonInstallOptions");
  }
  return true;
}

bool
addonInstallOptions::Init(JSContext* cx_, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
{
  // We don't want to use sourceDescription for our context here;
  // that's not really what it's formatted for.
  BindingCallContext cx(cx_, nullptr);
  return Init(cx, val, sourceDescription, passedToJSImpl);
}

bool
addonInstallOptions::ToObjectInternal(JSContext* cx, JS::MutableHandle<JS::Value> rval) const
{
  addonInstallOptionsAtoms* atomsCache = GetAtomCache<addonInstallOptionsAtoms>(cx);
  if (reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
      !InitIds(cx, atomsCache)) {
    return false;
  }

  JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
  if (!obj) {
    return false;
  }
  rval.set(JS::ObjectValue(*obj));

  do {
    // block for our 'break' successCode and scope for 'temp' and 'currentValue'
    JS::Rooted<JS::Value> temp(cx);
    nsString const & currentValue = mHash;
    if (!xpc::StringToJsval(cx, currentValue, &temp)) {
      return false;
    }
    if (!JS_DefinePropertyById(cx, obj, atomsCache->hash_id, temp, JSPROP_ENUMERATE)) {
      return false;
    }
    break;
  } while(false);

  do {
    // block for our 'break' successCode and scope for 'temp' and 'currentValue'
    JS::Rooted<JS::Value> temp(cx);
    nsString const & currentValue = mUrl;
    if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
      return false;
    }
    if (!JS_DefinePropertyById(cx, obj, atomsCache->url_id, temp, JSPROP_ENUMERATE)) {
      return false;
    }
    break;
  } while(false);

  return true;
}

void
addonInstallOptions::TraceDictionary(JSTracer* trc)
{
}

addonInstallOptions&
addonInstallOptions::operator=(const addonInstallOptions& aOther)
{
  DictionaryBase::operator=(aOther);
  mHash = aOther.mHash;
  mUrl = aOther.mUrl;
  return *this;
}



sendAbuseReportOptions::sendAbuseReportOptions()
{
  // Safe to pass a null context if we pass a null value
  Init(nullptr, JS::NullHandleValue);
}




bool
sendAbuseReportOptions::InitIds(JSContext* cx, sendAbuseReportOptionsAtoms* atomsCache)
{
  MOZ_ASSERT(reinterpret_cast<jsid*>(atomsCache)->isVoid());

  // Initialize these in reverse order so that any failure leaves the first one
  // uninitialized.
  if (!atomsCache->authorization_id.init(cx, "authorization")) {
    return false;
  }
  return true;
}

bool
sendAbuseReportOptions::Init(BindingCallContext& cx, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
{
  // Passing a null JSContext is OK only if we're initing from null,
  // Since in that case we will not have to do any property gets
  // Also evaluate isNullOrUndefined in order to avoid false-positive
  // checkers by static analysis tools
  MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
  sendAbuseReportOptionsAtoms* atomsCache = nullptr;
  if (cx) {
    atomsCache = GetAtomCache<sendAbuseReportOptionsAtoms>(cx);
    if (reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
        !InitIds(cx, atomsCache)) {
      return false;
    }
  }

  if (!IsConvertibleToDictionary(val)) {
    return cx.ThrowErrorMessage<MSG_CONVERSION_ERROR>(sourceDescription, "dictionary");
  }

  bool isNull = val.isNullOrUndefined();
  // We only need these if !isNull, in which case we have |cx|.
  Maybe<JS::Rooted<JSObject *> > object;
  Maybe<JS::Rooted<JS::Value> > temp;
  if (!isNull) {
    MOZ_ASSERT(cx);
    object.emplace(cx, &val.toObject());
    temp.emplace(cx);
  }
  if (!isNull) {
    if (!JS_GetPropertyById(cx, *object, atomsCache->authorization_id, temp.ptr())) {
      return false;
    }
  }
  if (!isNull && !temp->isUndefined()) {
    if (!ConvertJSValueToString(cx, temp.ref(), eNull, eNull, mAuthorization)) {
      return false;
    }
  } else {
    mAuthorization.SetIsVoid(true);
  }
  mIsAnyMemberPresent = true;
  return true;
}

bool
sendAbuseReportOptions::Init(JSContext* cx_, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
{
  // We don't want to use sourceDescription for our context here;
  // that's not really what it's formatted for.
  BindingCallContext cx(cx_, nullptr);
  return Init(cx, val, sourceDescription, passedToJSImpl);
}

bool
sendAbuseReportOptions::ToObjectInternal(JSContext* cx, JS::MutableHandle<JS::Value> rval) const
{
  sendAbuseReportOptionsAtoms* atomsCache = GetAtomCache<sendAbuseReportOptionsAtoms>(cx);
  if (reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
      !InitIds(cx, atomsCache)) {
    return false;
  }

  JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
  if (!obj) {
    return false;
  }
  rval.set(JS::ObjectValue(*obj));

  do {
    // block for our 'break' successCode and scope for 'temp' and 'currentValue'
    JS::Rooted<JS::Value> temp(cx);
    nsString const & currentValue = mAuthorization;
    if (!xpc::StringToJsval(cx, currentValue, &temp)) {
      return false;
    }
    if (!JS_DefinePropertyById(cx, obj, atomsCache->authorization_id, temp, JSPROP_ENUMERATE)) {
      return false;
    }
    break;
  } while(false);

  return true;
}

void
sendAbuseReportOptions::TraceDictionary(JSTracer* trc)
{
}

sendAbuseReportOptions&
sendAbuseReportOptions::operator=(const sendAbuseReportOptions& aOther)
{
  DictionaryBase::operator=(aOther);
  mAuthorization = aOther.mAuthorization;
  return *this;
}


namespace Addon_Binding {

MOZ_CAN_RUN_SCRIPT static bool
get_id(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, JSJitGetterCallArgs args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "Addon", "id", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::Addon*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  DOMString result;
  // NOTE: This assert does NOT call the function.
  static_assert(std::is_void_v<decltype(MOZ_KnownLive(self)->GetId(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))))>, "Should be returning void here");
  MOZ_KnownLive(self)->GetId(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "Addon.id getter"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) {
    return false;
  }
  return true;
}

static const JSJitInfo id_getterinfo = {
  { get_id },
  { prototypes::id::Addon },
  { PrototypeTraits<prototypes::id::Addon>::Depth },
  JSJitInfo::Getter,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_STRING,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
get_version(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, JSJitGetterCallArgs args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "Addon", "version", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::Addon*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  DOMString result;
  // NOTE: This assert does NOT call the function.
  static_assert(std::is_void_v<decltype(MOZ_KnownLive(self)->GetVersion(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))))>, "Should be returning void here");
  MOZ_KnownLive(self)->GetVersion(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "Addon.version getter"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) {
    return false;
  }
  return true;
}

static const JSJitInfo version_getterinfo = {
  { get_version },
  { prototypes::id::Addon },
  { PrototypeTraits<prototypes::id::Addon>::Depth },
  JSJitInfo::Getter,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_STRING,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
get_type(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, JSJitGetterCallArgs args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "Addon", "type", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::Addon*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  DOMString result;
  // NOTE: This assert does NOT call the function.
  static_assert(std::is_void_v<decltype(MOZ_KnownLive(self)->GetType(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))))>, "Should be returning void here");
  MOZ_KnownLive(self)->GetType(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "Addon.type getter"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) {
    return false;
  }
  return true;
}

static const JSJitInfo type_getterinfo = {
  { get_type },
  { prototypes::id::Addon },
  { PrototypeTraits<prototypes::id::Addon>::Depth },
  JSJitInfo::Getter,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_STRING,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
get_name(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, JSJitGetterCallArgs args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "Addon", "name", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::Addon*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  DOMString result;
  // NOTE: This assert does NOT call the function.
  static_assert(std::is_void_v<decltype(MOZ_KnownLive(self)->GetName(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))))>, "Should be returning void here");
  MOZ_KnownLive(self)->GetName(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "Addon.name getter"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) {
    return false;
  }
  return true;
}

static const JSJitInfo name_getterinfo = {
  { get_name },
  { prototypes::id::Addon },
  { PrototypeTraits<prototypes::id::Addon>::Depth },
  JSJitInfo::Getter,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_STRING,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
get_description(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, JSJitGetterCallArgs args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "Addon", "description", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::Addon*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  DOMString result;
  // NOTE: This assert does NOT call the function.
  static_assert(std::is_void_v<decltype(MOZ_KnownLive(self)->GetDescription(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))))>, "Should be returning void here");
  MOZ_KnownLive(self)->GetDescription(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "Addon.description getter"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) {
    return false;
  }
  return true;
}

static const JSJitInfo description_getterinfo = {
  { get_description },
  { prototypes::id::Addon },
  { PrototypeTraits<prototypes::id::Addon>::Depth },
  JSJitInfo::Getter,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_STRING,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
get_isEnabled(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, JSJitGetterCallArgs args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "Addon", "isEnabled", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::Addon*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  bool result(MOZ_KnownLive(self)->GetIsEnabled(rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "Addon.isEnabled getter"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  args.rval().setBoolean(result);
  return true;
}

static const JSJitInfo isEnabled_getterinfo = {
  { get_isEnabled },
  { prototypes::id::Addon },
  { PrototypeTraits<prototypes::id::Addon>::Depth },
  JSJitInfo::Getter,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_BOOLEAN,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
get_isActive(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, JSJitGetterCallArgs args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "Addon", "isActive", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::Addon*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  bool result(MOZ_KnownLive(self)->GetIsActive(rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "Addon.isActive getter"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  args.rval().setBoolean(result);
  return true;
}

static const JSJitInfo isActive_getterinfo = {
  { get_isActive },
  { prototypes::id::Addon },
  { PrototypeTraits<prototypes::id::Addon>::Depth },
  JSJitInfo::Getter,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_BOOLEAN,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
get_canUninstall(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, JSJitGetterCallArgs args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "Addon", "canUninstall", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::Addon*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  bool result(MOZ_KnownLive(self)->GetCanUninstall(rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "Addon.canUninstall getter"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  args.rval().setBoolean(result);
  return true;
}

static const JSJitInfo canUninstall_getterinfo = {
  { get_canUninstall },
  { prototypes::id::Addon },
  { PrototypeTraits<prototypes::id::Addon>::Depth },
  JSJitInfo::Getter,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_BOOLEAN,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
uninstall(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "Addon", "uninstall", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::Addon*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  auto result(StrongOrRawPtr<Promise>(MOZ_KnownLive(self)->Uninstall(rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)))));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "Addon.uninstall"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!ToJSValue(cx, result, args.rval())) {
    return false;
  }
  return true;
}

MOZ_CAN_RUN_SCRIPT static bool
uninstall_promiseWrapper(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  bool ok = uninstall(cx, obj, void_self, args);
  if (ok) {
    return true;
  }
  return ConvertExceptionToPromise(cx, args.rval());
}

static const JSJitInfo uninstall_methodinfo = {
  { (JSJitGetterOp)uninstall_promiseWrapper },
  { prototypes::id::Addon },
  { PrototypeTraits<prototypes::id::Addon>::Depth },
  JSJitInfo::Method,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_OBJECT,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
setEnabled(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "Addon", "setEnabled", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::Addon*>(void_self);
  if (!args.requireAtLeast(cx, "Addon.setEnabled", 1)) {
    return false;
  }
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  bool arg0;
  if (!ValueToPrimitive<bool, eDefault>(cx, args[0], "Argument 1", &arg0)) {
    return false;
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  auto result(StrongOrRawPtr<Promise>(MOZ_KnownLive(self)->SetEnabled(arg0, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)))));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "Addon.setEnabled"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!ToJSValue(cx, result, args.rval())) {
    return false;
  }
  return true;
}

MOZ_CAN_RUN_SCRIPT static bool
setEnabled_promiseWrapper(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  bool ok = setEnabled(cx, obj, void_self, args);
  if (ok) {
    return true;
  }
  return ConvertExceptionToPromise(cx, args.rval());
}

static const JSJitInfo setEnabled_methodinfo = {
  { (JSJitGetterOp)setEnabled_promiseWrapper },
  { prototypes::id::Addon },
  { PrototypeTraits<prototypes::id::Addon>::Depth },
  JSJitInfo::Method,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_OBJECT,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

static void
_finalize(JS::GCContext* gcx, JSObject* obj)
{
  mozilla::dom::Addon* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::Addon>(obj);
  if (self) {
    JS::SetReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue());
    ClearWrapper(self, self, obj);
    if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) {
      JS::RemoveAssociatedMemory(obj, mallocBytes,
                                 JS::MemoryUse::DOMBinding);
    }
    AddForDeferredFinalization<mozilla::dom::Addon>(self);
  }
}

MOZ_GLOBINIT static const JSFunctionSpec sChromeStaticMethods_specs[] = {
  JS_FNSPEC("_create", Addon::_Create, nullptr, 2, 0, nullptr),
  JS_FS_END
};


static const Prefable<const JSFunctionSpec> sChromeStaticMethods[] = {
  { nullptr, &sChromeStaticMethods_specs[0] },
  { nullptr, nullptr }
};

static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
    "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
    "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");

MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = {
  JS_FNSPEC("uninstall", (GenericMethod<NormalThisPolicy, ConvertExceptionsToPromises>), reinterpret_cast<const JSJitInfo*>(&uninstall_methodinfo), 0, JSPROP_ENUMERATE, nullptr),
  JS_FNSPEC("setEnabled", (GenericMethod<NormalThisPolicy, ConvertExceptionsToPromises>), reinterpret_cast<const JSJitInfo*>(&setEnabled_methodinfo), 1, JSPROP_ENUMERATE, nullptr),
  JS_FS_END
};


static const Prefable<const JSFunctionSpec> sMethods[] = {
  { nullptr, &sMethods_specs[0] },
  { nullptr, nullptr }
};

static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
    "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
    "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");

MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = {
  JSPropertySpec::nativeAccessors("id", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &id_getterinfo, nullptr, nullptr),
  JSPropertySpec::nativeAccessors("version", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &version_getterinfo, nullptr, nullptr),
  JSPropertySpec::nativeAccessors("type", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &type_getterinfo, nullptr, nullptr),
  JSPropertySpec::nativeAccessors("name", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &name_getterinfo, nullptr, nullptr),
  JSPropertySpec::nativeAccessors("description", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &description_getterinfo, nullptr, nullptr),
  JSPropertySpec::nativeAccessors("isEnabled", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &isEnabled_getterinfo, nullptr, nullptr),
  JSPropertySpec::nativeAccessors("isActive", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &isActive_getterinfo, nullptr, nullptr),
  JSPropertySpec::nativeAccessors("canUninstall", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &canUninstall_getterinfo, nullptr, nullptr),
  JS_PS_END
};


static const Prefable<const JSPropertySpec> sAttributes[] = {
  { nullptr, &sAttributes_specs[0] },
  { nullptr, nullptr }
};

static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
    "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
static_assert(8 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
    "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");


static uint16_t sNativeProperties_sortedPropertyIndices[10];
static PropertyInfo sNativeProperties_propertyInfos[10];

static const NativePropertiesN<2> sNativeProperties = {
  false, 0,
  false, 0,
  true,  0 /* sMethods */,
  true,  1 /* sAttributes */,
  false, 0,
  false, 0,
  false, 0,
  -1,
  10,
  sNativeProperties_sortedPropertyIndices,
  {
    { sMethods, &sNativeProperties_propertyInfos[0] },
    { sAttributes, &sNativeProperties_propertyInfos[2] }
  }
};
static_assert(10 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)),
    "We have a property info count that is oversized");

static uint16_t sChromeOnlyNativeProperties_sortedPropertyIndices[1];
static PropertyInfo sChromeOnlyNativeProperties_propertyInfos[1];

static const NativePropertiesN<1> sChromeOnlyNativeProperties = {
  true,  0 /* sChromeStaticMethods */,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  -1,
  1,
  sChromeOnlyNativeProperties_sortedPropertyIndices,
  {
    { sChromeStaticMethods, &sChromeOnlyNativeProperties_propertyInfos[0] }
  }
};
static_assert(1 < 1ull << (CHAR_BIT * sizeof(sChromeOnlyNativeProperties.propertyInfoCount)),
    "We have a property info count that is oversized");

bool sNativePropertiesInited = false;
const NativePropertyHooks sNativePropertyHooks = {
  nullptr,
  { sNativeProperties.Upcast(), sChromeOnlyNativeProperties.Upcast(), &sNativePropertiesInited },
  prototypes::id::Addon,
  constructors::id::Addon,
  &DefaultXrayExpandoObjectClass
};

static const DOMInterfaceInfo sInterfaceObjectInfo = {
  { ThrowingConstructor, &sNativePropertyHooks },
  JS::GetRealmFunctionPrototypeHandle,
  PrototypeTraits<prototypes::id::Addon>::Depth,
  prototypes::id::Addon,
  true,
  0,
  "Addon",
};

static const DOMIfaceAndProtoJSClass sPrototypeClass = {
  {
    "AddonPrototype",
    JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE),
    JS_NULL_CLASS_OPS,
    JS_NULL_CLASS_SPEC,
    JS_NULL_CLASS_EXT,
    JS_NULL_OBJECT_OPS
  },
  eInterfacePrototype,
  prototypes::id::Addon,
  PrototypeTraits<prototypes::id::Addon>::Depth,
  &sNativePropertyHooks,
  JS::GetRealmObjectPrototype
};

bool
ConstructorEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj)
{
  return nsContentUtils::ThreadsafeIsSystemCaller(aCx);
}

static JS::Handle<JSObject*>
GetProtoObjectHandle(JSContext* aCx);

static const JSClassOps sClassOps = {
  nullptr,               /* addProperty */
  nullptr,               /* delProperty */
  nullptr,               /* enumerate */
  nullptr, /* newEnumerate */
  nullptr, /* resolve */
  nullptr, /* mayResolve */
  _finalize, /* finalize */
  nullptr, /* call */
  nullptr,               /* construct */
  nullptr, /* trace */
};

static const DOMJSClass sClass = {
  { "Addon",
    JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER,
    &sClassOps,
    JS_NULL_CLASS_SPEC,
    &NativeTypeHelpers<mozilla::dom::Addon>::sClassExtension,
    JS_NULL_OBJECT_OPS
  },
  { prototypes::id::Addon, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count },
  std::is_base_of_v<nsISupports, mozilla::dom::Addon>,
  &sNativePropertyHooks,
  FindAssociatedGlobalForNative<mozilla::dom::Addon>::Get,
  GetProtoObjectHandle,
  GetCCParticipant<mozilla::dom::Addon>::Get(),
  nullptr,
  NativeTypeHelpers<mozilla::dom::Addon>::GetWrapperCache
};
static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS,
              "Must have the right minimal number of reserved slots.");
static_assert(1 >= 1,
              "Must have enough reserved slots.");

bool
Wrap(JSContext* aCx, mozilla::dom::Addon* aObject, nsWrapperCache* aCache, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
{
  static_assert(!std::is_base_of_v<NonRefcountedDOMObject, mozilla::dom::Addon>,
                "Shouldn't have wrappercached things that are not refcounted.");
  static_assert(std::is_same_v<decltype(aObject), mozilla::dom::Addon*>);
  MOZ_ASSERT(ToSupportsIsCorrect(aObject));
  MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
  MOZ_ASSERT(!aCache->GetWrapper(),
             "You should probably not be using Wrap() directly; use "
             "GetOrCreateDOMReflector instead");

  MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
             "nsISupports must be on our primary inheritance chain");

  // If the wrapper cache contains a dead reflector then finalize that
  // now, ensuring that the finalizer for the old reflector always
  // runs before the new reflector is created and attached. This
  // avoids the awkward situation where there are multiple reflector
  // objects that contain pointers to the same native.

  if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) {
    _finalize(nullptr /* unused */, oldReflector);
    MOZ_ASSERT(!aCache->GetWrapperMaybeDead());
  }

  JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
  if (!global) {
    return false;
  }
  MOZ_ASSERT(JS_IsGlobalObject(global));
  JS::AssertObjectIsNotGray(global);

  // That might have ended up wrapping us already, due to the wonders
  // of XBL.  Check for that, and bail out as needed.
  aReflector.set(aCache->GetWrapper());
  if (aReflector) {
#ifdef DEBUG
    AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
#endif // DEBUG
    return true;
  }

  JSAutoRealm ar(aCx, global);
  JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
  if (!canonicalProto) {
    return false;
  }
  JS::Rooted<JSObject*> proto(aCx);
  if (aGivenProto) {
    proto = aGivenProto;
    // Unfortunately, while aGivenProto was in the compartment of aCx
    // coming in, we changed compartments to that of "parent" so may need
    // to wrap the proto here.
    if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) {
      if (!JS_WrapObject(aCx, &proto)) {
        return false;
      }
    }
  } else {
    proto = canonicalProto;
  }

  BindingJSObjectCreator<mozilla::dom::Addon> creator(aCx);
  creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
  if (!aReflector) {
    return false;
  }

  aCache->SetWrapper(aReflector);
  creator.InitializationSucceeded();

  MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
             aCache->GetWrapperPreserveColor() == aReflector);
  // If proto != canonicalProto, we have to preserve our wrapper;
  // otherwise we won't be able to properly recreate it later, since
  // we won't know what proto to use.  Note that we don't check
  // aGivenProto here, since it's entirely possible (and even
  // somewhat common) to have a non-null aGivenProto which is the
  // same as canonicalProto.
  if (proto != canonicalProto) {
    PreserveWrapper(aObject);
  }

  return true;
}

void
CreateInterfaceObjects(JSContext* aCx, JS::Handle<JSObject*> aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal)
{
  JS::Heap<JSObject*>* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::Addon);
  JS::Heap<JSObject*>* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::Addon);

  JS::Handle<JSObject*> parentProto(JS::GetRealmObjectPrototypeHandle(aCx));
  if (!parentProto) {
    return;
  }

  JS::Handle<JSObject*> constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx));
  if (!constructorProto) {
    return;
  }

  dom::CreateInterfaceObjects(aCx, aGlobal, parentProto,
                              &sPrototypeClass, protoCache,
                              constructorProto, &sInterfaceObjectInfo, 0, false, Span<const LegacyFactoryFunction, 0>{},
                              interfaceCache,
                              sNativeProperties.Upcast(),
                              sChromeOnlyNativeProperties.Upcast(),
                              "Addon",
                              ShouldExpose<Addon_Binding::ConstructorEnabled>(aCx, aGlobal, aDefineOnGlobal),
                              nullptr,
                              false,
                              nullptr);
}

static JS::Handle<JSObject*>
GetProtoObjectHandle(JSContext* aCx)
{
  /* Get the interface prototype object for this class.  This will create the
     object as needed. */
  return GetPerInterfaceObjectHandle(aCx, prototypes::id::Addon,
                                     &CreateInterfaceObjects,
                                     DefineInterfaceProperty::CheckExposure);

}

JS::Handle<JSObject*>
GetConstructorObjectHandle(JSContext* aCx)
{
  /* Get the interface object for this class.  This will create the object as
     needed. */

  return GetPerInterfaceObjectHandle(aCx, constructors::id::Addon,
                                     &CreateInterfaceObjects,
                                     DefineInterfaceProperty::CheckExposure);
}

} // namespace Addon_Binding



namespace AddonInstall_Binding {

static_assert(IsRefcounted<NativeType>::value == IsRefcounted<EventTarget_Binding::NativeType>::value,
              "Can't inherit from an interface with a different ownership model.");

MOZ_CAN_RUN_SCRIPT static bool
get_state(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, JSJitGetterCallArgs args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "AddonInstall", "state", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::AddonInstall*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  DOMString result;
  // NOTE: This assert does NOT call the function.
  static_assert(std::is_void_v<decltype(MOZ_KnownLive(self)->GetState(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))))>, "Should be returning void here");
  MOZ_KnownLive(self)->GetState(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "AddonInstall.state getter"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) {
    return false;
  }
  return true;
}

static const JSJitInfo state_getterinfo = {
  { get_state },
  { prototypes::id::AddonInstall },
  { PrototypeTraits<prototypes::id::AddonInstall>::Depth },
  JSJitInfo::Getter,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_STRING,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
get_error(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, JSJitGetterCallArgs args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "AddonInstall", "error", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::AddonInstall*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  DOMString result;
  // NOTE: This assert does NOT call the function.
  static_assert(std::is_void_v<decltype(MOZ_KnownLive(self)->GetError(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))))>, "Should be returning void here");
  MOZ_KnownLive(self)->GetError(result, rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "AddonInstall.error getter"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!xpc::StringToJsval(cx, result, args.rval())) {
    return false;
  }
  return true;
}

static const JSJitInfo error_getterinfo = {
  { get_error },
  { prototypes::id::AddonInstall },
  { PrototypeTraits<prototypes::id::AddonInstall>::Depth },
  JSJitInfo::Getter,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_UNKNOWN,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
get_progress(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, JSJitGetterCallArgs args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "AddonInstall", "progress", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::AddonInstall*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  int64_t result(MOZ_KnownLive(self)->GetProgress(rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "AddonInstall.progress getter"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  args.rval().set(JS_NumberValue(double(result)));
  return true;
}

static const JSJitInfo progress_getterinfo = {
  { get_progress },
  { prototypes::id::AddonInstall },
  { PrototypeTraits<prototypes::id::AddonInstall>::Depth },
  JSJitInfo::Getter,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_DOUBLE,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
get_maxProgress(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, JSJitGetterCallArgs args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "AddonInstall", "maxProgress", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::AddonInstall*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  int64_t result(MOZ_KnownLive(self)->GetMaxProgress(rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "AddonInstall.maxProgress getter"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  args.rval().set(JS_NumberValue(double(result)));
  return true;
}

static const JSJitInfo maxProgress_getterinfo = {
  { get_maxProgress },
  { prototypes::id::AddonInstall },
  { PrototypeTraits<prototypes::id::AddonInstall>::Depth },
  JSJitInfo::Getter,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_DOUBLE,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
install(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "AddonInstall", "install", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::AddonInstall*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  auto result(StrongOrRawPtr<Promise>(MOZ_KnownLive(self)->Install(rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)))));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "AddonInstall.install"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!ToJSValue(cx, result, args.rval())) {
    return false;
  }
  return true;
}

MOZ_CAN_RUN_SCRIPT static bool
install_promiseWrapper(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  bool ok = install(cx, obj, void_self, args);
  if (ok) {
    return true;
  }
  return ConvertExceptionToPromise(cx, args.rval());
}

static const JSJitInfo install_methodinfo = {
  { (JSJitGetterOp)install_promiseWrapper },
  { prototypes::id::AddonInstall },
  { PrototypeTraits<prototypes::id::AddonInstall>::Depth },
  JSJitInfo::Method,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_OBJECT,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
cancel(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "AddonInstall", "cancel", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::AddonInstall*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  auto result(StrongOrRawPtr<Promise>(MOZ_KnownLive(self)->Cancel(rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)))));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "AddonInstall.cancel"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!ToJSValue(cx, result, args.rval())) {
    return false;
  }
  return true;
}

MOZ_CAN_RUN_SCRIPT static bool
cancel_promiseWrapper(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  bool ok = cancel(cx, obj, void_self, args);
  if (ok) {
    return true;
  }
  return ConvertExceptionToPromise(cx, args.rval());
}

static const JSJitInfo cancel_methodinfo = {
  { (JSJitGetterOp)cancel_promiseWrapper },
  { prototypes::id::AddonInstall },
  { PrototypeTraits<prototypes::id::AddonInstall>::Depth },
  JSJitInfo::Method,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_OBJECT,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

static void
_finalize(JS::GCContext* gcx, JSObject* obj)
{
  mozilla::dom::AddonInstall* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::AddonInstall>(obj);
  if (self) {
    JS::SetReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue());
    ClearWrapper(self, self, obj);
    if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) {
      JS::RemoveAssociatedMemory(obj, mallocBytes,
                                 JS::MemoryUse::DOMBinding);
    }
    AddForDeferredFinalization<mozilla::dom::AddonInstall>(self);
  }
}

MOZ_GLOBINIT static const JSFunctionSpec sChromeStaticMethods_specs[] = {
  JS_FNSPEC("_create", AddonInstall::_Create, nullptr, 2, 0, nullptr),
  JS_FS_END
};


static const Prefable<const JSFunctionSpec> sChromeStaticMethods[] = {
  { nullptr, &sChromeStaticMethods_specs[0] },
  { nullptr, nullptr }
};

static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
    "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
    "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");

MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = {
  JS_FNSPEC("install", (GenericMethod<NormalThisPolicy, ConvertExceptionsToPromises>), reinterpret_cast<const JSJitInfo*>(&install_methodinfo), 0, JSPROP_ENUMERATE, nullptr),
  JS_FNSPEC("cancel", (GenericMethod<NormalThisPolicy, ConvertExceptionsToPromises>), reinterpret_cast<const JSJitInfo*>(&cancel_methodinfo), 0, JSPROP_ENUMERATE, nullptr),
  JS_FS_END
};


static const Prefable<const JSFunctionSpec> sMethods[] = {
  { nullptr, &sMethods_specs[0] },
  { nullptr, nullptr }
};

static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
    "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
    "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");

MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = {
  JSPropertySpec::nativeAccessors("state", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &state_getterinfo, nullptr, nullptr),
  JSPropertySpec::nativeAccessors("error", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &error_getterinfo, nullptr, nullptr),
  JSPropertySpec::nativeAccessors("progress", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &progress_getterinfo, nullptr, nullptr),
  JSPropertySpec::nativeAccessors("maxProgress", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &maxProgress_getterinfo, nullptr, nullptr),
  JS_PS_END
};


static const Prefable<const JSPropertySpec> sAttributes[] = {
  { nullptr, &sAttributes_specs[0] },
  { nullptr, nullptr }
};

static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
    "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
static_assert(4 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
    "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");


static uint16_t sNativeProperties_sortedPropertyIndices[6];
static PropertyInfo sNativeProperties_propertyInfos[6];

static const NativePropertiesN<2> sNativeProperties = {
  false, 0,
  false, 0,
  true,  0 /* sMethods */,
  true,  1 /* sAttributes */,
  false, 0,
  false, 0,
  false, 0,
  -1,
  6,
  sNativeProperties_sortedPropertyIndices,
  {
    { sMethods, &sNativeProperties_propertyInfos[0] },
    { sAttributes, &sNativeProperties_propertyInfos[2] }
  }
};
static_assert(6 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)),
    "We have a property info count that is oversized");

static uint16_t sChromeOnlyNativeProperties_sortedPropertyIndices[1];
static PropertyInfo sChromeOnlyNativeProperties_propertyInfos[1];

static const NativePropertiesN<1> sChromeOnlyNativeProperties = {
  true,  0 /* sChromeStaticMethods */,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  -1,
  1,
  sChromeOnlyNativeProperties_sortedPropertyIndices,
  {
    { sChromeStaticMethods, &sChromeOnlyNativeProperties_propertyInfos[0] }
  }
};
static_assert(1 < 1ull << (CHAR_BIT * sizeof(sChromeOnlyNativeProperties.propertyInfoCount)),
    "We have a property info count that is oversized");

bool sNativePropertiesInited = false;
const NativePropertyHooks sNativePropertyHooks = {
  nullptr,
  { sNativeProperties.Upcast(), sChromeOnlyNativeProperties.Upcast(), &sNativePropertiesInited },
  prototypes::id::AddonInstall,
  constructors::id::AddonInstall,
  &DefaultXrayExpandoObjectClass
};

static const DOMInterfaceInfo sInterfaceObjectInfo = {
  { ThrowingConstructor, &sNativePropertyHooks },
  EventTarget_Binding::GetConstructorObjectHandle,
  PrototypeTraits<prototypes::id::AddonInstall>::Depth,
  prototypes::id::AddonInstall,
  true,
  0,
  "AddonInstall",
};

static const DOMIfaceAndProtoJSClass sPrototypeClass = {
  {
    "AddonInstallPrototype",
    JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE),
    JS_NULL_CLASS_OPS,
    JS_NULL_CLASS_SPEC,
    JS_NULL_CLASS_EXT,
    JS_NULL_OBJECT_OPS
  },
  eInterfacePrototype,
  prototypes::id::AddonInstall,
  PrototypeTraits<prototypes::id::AddonInstall>::Depth,
  &sNativePropertyHooks,
  EventTarget_Binding::GetProtoObject
};

bool
ConstructorEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj)
{
  return nsContentUtils::ThreadsafeIsSystemCaller(aCx);
}

static JS::Handle<JSObject*>
GetProtoObjectHandle(JSContext* aCx);

static const JSClassOps sClassOps = {
  nullptr,               /* addProperty */
  nullptr,               /* delProperty */
  nullptr,               /* enumerate */
  nullptr, /* newEnumerate */
  nullptr, /* resolve */
  nullptr, /* mayResolve */
  _finalize, /* finalize */
  nullptr, /* call */
  nullptr,               /* construct */
  nullptr, /* trace */
};

static const DOMJSClass sClass = {
  { "AddonInstall",
    JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER,
    &sClassOps,
    JS_NULL_CLASS_SPEC,
    &NativeTypeHelpers<mozilla::dom::AddonInstall>::sClassExtension,
    JS_NULL_OBJECT_OPS
  },
  { prototypes::id::EventTarget, prototypes::id::AddonInstall, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count },
  std::is_base_of_v<nsISupports, mozilla::dom::AddonInstall>,
  &sNativePropertyHooks,
  FindAssociatedGlobalForNative<mozilla::dom::AddonInstall>::Get,
  GetProtoObjectHandle,
  GetCCParticipant<mozilla::dom::AddonInstall>::Get(),
  nullptr,
  NativeTypeHelpers<mozilla::dom::AddonInstall>::GetWrapperCache
};
static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS,
              "Must have the right minimal number of reserved slots.");
static_assert(1 >= 1,
              "Must have enough reserved slots.");

bool
Wrap(JSContext* aCx, mozilla::dom::AddonInstall* aObject, nsWrapperCache* aCache, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
{
  static_assert(!std::is_base_of_v<NonRefcountedDOMObject, mozilla::dom::AddonInstall>,
                "Shouldn't have wrappercached things that are not refcounted.");
  static_assert(std::is_same_v<decltype(aObject), mozilla::dom::AddonInstall*>);
  MOZ_ASSERT(static_cast<mozilla::dom::EventTarget*>(aObject) ==
             reinterpret_cast<mozilla::dom::EventTarget*>(aObject),
             "Multiple inheritance for mozilla::dom::EventTarget is broken.");
  MOZ_ASSERT(ToSupportsIsCorrect(aObject));
  MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
  MOZ_ASSERT(!aCache->GetWrapper(),
             "You should probably not be using Wrap() directly; use "
             "GetOrCreateDOMReflector instead");

  MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
             "nsISupports must be on our primary inheritance chain");

  // If the wrapper cache contains a dead reflector then finalize that
  // now, ensuring that the finalizer for the old reflector always
  // runs before the new reflector is created and attached. This
  // avoids the awkward situation where there are multiple reflector
  // objects that contain pointers to the same native.

  if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) {
    _finalize(nullptr /* unused */, oldReflector);
    MOZ_ASSERT(!aCache->GetWrapperMaybeDead());
  }

  JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
  if (!global) {
    return false;
  }
  MOZ_ASSERT(JS_IsGlobalObject(global));
  JS::AssertObjectIsNotGray(global);

  // That might have ended up wrapping us already, due to the wonders
  // of XBL.  Check for that, and bail out as needed.
  aReflector.set(aCache->GetWrapper());
  if (aReflector) {
#ifdef DEBUG
    AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
#endif // DEBUG
    return true;
  }

  JSAutoRealm ar(aCx, global);
  JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
  if (!canonicalProto) {
    return false;
  }
  JS::Rooted<JSObject*> proto(aCx);
  if (aGivenProto) {
    proto = aGivenProto;
    // Unfortunately, while aGivenProto was in the compartment of aCx
    // coming in, we changed compartments to that of "parent" so may need
    // to wrap the proto here.
    if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) {
      if (!JS_WrapObject(aCx, &proto)) {
        return false;
      }
    }
  } else {
    proto = canonicalProto;
  }

  BindingJSObjectCreator<mozilla::dom::AddonInstall> creator(aCx);
  creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
  if (!aReflector) {
    return false;
  }

  aCache->SetWrapper(aReflector);
  creator.InitializationSucceeded();

  MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
             aCache->GetWrapperPreserveColor() == aReflector);
  // If proto != canonicalProto, we have to preserve our wrapper;
  // otherwise we won't be able to properly recreate it later, since
  // we won't know what proto to use.  Note that we don't check
  // aGivenProto here, since it's entirely possible (and even
  // somewhat common) to have a non-null aGivenProto which is the
  // same as canonicalProto.
  if (proto != canonicalProto) {
    PreserveWrapper(aObject);
  }

  return true;
}

void
CreateInterfaceObjects(JSContext* aCx, JS::Handle<JSObject*> aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal)
{
  JS::Heap<JSObject*>* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::AddonInstall);
  JS::Heap<JSObject*>* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::AddonInstall);

  JS::Handle<JSObject*> parentProto(EventTarget_Binding::GetProtoObjectHandle(aCx));
  if (!parentProto) {
    return;
  }

  JS::Handle<JSObject*> constructorProto(EventTarget_Binding::GetConstructorObjectHandle(aCx));
  if (!constructorProto) {
    return;
  }

  dom::CreateInterfaceObjects(aCx, aGlobal, parentProto,
                              &sPrototypeClass, protoCache,
                              constructorProto, &sInterfaceObjectInfo, 0, false, Span<const LegacyFactoryFunction, 0>{},
                              interfaceCache,
                              sNativeProperties.Upcast(),
                              sChromeOnlyNativeProperties.Upcast(),
                              "AddonInstall",
                              ShouldExpose<AddonInstall_Binding::ConstructorEnabled>(aCx, aGlobal, aDefineOnGlobal),
                              nullptr,
                              false,
                              nullptr);
}

static JS::Handle<JSObject*>
GetProtoObjectHandle(JSContext* aCx)
{
  /* Get the interface prototype object for this class.  This will create the
     object as needed. */
  return GetPerInterfaceObjectHandle(aCx, prototypes::id::AddonInstall,
                                     &CreateInterfaceObjects,
                                     DefineInterfaceProperty::CheckExposure);

}

JS::Handle<JSObject*>
GetConstructorObjectHandle(JSContext* aCx)
{
  /* Get the interface object for this class.  This will create the object as
     needed. */

  return GetPerInterfaceObjectHandle(aCx, constructors::id::AddonInstall,
                                     &CreateInterfaceObjects,
                                     DefineInterfaceProperty::CheckExposure);
}

} // namespace AddonInstall_Binding



namespace AddonManager_Binding {

static_assert(IsRefcounted<NativeType>::value == IsRefcounted<EventTarget_Binding::NativeType>::value,
              "Can't inherit from an interface with a different ownership model.");

MOZ_CAN_RUN_SCRIPT static bool
getAddonByID(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "AddonManager", "getAddonByID", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::AddonManager*>(void_self);
  if (!args.requireAtLeast(cx, "AddonManager.getAddonByID", 1)) {
    return false;
  }
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  binding_detail::FakeString<char16_t> arg0;
  if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) {
    return false;
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  auto result(StrongOrRawPtr<Promise>(MOZ_KnownLive(self)->GetAddonByID(NonNullHelper(Constify(arg0)), rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)))));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "AddonManager.getAddonByID"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!ToJSValue(cx, result, args.rval())) {
    return false;
  }
  return true;
}

MOZ_CAN_RUN_SCRIPT static bool
getAddonByID_promiseWrapper(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  bool ok = getAddonByID(cx, obj, void_self, args);
  if (ok) {
    return true;
  }
  return ConvertExceptionToPromise(cx, args.rval());
}

static const JSJitInfo getAddonByID_methodinfo = {
  { (JSJitGetterOp)getAddonByID_promiseWrapper },
  { prototypes::id::AddonManager },
  { PrototypeTraits<prototypes::id::AddonManager>::Depth },
  JSJitInfo::Method,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_OBJECT,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
createInstall(JSContext* cx_, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  BindingCallContext cx(cx_, "AddonManager.createInstall");
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "AddonManager", "createInstall", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::AddonManager*>(void_self);
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  binding_detail::FastaddonInstallOptions arg0;
  if (!arg0.Init(cx, (args.hasDefined(0)) ? args[0] : JS::NullHandleValue, "Argument 1", true)) {
    return false;
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  auto result(StrongOrRawPtr<Promise>(MOZ_KnownLive(self)->CreateInstall(Constify(arg0), rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)))));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "AddonManager.createInstall"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  if (!ToJSValue(cx, result, args.rval())) {
    return false;
  }
  return true;
}

MOZ_CAN_RUN_SCRIPT static bool
createInstall_promiseWrapper(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  bool ok = createInstall(cx, obj, void_self, args);
  if (ok) {
    return true;
  }
  return ConvertExceptionToPromise(cx, args.rval());
}

static const JSJitInfo createInstall_methodinfo = {
  { (JSJitGetterOp)createInstall_promiseWrapper },
  { prototypes::id::AddonManager },
  { PrototypeTraits<prototypes::id::AddonManager>::Depth },
  JSJitInfo::Method,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_OBJECT,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

MOZ_CAN_RUN_SCRIPT static bool
sendAbuseReport(JSContext* cx_, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  BindingCallContext cx(cx_, "AddonManager.sendAbuseReport");
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "AddonManager", "sendAbuseReport", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  auto* self = static_cast<mozilla::dom::AddonManager*>(void_self);
  if (!args.requireAtLeast(cx, "AddonManager.sendAbuseReport", 2)) {
    return false;
  }
  Maybe<JS::Rooted<JSObject*> > unwrappedObj;
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
  if (objIsXray) {
    unwrappedObj.emplace(cx, obj);
  }
  binding_detail::FakeString<char16_t> arg0;
  if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) {
    return false;
  }
  Record<nsString, nsString> arg1;
  if (args[1].isObject()) {
    auto& recordEntries = arg1.Entries();

    JS::Rooted<JSObject*> recordObj(cx, &args[1].toObject());
    JS::RootedVector<jsid> ids(cx);
    if (!js::GetPropertyKeys(cx, recordObj,
                             JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) {
      return false;
    }
    if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) {
      JS_ReportOutOfMemory(cx);
      return false;
    }
    JS::Rooted<JS::Value> propNameValue(cx);
    JS::Rooted<JS::Value> temp(cx);
    JS::Rooted<jsid> curId(cx);
    JS::Rooted<JS::Value> idVal(cx);
    // Use a hashset to keep track of ids seen, to avoid
    // introducing nasty O(N^2) behavior scanning for them all the
    // time.  Ideally we'd use a data structure with O(1) lookup
    // _and_ ordering for the MozMap, but we don't have one lying
    // around.
    nsTHashtable<nsStringHashKey> idsSeen;
    for (size_t i = 0; i < ids.length(); ++i) {
      curId = ids[i];

      JS::Rooted<mozilla::Maybe<JS::PropertyDescriptor>> desc(cx);
      if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId,
                                           &desc)) {
        return false;
      }

      if (desc.isNothing() || !desc->enumerable()) {
        continue;
      }

      idVal = js::IdToValue(curId);
      nsString propName;
      // This will just throw if idVal is a Symbol, like the spec says
      // to do.
      if (!ConvertJSValueToString(cx, idVal, "key of argument 2", propName)) {
        return false;
      }

      if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) {
        return false;
      }

      Record<nsString, nsString>::EntryType* entry;
      if (!idsSeen.EnsureInserted(propName)) {
        // Find the existing entry.
        auto idx = recordEntries.IndexOf(propName);
        MOZ_ASSERT(idx != recordEntries.NoIndex,
                   "Why is it not found?");
        // Now blow it away to make it look like it was just added
        // to the array, because it's not obvious that it's
        // safe to write to its already-initialized mValue via our
        // normal codegen conversions.  For example, the value
        // could be a union and this would change its type, but
        // codegen assumes we won't do that.
        entry = recordEntries.ReconstructElementAt(idx);
      } else {
        // Safe to do an infallible append here, because we did a
        // SetCapacity above to the right capacity.
        entry = recordEntries.AppendElement();
      }
      entry->mKey = propName;
      nsString& slot = entry->mValue;
      if (!ConvertJSValueToString(cx, temp, eNull, eNull, slot)) {
        return false;
      }
    }
  } else {
    cx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 2");
    return false;
  }
  binding_detail::FastsendAbuseReportOptions arg2;
  if (!arg2.Init(cx, (args.hasDefined(2)) ? args[2] : JS::NullHandleValue, "Argument 3", true)) {
    return false;
  }
  if (objIsXray) {
    // Since our object is an Xray, we can just CheckedUnwrapStatic:
    // we know Xrays have no dynamic unwrap behavior.
    unwrappedObj.ref() = js::CheckedUnwrapStatic(unwrappedObj.ref());
    if (!unwrappedObj.ref()) {
      return false;
    }
  }
  FastErrorResult rv;
  auto result(StrongOrRawPtr<Promise>(MOZ_KnownLive(self)->SendAbuseReport(NonNullHelper(Constify(arg0)), Constify(arg1), Constify(arg2), rv, (unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx)))));
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, "AddonManager.sendAbuseReport"))) {
    return false;
  }
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  static_assert(!std::is_pointer_v<decltype(result)>,
                "NewObject implies that we need to keep the object alive with a strong reference.");
  if (!ToJSValue(cx, result, args.rval())) {
    return false;
  }
  return true;
}

MOZ_CAN_RUN_SCRIPT static bool
sendAbuseReport_promiseWrapper(JSContext* cx, JS::Handle<JSObject*> obj, void* void_self, const JSJitMethodCallArgs& args)
{
  bool ok = sendAbuseReport(cx, obj, void_self, args);
  if (ok) {
    return true;
  }
  return ConvertExceptionToPromise(cx, args.rval());
}

static const JSJitInfo sendAbuseReport_methodinfo = {
  { (JSJitGetterOp)sendAbuseReport_promiseWrapper },
  { prototypes::id::AddonManager },
  { PrototypeTraits<prototypes::id::AddonManager>::Depth },
  JSJitInfo::Method,
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
  JSVAL_TYPE_OBJECT,  /* returnType.  Not relevant for setters. */
  false,  /* isInfallible. False in setters. */
  false,  /* isMovable.  Not relevant for setters. */
  false, /* isEliminatable.  Not relevant for setters. */
  false, /* isAlwaysInSlot.  Only relevant for getters. */
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
  false,  /* isTypedMethod.  Only relevant for methods. */
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
};

static void
_finalize(JS::GCContext* gcx, JSObject* obj)
{
  mozilla::dom::AddonManager* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::AddonManager>(obj);
  if (self) {
    JS::SetReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue());
    ClearWrapper(self, self, obj);
    if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) {
      JS::RemoveAssociatedMemory(obj, mallocBytes,
                                 JS::MemoryUse::DOMBinding);
    }
    AddForDeferredFinalization<mozilla::dom::AddonManager>(self);
  }
}

MOZ_GLOBINIT static const JSFunctionSpec sChromeStaticMethods_specs[] = {
  JS_FNSPEC("_create", AddonManager::_Create, nullptr, 2, 0, nullptr),
  JS_FS_END
};


static const Prefable<const JSFunctionSpec> sChromeStaticMethods[] = {
  { nullptr, &sChromeStaticMethods_specs[0] },
  { nullptr, nullptr }
};

static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
    "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
    "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");

MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = {
  JS_FNSPEC("getAddonByID", (GenericMethod<NormalThisPolicy, ConvertExceptionsToPromises>), reinterpret_cast<const JSJitInfo*>(&getAddonByID_methodinfo), 1, JSPROP_ENUMERATE, nullptr),
  JS_FNSPEC("createInstall", (GenericMethod<NormalThisPolicy, ConvertExceptionsToPromises>), reinterpret_cast<const JSJitInfo*>(&createInstall_methodinfo), 0, JSPROP_ENUMERATE, nullptr),
  JS_FNSPEC("sendAbuseReport", (GenericMethod<NormalThisPolicy, ConvertExceptionsToPromises>), reinterpret_cast<const JSJitInfo*>(&sendAbuseReport_methodinfo), 2, JSPROP_ENUMERATE, nullptr),
  JS_FS_END
};


static const Prefable<const JSFunctionSpec> sMethods[] = {
  { nullptr, &sMethods_specs[0] },
  { nullptr, nullptr }
};

static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
    "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
static_assert(3 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
    "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");


static uint16_t sNativeProperties_sortedPropertyIndices[3];
static PropertyInfo sNativeProperties_propertyInfos[3];

static const NativePropertiesN<1> sNativeProperties = {
  false, 0,
  false, 0,
  true,  0 /* sMethods */,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  -1,
  3,
  sNativeProperties_sortedPropertyIndices,
  {
    { sMethods, &sNativeProperties_propertyInfos[0] }
  }
};
static_assert(3 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)),
    "We have a property info count that is oversized");

static uint16_t sChromeOnlyNativeProperties_sortedPropertyIndices[1];
static PropertyInfo sChromeOnlyNativeProperties_propertyInfos[1];

static const NativePropertiesN<1> sChromeOnlyNativeProperties = {
  true,  0 /* sChromeStaticMethods */,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  -1,
  1,
  sChromeOnlyNativeProperties_sortedPropertyIndices,
  {
    { sChromeStaticMethods, &sChromeOnlyNativeProperties_propertyInfos[0] }
  }
};
static_assert(1 < 1ull << (CHAR_BIT * sizeof(sChromeOnlyNativeProperties.propertyInfoCount)),
    "We have a property info count that is oversized");

bool sNativePropertiesInited = false;
const NativePropertyHooks sNativePropertyHooks = {
  nullptr,
  { sNativeProperties.Upcast(), sChromeOnlyNativeProperties.Upcast(), &sNativePropertiesInited },
  prototypes::id::AddonManager,
  constructors::id::AddonManager,
  &DefaultXrayExpandoObjectClass
};

static const DOMInterfaceInfo sInterfaceObjectInfo = {
  { ThrowingConstructor, &sNativePropertyHooks },
  EventTarget_Binding::GetConstructorObjectHandle,
  PrototypeTraits<prototypes::id::AddonManager>::Depth,
  prototypes::id::AddonManager,
  true,
  0,
  "AddonManager",
};

static const DOMIfaceAndProtoJSClass sPrototypeClass = {
  {
    "AddonManagerPrototype",
    JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE),
    JS_NULL_CLASS_OPS,
    JS_NULL_CLASS_SPEC,
    JS_NULL_CLASS_EXT,
    JS_NULL_OBJECT_OPS
  },
  eInterfacePrototype,
  prototypes::id::AddonManager,
  PrototypeTraits<prototypes::id::AddonManager>::Depth,
  &sNativePropertyHooks,
  EventTarget_Binding::GetProtoObject
};

bool
ConstructorEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj)
{
  return mozilla::AddonManagerWebAPI::IsAPIEnabled(aCx, aObj);
}

static JS::Handle<JSObject*>
GetProtoObjectHandle(JSContext* aCx);

static const JSClassOps sClassOps = {
  nullptr,               /* addProperty */
  nullptr,               /* delProperty */
  nullptr,               /* enumerate */
  nullptr, /* newEnumerate */
  nullptr, /* resolve */
  nullptr, /* mayResolve */
  _finalize, /* finalize */
  nullptr, /* call */
  nullptr,               /* construct */
  nullptr, /* trace */
};

static const DOMJSClass sClass = {
  { "AddonManager",
    JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER,
    &sClassOps,
    JS_NULL_CLASS_SPEC,
    &NativeTypeHelpers<mozilla::dom::AddonManager>::sClassExtension,
    JS_NULL_OBJECT_OPS
  },
  { prototypes::id::EventTarget, prototypes::id::AddonManager, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count },
  std::is_base_of_v<nsISupports, mozilla::dom::AddonManager>,
  &sNativePropertyHooks,
  FindAssociatedGlobalForNative<mozilla::dom::AddonManager>::Get,
  GetProtoObjectHandle,
  GetCCParticipant<mozilla::dom::AddonManager>::Get(),
  nullptr,
  NativeTypeHelpers<mozilla::dom::AddonManager>::GetWrapperCache
};
static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS,
              "Must have the right minimal number of reserved slots.");
static_assert(1 >= 1,
              "Must have enough reserved slots.");

bool
Wrap(JSContext* aCx, mozilla::dom::AddonManager* aObject, nsWrapperCache* aCache, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
{
  static_assert(!std::is_base_of_v<NonRefcountedDOMObject, mozilla::dom::AddonManager>,
                "Shouldn't have wrappercached things that are not refcounted.");
  static_assert(std::is_same_v<decltype(aObject), mozilla::dom::AddonManager*>);
  MOZ_ASSERT(static_cast<mozilla::dom::EventTarget*>(aObject) ==
             reinterpret_cast<mozilla::dom::EventTarget*>(aObject),
             "Multiple inheritance for mozilla::dom::EventTarget is broken.");
  MOZ_ASSERT(ToSupportsIsCorrect(aObject));
  MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
  MOZ_ASSERT(!aCache->GetWrapper(),
             "You should probably not be using Wrap() directly; use "
             "GetOrCreateDOMReflector instead");

  MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
             "nsISupports must be on our primary inheritance chain");

  // If the wrapper cache contains a dead reflector then finalize that
  // now, ensuring that the finalizer for the old reflector always
  // runs before the new reflector is created and attached. This
  // avoids the awkward situation where there are multiple reflector
  // objects that contain pointers to the same native.

  if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) {
    _finalize(nullptr /* unused */, oldReflector);
    MOZ_ASSERT(!aCache->GetWrapperMaybeDead());
  }

  JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
  if (!global) {
    return false;
  }
  MOZ_ASSERT(JS_IsGlobalObject(global));
  JS::AssertObjectIsNotGray(global);

  // That might have ended up wrapping us already, due to the wonders
  // of XBL.  Check for that, and bail out as needed.
  aReflector.set(aCache->GetWrapper());
  if (aReflector) {
#ifdef DEBUG
    AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
#endif // DEBUG
    return true;
  }

  JSAutoRealm ar(aCx, global);
  JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
  if (!canonicalProto) {
    return false;
  }
  JS::Rooted<JSObject*> proto(aCx);
  if (aGivenProto) {
    proto = aGivenProto;
    // Unfortunately, while aGivenProto was in the compartment of aCx
    // coming in, we changed compartments to that of "parent" so may need
    // to wrap the proto here.
    if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) {
      if (!JS_WrapObject(aCx, &proto)) {
        return false;
      }
    }
  } else {
    proto = canonicalProto;
  }

  BindingJSObjectCreator<mozilla::dom::AddonManager> creator(aCx);
  creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
  if (!aReflector) {
    return false;
  }

  aCache->SetWrapper(aReflector);
  creator.InitializationSucceeded();

  MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
             aCache->GetWrapperPreserveColor() == aReflector);
  // If proto != canonicalProto, we have to preserve our wrapper;
  // otherwise we won't be able to properly recreate it later, since
  // we won't know what proto to use.  Note that we don't check
  // aGivenProto here, since it's entirely possible (and even
  // somewhat common) to have a non-null aGivenProto which is the
  // same as canonicalProto.
  if (proto != canonicalProto) {
    PreserveWrapper(aObject);
  }

  return true;
}

void
CreateInterfaceObjects(JSContext* aCx, JS::Handle<JSObject*> aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal)
{
  JS::Heap<JSObject*>* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::AddonManager);
  JS::Heap<JSObject*>* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::AddonManager);

  JS::Handle<JSObject*> parentProto(EventTarget_Binding::GetProtoObjectHandle(aCx));
  if (!parentProto) {
    return;
  }

  JS::Handle<JSObject*> constructorProto(EventTarget_Binding::GetConstructorObjectHandle(aCx));
  if (!constructorProto) {
    return;
  }

  dom::CreateInterfaceObjects(aCx, aGlobal, parentProto,
                              &sPrototypeClass, protoCache,
                              constructorProto, &sInterfaceObjectInfo, 0, false, Span<const LegacyFactoryFunction, 0>{},
                              interfaceCache,
                              sNativeProperties.Upcast(),
                              sChromeOnlyNativeProperties.Upcast(),
                              "AddonManager",
                              ShouldExpose<AddonManager_Binding::ConstructorEnabled>(aCx, aGlobal, aDefineOnGlobal),
                              nullptr,
                              false,
                              nullptr);
}

static JS::Handle<JSObject*>
GetProtoObjectHandle(JSContext* aCx)
{
  /* Get the interface prototype object for this class.  This will create the
     object as needed. */
  return GetPerInterfaceObjectHandle(aCx, prototypes::id::AddonManager,
                                     &CreateInterfaceObjects,
                                     DefineInterfaceProperty::CheckExposure);

}

JS::Handle<JSObject*>
GetConstructorObjectHandle(JSContext* aCx)
{
  /* Get the interface object for this class.  This will create the object as
     needed. */

  return GetPerInterfaceObjectHandle(aCx, constructors::id::AddonManager,
                                     &CreateInterfaceObjects,
                                     DefineInterfaceProperty::CheckExposure);
}

} // namespace AddonManager_Binding



namespace AddonManagerPermissions_Binding {

MOZ_CAN_RUN_SCRIPT static bool
isHostPermitted(JSContext* cx, unsigned argc, JS::Value* vp)
{
  AUTO_PROFILER_LABEL_DYNAMIC_FAST(
    "AddonManagerPermissions", "isHostPermitted", DOM, cx,
    uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
    uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));

  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  JS::Rooted<JSObject*> obj(cx, &args.callee());

  if (!args.requireAtLeast(cx, "AddonManagerPermissions.isHostPermitted", 1)) {
    return false;
  }
  GlobalObject global(cx, xpc::XrayAwareCalleeGlobal(obj));
  if (global.Failed()) {
    return false;
  }

  binding_detail::FakeString<char16_t> arg0;
  if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) {
    return false;
  }
  bool result(mozilla::dom::AddonManagerPermissions::IsHostPermitted(global, NonNullHelper(Constify(arg0))));
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
  args.rval().setBoolean(result);
  return true;
}

MOZ_GLOBINIT static const JSFunctionSpec sStaticMethods_specs[] = {
  JS_FNSPEC("isHostPermitted", isHostPermitted, nullptr, 1, JSPROP_ENUMERATE, nullptr),
  JS_FS_END
};


static const Prefable<const JSFunctionSpec> sStaticMethods[] = {
  { nullptr, &sStaticMethods_specs[0] },
  { nullptr, nullptr }
};

static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
    "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
    "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");


static uint16_t sNativeProperties_sortedPropertyIndices[1];
static PropertyInfo sNativeProperties_propertyInfos[1];

static const NativePropertiesN<1> sNativeProperties = {
  true,  0 /* sStaticMethods */,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  false, 0,
  -1,
  1,
  sNativeProperties_sortedPropertyIndices,
  {
    { sStaticMethods, &sNativeProperties_propertyInfos[0] }
  }
};
static_assert(1 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)),
    "We have a property info count that is oversized");

bool sNativePropertiesInited = false;
const NativePropertyHooks sNativePropertyHooks = {
  nullptr,
  { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited },
  prototypes::id::_ID_Count,
  constructors::id::AddonManagerPermissions,
  &DefaultXrayExpandoObjectClass
};

static const DOMIfaceAndProtoJSClass sNamespaceObjectClass = {
  {
    "AddonManagerPermissions",
    JSCLASS_IS_DOMIFACEANDPROTOJSCLASS,
    JS_NULL_CLASS_OPS,
    JS_NULL_CLASS_SPEC,
    JS_NULL_CLASS_EXT,
    JS_NULL_OBJECT_OPS
  },
  eNamespace,
  prototypes::id::_ID_Count,
  0,
  &sNativePropertyHooks,
  // This isn't strictly following the spec (see
  // https://console.spec.whatwg.org/#ref-for-dfn-namespace-object),
  // but should be ok for Xrays.
  JS::GetRealmObjectPrototype
};

bool
ConstructorEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj)
{
  return nsContentUtils::ThreadsafeIsSystemCaller(aCx);
}

void
CreateInterfaceObjects(JSContext* aCx, JS::Handle<JSObject*> aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal)
{
  JS::Rooted<JSObject*> constructorProto(aCx, JS::GetRealmObjectPrototype(aCx));
  if (!constructorProto) {
    return;
  }

  JS::Heap<JSObject*>* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::AddonManagerPermissions);
  dom::CreateNamespaceObject(aCx, aGlobal, constructorProto,
                             sNamespaceObjectClass,
                             interfaceCache,
                             sNativeProperties.Upcast(),
                             nullptr,
                             "AddonManagerPermissions",
                             ShouldExpose<AddonManagerPermissions_Binding::ConstructorEnabled>(aCx, aGlobal, aDefineOnGlobal));
}

JS::Handle<JSObject*>
GetConstructorObjectHandle(JSContext* aCx)
{
  /* Get the interface object for this class.  This will create the object as
     needed. */

  return GetPerInterfaceObjectHandle(aCx, constructors::id::AddonManagerPermissions,
                                     &CreateInterfaceObjects,
                                     DefineInterfaceProperty::CheckExposure);
}

} // namespace AddonManagerPermissions_Binding



already_AddRefed<Promise>
AddonJSImpl::Uninstall(ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "Addon.uninstall", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return nullptr;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JS::Value> callable(cx);
  AddonAtoms* atomsCache = GetAtomCache<AddonAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
       !InitIds(cx, atomsCache)) ||
      !GetCallableProperty(cx, atomsCache->uninstall_id, &callable)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return nullptr;
  }
  JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));
  if (!JS::Call(cx, thisValue, callable,
                JS::HandleValueArray::empty(), &rval)) {
    aRv.NoteJSContextException(cx);
    return nullptr;
  }
  RefPtr<Promise> rvalDecl;
  { // Scope for our GlobalObject, FastErrorResult, JSAutoRealm,
    // etc.

    JS::Rooted<JSObject*> globalObj(cx);
    if (!rval.isObject()) {
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of Addon.uninstall");
      return nullptr;
    }
    JSObject* unwrappedVal = js::CheckedUnwrapStatic(&rval.toObject());
    if (!unwrappedVal) {
      // A slight lie, but not much of one, for a dead object wrapper.
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of Addon.uninstall");
      return nullptr;
    }
    globalObj = JS::GetNonCCWObjectGlobal(unwrappedVal);
    JSAutoRealm ar(cx, globalObj);
    GlobalObject promiseGlobal(cx, globalObj);
    if (promiseGlobal.Failed()) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }

    JS::Rooted<JS::Value> valueToResolve(cx, rval);
    if (!JS_WrapValue(cx, &valueToResolve)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    binding_detail::FastErrorResult promiseRv;
    nsCOMPtr<nsIGlobalObject> global =
      do_QueryInterface(promiseGlobal.GetAsSupports());
    if (!global) {
      promiseRv.Throw(NS_ERROR_UNEXPECTED);
      MOZ_ALWAYS_TRUE(promiseRv.MaybeSetPendingException(cx));
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    rvalDecl = Promise::Resolve(global, cx, valueToResolve,
                                    promiseRv);
    if (promiseRv.MaybeSetPendingException(cx)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
  }
  return rvalDecl.forget();
}

already_AddRefed<Promise>
AddonJSImpl::SetEnabled(bool value, ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "Addon.setEnabled", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return nullptr;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);
  JS::RootedVector<JS::Value> argv(cx);
  if (!argv.resize(1)) {
    // That threw an exception on the JSContext, and our CallSetup will do
    // the right thing with that.
    return nullptr;
  }
  unsigned argc = 1;

  do {
    argv[0].setBoolean(value);
    break;
  } while (false);

  JS::Rooted<JS::Value> callable(cx);
  AddonAtoms* atomsCache = GetAtomCache<AddonAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
       !InitIds(cx, atomsCache)) ||
      !GetCallableProperty(cx, atomsCache->setEnabled_id, &callable)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return nullptr;
  }
  JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));
  if (!JS::Call(cx, thisValue, callable,
                JS::HandleValueArray::subarray(argv, 0, argc), &rval)) {
    aRv.NoteJSContextException(cx);
    return nullptr;
  }
  RefPtr<Promise> rvalDecl;
  { // Scope for our GlobalObject, FastErrorResult, JSAutoRealm,
    // etc.

    JS::Rooted<JSObject*> globalObj(cx);
    if (!rval.isObject()) {
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of Addon.setEnabled");
      return nullptr;
    }
    JSObject* unwrappedVal = js::CheckedUnwrapStatic(&rval.toObject());
    if (!unwrappedVal) {
      // A slight lie, but not much of one, for a dead object wrapper.
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of Addon.setEnabled");
      return nullptr;
    }
    globalObj = JS::GetNonCCWObjectGlobal(unwrappedVal);
    JSAutoRealm ar(cx, globalObj);
    GlobalObject promiseGlobal(cx, globalObj);
    if (promiseGlobal.Failed()) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }

    JS::Rooted<JS::Value> valueToResolve(cx, rval);
    if (!JS_WrapValue(cx, &valueToResolve)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    binding_detail::FastErrorResult promiseRv;
    nsCOMPtr<nsIGlobalObject> global =
      do_QueryInterface(promiseGlobal.GetAsSupports());
    if (!global) {
      promiseRv.Throw(NS_ERROR_UNEXPECTED);
      MOZ_ALWAYS_TRUE(promiseRv.MaybeSetPendingException(cx));
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    rvalDecl = Promise::Resolve(global, cx, valueToResolve,
                                    promiseRv);
    if (promiseRv.MaybeSetPendingException(cx)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
  }
  return rvalDecl.forget();
}

bool
AddonJSImpl::InitIds(JSContext* cx, AddonAtoms* atomsCache)
{
  MOZ_ASSERT(reinterpret_cast<jsid*>(atomsCache)->isVoid());

  // Initialize these in reverse order so that any failure leaves the first one
  // uninitialized.
  if (!atomsCache->setEnabled_id.init(cx, "setEnabled") ||
      !atomsCache->uninstall_id.init(cx, "uninstall") ||
      !atomsCache->canUninstall_id.init(cx, "canUninstall") ||
      !atomsCache->isActive_id.init(cx, "isActive") ||
      !atomsCache->isEnabled_id.init(cx, "isEnabled") ||
      !atomsCache->description_id.init(cx, "description") ||
      !atomsCache->name_id.init(cx, "name") ||
      !atomsCache->type_id.init(cx, "type") ||
      !atomsCache->version_id.init(cx, "version") ||
      !atomsCache->id_id.init(cx, "id")) {
    return false;
  }
  return true;
}


void
AddonJSImpl::GetId(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "Addon.id", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JSObject *> callback(cx, mCallback);
  AddonAtoms* atomsCache = GetAtomCache<AddonAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
       && !InitIds(cx, atomsCache)) ||
      !JS_GetPropertyById(cx, callback, atomsCache->id_id, &rval)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  binding_detail::FakeString<char16_t> rvalDecl;
  if (!ConvertJSValueToString(cx, rval, eStringify, eStringify, rvalDecl)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  aRetVal = rvalDecl;
}

void
AddonJSImpl::GetVersion(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "Addon.version", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JSObject *> callback(cx, mCallback);
  AddonAtoms* atomsCache = GetAtomCache<AddonAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
       && !InitIds(cx, atomsCache)) ||
      !JS_GetPropertyById(cx, callback, atomsCache->version_id, &rval)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  binding_detail::FakeString<char16_t> rvalDecl;
  if (!ConvertJSValueToString(cx, rval, eStringify, eStringify, rvalDecl)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  aRetVal = rvalDecl;
}

void
AddonJSImpl::GetType(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "Addon.type", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JSObject *> callback(cx, mCallback);
  AddonAtoms* atomsCache = GetAtomCache<AddonAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
       && !InitIds(cx, atomsCache)) ||
      !JS_GetPropertyById(cx, callback, atomsCache->type_id, &rval)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  binding_detail::FakeString<char16_t> rvalDecl;
  if (!ConvertJSValueToString(cx, rval, eStringify, eStringify, rvalDecl)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  aRetVal = rvalDecl;
}

void
AddonJSImpl::GetName(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "Addon.name", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JSObject *> callback(cx, mCallback);
  AddonAtoms* atomsCache = GetAtomCache<AddonAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
       && !InitIds(cx, atomsCache)) ||
      !JS_GetPropertyById(cx, callback, atomsCache->name_id, &rval)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  binding_detail::FakeString<char16_t> rvalDecl;
  if (!ConvertJSValueToString(cx, rval, eStringify, eStringify, rvalDecl)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  aRetVal = rvalDecl;
}

void
AddonJSImpl::GetDescription(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "Addon.description", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JSObject *> callback(cx, mCallback);
  AddonAtoms* atomsCache = GetAtomCache<AddonAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
       && !InitIds(cx, atomsCache)) ||
      !JS_GetPropertyById(cx, callback, atomsCache->description_id, &rval)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  binding_detail::FakeString<char16_t> rvalDecl;
  if (!ConvertJSValueToString(cx, rval, eStringify, eStringify, rvalDecl)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  aRetVal = rvalDecl;
}

bool
AddonJSImpl::GetIsEnabled(ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "Addon.isEnabled", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return bool(0);
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JSObject *> callback(cx, mCallback);
  AddonAtoms* atomsCache = GetAtomCache<AddonAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
       && !InitIds(cx, atomsCache)) ||
      !JS_GetPropertyById(cx, callback, atomsCache->isEnabled_id, &rval)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return bool(0);
  }
  bool rvalDecl;
  if (!ValueToPrimitive<bool, eDefault>(cx, rval, "Return value of Addon.isEnabled", &rvalDecl)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return bool(0);
  }
  return rvalDecl;
}

bool
AddonJSImpl::GetIsActive(ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "Addon.isActive", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return bool(0);
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JSObject *> callback(cx, mCallback);
  AddonAtoms* atomsCache = GetAtomCache<AddonAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
       && !InitIds(cx, atomsCache)) ||
      !JS_GetPropertyById(cx, callback, atomsCache->isActive_id, &rval)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return bool(0);
  }
  bool rvalDecl;
  if (!ValueToPrimitive<bool, eDefault>(cx, rval, "Return value of Addon.isActive", &rvalDecl)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return bool(0);
  }
  return rvalDecl;
}

bool
AddonJSImpl::GetCanUninstall(ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "Addon.canUninstall", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return bool(0);
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JSObject *> callback(cx, mCallback);
  AddonAtoms* atomsCache = GetAtomCache<AddonAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
       && !InitIds(cx, atomsCache)) ||
      !JS_GetPropertyById(cx, callback, atomsCache->canUninstall_id, &rval)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return bool(0);
  }
  bool rvalDecl;
  if (!ValueToPrimitive<bool, eDefault>(cx, rval, "Return value of Addon.canUninstall", &rvalDecl)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return bool(0);
  }
  return rvalDecl;
}


NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Addon)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Addon)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mImpl)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
  tmp->ClearWeakReferences();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Addon)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(Addon)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Addon)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Addon)
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  NS_INTERFACE_MAP_ENTRY(nsISupports)
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END

Addon::Addon(JS::Handle<JSObject*> aJSImplObject, JS::Handle<JSObject*> aJSImplGlobal, nsIGlobalObject* aParent)
  : mImpl(new AddonJSImpl(nullptr, aJSImplObject, aJSImplGlobal, /* aIncumbentGlobal = */ nullptr)),
    mParent(aParent)
{
}


Addon::~Addon()
{
}

nsISupports*
Addon::GetParentObject() const
{
  return mParent;
}

JSObject*
Addon::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
  JS::Rooted<JSObject*> obj(aCx, Addon_Binding::Wrap(aCx, this, aGivenProto));
  if (!obj) {
    return nullptr;
  }

  // Now define it on our chrome object
  JSAutoRealm ar(aCx, mImpl->CallbackGlobalOrNull());
  if (!JS_WrapObject(aCx, &obj)) {
    return nullptr;
  }
  JS::Rooted<JSObject*> callback(aCx, mImpl->CallbackOrNull());
  if (!JS_DefineProperty(aCx, callback, "__DOM_IMPL__", obj, 0)) {
    return nullptr;
  }
  return obj;
}

void
Addon::GetId(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm) const
{
  return mImpl->GetId(aRetVal, aRv, aRealm);
}

void
Addon::GetVersion(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm) const
{
  return mImpl->GetVersion(aRetVal, aRv, aRealm);
}

void
Addon::GetType(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm) const
{
  return mImpl->GetType(aRetVal, aRv, aRealm);
}

void
Addon::GetName(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm) const
{
  return mImpl->GetName(aRetVal, aRv, aRealm);
}

void
Addon::GetDescription(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm) const
{
  return mImpl->GetDescription(aRetVal, aRv, aRealm);
}

bool
Addon::GetIsEnabled(ErrorResult& aRv, JS::Realm* aRealm) const
{
  return mImpl->GetIsEnabled(aRv, aRealm);
}

bool
Addon::GetIsActive(ErrorResult& aRv, JS::Realm* aRealm) const
{
  return mImpl->GetIsActive(aRv, aRealm);
}

bool
Addon::GetCanUninstall(ErrorResult& aRv, JS::Realm* aRealm) const
{
  return mImpl->GetCanUninstall(aRv, aRealm);
}

// Return a raw pointer here to avoid refcounting, but make sure it's safe (the object should be kept alive by the callee).
already_AddRefed<Promise>
Addon::Uninstall(ErrorResult& aRv, JS::Realm* aRealm)
{
  return mImpl->Uninstall(aRv, aRealm);
}

// Return a raw pointer here to avoid refcounting, but make sure it's safe (the object should be kept alive by the callee).
already_AddRefed<Promise>
Addon::SetEnabled(bool value, ErrorResult& aRv, JS::Realm* aRealm)
{
  return mImpl->SetEnabled(value, aRv, aRealm);
}

bool
Addon::_Create(JSContext* cx, unsigned argc, JS::Value* vp)
{
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  if (!args.requireAtLeast(cx, "Addon._create", 2)) {
    return false;
  }
  BindingCallContext callCx(cx, "Addon._create");
  if (!args[0].isObject()) {
    return callCx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 1");
  }
  if (!args[1].isObject()) {
    return callCx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 2");
  }

  // GlobalObject will go through wrappers as needed for us, and
  // is simpler than the right UnwrapArg incantation.
  GlobalObject global(cx, &args[0].toObject());
  if (global.Failed()) {
    return false;
  }
  nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(global.GetAsSupports());
  MOZ_ASSERT(globalHolder);
  JS::Rooted<JSObject*> arg(cx, &args[1].toObject());
  JS::Rooted<JSObject*> argGlobal(cx, JS::CurrentGlobalOrNull(cx));
  RefPtr<Addon> impl = new Addon(arg, argGlobal, globalHolder);
  MOZ_ASSERT(js::IsObjectInContextCompartment(arg, cx));
  return GetOrCreateDOMReflector(cx, impl, args.rval());
}


already_AddRefed<Promise>
AddonInstallJSImpl::Install(ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "AddonInstall.install", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return nullptr;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JS::Value> callable(cx);
  AddonInstallAtoms* atomsCache = GetAtomCache<AddonInstallAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
       !InitIds(cx, atomsCache)) ||
      !GetCallableProperty(cx, atomsCache->install_id, &callable)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return nullptr;
  }
  JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));
  if (!JS::Call(cx, thisValue, callable,
                JS::HandleValueArray::empty(), &rval)) {
    aRv.NoteJSContextException(cx);
    return nullptr;
  }
  RefPtr<Promise> rvalDecl;
  { // Scope for our GlobalObject, FastErrorResult, JSAutoRealm,
    // etc.

    JS::Rooted<JSObject*> globalObj(cx);
    if (!rval.isObject()) {
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of AddonInstall.install");
      return nullptr;
    }
    JSObject* unwrappedVal = js::CheckedUnwrapStatic(&rval.toObject());
    if (!unwrappedVal) {
      // A slight lie, but not much of one, for a dead object wrapper.
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of AddonInstall.install");
      return nullptr;
    }
    globalObj = JS::GetNonCCWObjectGlobal(unwrappedVal);
    JSAutoRealm ar(cx, globalObj);
    GlobalObject promiseGlobal(cx, globalObj);
    if (promiseGlobal.Failed()) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }

    JS::Rooted<JS::Value> valueToResolve(cx, rval);
    if (!JS_WrapValue(cx, &valueToResolve)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    binding_detail::FastErrorResult promiseRv;
    nsCOMPtr<nsIGlobalObject> global =
      do_QueryInterface(promiseGlobal.GetAsSupports());
    if (!global) {
      promiseRv.Throw(NS_ERROR_UNEXPECTED);
      MOZ_ALWAYS_TRUE(promiseRv.MaybeSetPendingException(cx));
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    rvalDecl = Promise::Resolve(global, cx, valueToResolve,
                                    promiseRv);
    if (promiseRv.MaybeSetPendingException(cx)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
  }
  return rvalDecl.forget();
}

already_AddRefed<Promise>
AddonInstallJSImpl::Cancel(ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "AddonInstall.cancel", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return nullptr;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JS::Value> callable(cx);
  AddonInstallAtoms* atomsCache = GetAtomCache<AddonInstallAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
       !InitIds(cx, atomsCache)) ||
      !GetCallableProperty(cx, atomsCache->cancel_id, &callable)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return nullptr;
  }
  JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));
  if (!JS::Call(cx, thisValue, callable,
                JS::HandleValueArray::empty(), &rval)) {
    aRv.NoteJSContextException(cx);
    return nullptr;
  }
  RefPtr<Promise> rvalDecl;
  { // Scope for our GlobalObject, FastErrorResult, JSAutoRealm,
    // etc.

    JS::Rooted<JSObject*> globalObj(cx);
    if (!rval.isObject()) {
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of AddonInstall.cancel");
      return nullptr;
    }
    JSObject* unwrappedVal = js::CheckedUnwrapStatic(&rval.toObject());
    if (!unwrappedVal) {
      // A slight lie, but not much of one, for a dead object wrapper.
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of AddonInstall.cancel");
      return nullptr;
    }
    globalObj = JS::GetNonCCWObjectGlobal(unwrappedVal);
    JSAutoRealm ar(cx, globalObj);
    GlobalObject promiseGlobal(cx, globalObj);
    if (promiseGlobal.Failed()) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }

    JS::Rooted<JS::Value> valueToResolve(cx, rval);
    if (!JS_WrapValue(cx, &valueToResolve)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    binding_detail::FastErrorResult promiseRv;
    nsCOMPtr<nsIGlobalObject> global =
      do_QueryInterface(promiseGlobal.GetAsSupports());
    if (!global) {
      promiseRv.Throw(NS_ERROR_UNEXPECTED);
      MOZ_ALWAYS_TRUE(promiseRv.MaybeSetPendingException(cx));
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    rvalDecl = Promise::Resolve(global, cx, valueToResolve,
                                    promiseRv);
    if (promiseRv.MaybeSetPendingException(cx)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
  }
  return rvalDecl.forget();
}

bool
AddonInstallJSImpl::InitIds(JSContext* cx, AddonInstallAtoms* atomsCache)
{
  MOZ_ASSERT(reinterpret_cast<jsid*>(atomsCache)->isVoid());

  // Initialize these in reverse order so that any failure leaves the first one
  // uninitialized.
  if (!atomsCache->cancel_id.init(cx, "cancel") ||
      !atomsCache->install_id.init(cx, "install") ||
      !atomsCache->maxProgress_id.init(cx, "maxProgress") ||
      !atomsCache->progress_id.init(cx, "progress") ||
      !atomsCache->error_id.init(cx, "error") ||
      !atomsCache->state_id.init(cx, "state")) {
    return false;
  }
  return true;
}


void
AddonInstallJSImpl::GetState(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "AddonInstall.state", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JSObject *> callback(cx, mCallback);
  AddonInstallAtoms* atomsCache = GetAtomCache<AddonInstallAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
       && !InitIds(cx, atomsCache)) ||
      !JS_GetPropertyById(cx, callback, atomsCache->state_id, &rval)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  binding_detail::FakeString<char16_t> rvalDecl;
  if (!ConvertJSValueToString(cx, rval, eStringify, eStringify, rvalDecl)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  aRetVal = rvalDecl;
}

void
AddonInstallJSImpl::GetError(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "AddonInstall.error", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JSObject *> callback(cx, mCallback);
  AddonInstallAtoms* atomsCache = GetAtomCache<AddonInstallAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
       && !InitIds(cx, atomsCache)) ||
      !JS_GetPropertyById(cx, callback, atomsCache->error_id, &rval)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  binding_detail::FakeString<char16_t> rvalDecl;
  if (!ConvertJSValueToString(cx, rval, eNull, eNull, rvalDecl)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  aRetVal = rvalDecl;
}

int64_t
AddonInstallJSImpl::GetProgress(ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "AddonInstall.progress", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return int64_t(0);
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JSObject *> callback(cx, mCallback);
  AddonInstallAtoms* atomsCache = GetAtomCache<AddonInstallAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
       && !InitIds(cx, atomsCache)) ||
      !JS_GetPropertyById(cx, callback, atomsCache->progress_id, &rval)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return int64_t(0);
  }
  int64_t rvalDecl;
  if (!ValueToPrimitive<int64_t, eDefault>(cx, rval, "Return value of AddonInstall.progress", &rvalDecl)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return int64_t(0);
  }
  return rvalDecl;
}

int64_t
AddonInstallJSImpl::GetMaxProgress(ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "AddonInstall.maxProgress", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return int64_t(0);
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);

  JS::Rooted<JSObject *> callback(cx, mCallback);
  AddonInstallAtoms* atomsCache = GetAtomCache<AddonInstallAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
       && !InitIds(cx, atomsCache)) ||
      !JS_GetPropertyById(cx, callback, atomsCache->maxProgress_id, &rval)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return int64_t(0);
  }
  int64_t rvalDecl;
  if (!ValueToPrimitive<int64_t, eDefault>(cx, rval, "Return value of AddonInstall.maxProgress", &rvalDecl)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return int64_t(0);
  }
  return rvalDecl;
}


NS_IMPL_CYCLE_COLLECTION_INHERITED(AddonInstall, mozilla::DOMEventTargetHelper, mImpl, mParent)
NS_IMPL_ADDREF_INHERITED(AddonInstall, mozilla::DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(AddonInstall, mozilla::DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AddonInstall)
NS_INTERFACE_MAP_END_INHERITING(mozilla::DOMEventTargetHelper)

AddonInstall::AddonInstall(JS::Handle<JSObject*> aJSImplObject, JS::Handle<JSObject*> aJSImplGlobal, nsIGlobalObject* aParent)
  : mozilla::DOMEventTargetHelper(aParent),
    mImpl(new AddonInstallJSImpl(nullptr, aJSImplObject, aJSImplGlobal, /* aIncumbentGlobal = */ nullptr)),
    mParent(aParent)
{
}


AddonInstall::~AddonInstall()
{
}

nsISupports*
AddonInstall::GetParentObject() const
{
  return mParent;
}

JSObject*
AddonInstall::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
  JS::Rooted<JSObject*> obj(aCx, AddonInstall_Binding::Wrap(aCx, this, aGivenProto));
  if (!obj) {
    return nullptr;
  }

  // Now define it on our chrome object
  JSAutoRealm ar(aCx, mImpl->CallbackGlobalOrNull());
  if (!JS_WrapObject(aCx, &obj)) {
    return nullptr;
  }
  JS::Rooted<JSObject*> callback(aCx, mImpl->CallbackOrNull());
  if (!JS_DefineProperty(aCx, callback, "__DOM_IMPL__", obj, 0)) {
    return nullptr;
  }
  return obj;
}

void
AddonInstall::GetState(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm) const
{
  return mImpl->GetState(aRetVal, aRv, aRealm);
}

void
AddonInstall::GetError(nsString& aRetVal, ErrorResult& aRv, JS::Realm* aRealm) const
{
  return mImpl->GetError(aRetVal, aRv, aRealm);
}

int64_t
AddonInstall::GetProgress(ErrorResult& aRv, JS::Realm* aRealm) const
{
  return mImpl->GetProgress(aRv, aRealm);
}

int64_t
AddonInstall::GetMaxProgress(ErrorResult& aRv, JS::Realm* aRealm) const
{
  return mImpl->GetMaxProgress(aRv, aRealm);
}

// Return a raw pointer here to avoid refcounting, but make sure it's safe (the object should be kept alive by the callee).
already_AddRefed<Promise>
AddonInstall::Install(ErrorResult& aRv, JS::Realm* aRealm)
{
  return mImpl->Install(aRv, aRealm);
}

// Return a raw pointer here to avoid refcounting, but make sure it's safe (the object should be kept alive by the callee).
already_AddRefed<Promise>
AddonInstall::Cancel(ErrorResult& aRv, JS::Realm* aRealm)
{
  return mImpl->Cancel(aRv, aRealm);
}

bool
AddonInstall::_Create(JSContext* cx, unsigned argc, JS::Value* vp)
{
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  if (!args.requireAtLeast(cx, "AddonInstall._create", 2)) {
    return false;
  }
  BindingCallContext callCx(cx, "AddonInstall._create");
  if (!args[0].isObject()) {
    return callCx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 1");
  }
  if (!args[1].isObject()) {
    return callCx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 2");
  }

  // GlobalObject will go through wrappers as needed for us, and
  // is simpler than the right UnwrapArg incantation.
  GlobalObject global(cx, &args[0].toObject());
  if (global.Failed()) {
    return false;
  }
  nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(global.GetAsSupports());
  MOZ_ASSERT(globalHolder);
  JS::Rooted<JSObject*> arg(cx, &args[1].toObject());
  JS::Rooted<JSObject*> argGlobal(cx, JS::CurrentGlobalOrNull(cx));
  RefPtr<AddonInstall> impl = new AddonInstall(arg, argGlobal, globalHolder);
  MOZ_ASSERT(js::IsObjectInContextCompartment(arg, cx));
  return GetOrCreateDOMReflector(cx, impl, args.rval());
}


already_AddRefed<Promise>
AddonManagerJSImpl::GetAddonByID(const nsAString& id, ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "AddonManager.getAddonByID", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return nullptr;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);
  JS::RootedVector<JS::Value> argv(cx);
  if (!argv.resize(1)) {
    // That threw an exception on the JSContext, and our CallSetup will do
    // the right thing with that.
    return nullptr;
  }
  unsigned argc = 1;

  do {
    if (!xpc::NonVoidStringToJsval(cx, id, argv[0])) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    break;
  } while (false);

  JS::Rooted<JS::Value> callable(cx);
  AddonManagerAtoms* atomsCache = GetAtomCache<AddonManagerAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
       !InitIds(cx, atomsCache)) ||
      !GetCallableProperty(cx, atomsCache->getAddonByID_id, &callable)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return nullptr;
  }
  JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));
  if (!JS::Call(cx, thisValue, callable,
                JS::HandleValueArray::subarray(argv, 0, argc), &rval)) {
    aRv.NoteJSContextException(cx);
    return nullptr;
  }
  RefPtr<Promise> rvalDecl;
  { // Scope for our GlobalObject, FastErrorResult, JSAutoRealm,
    // etc.

    JS::Rooted<JSObject*> globalObj(cx);
    if (!rval.isObject()) {
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of AddonManager.getAddonByID");
      return nullptr;
    }
    JSObject* unwrappedVal = js::CheckedUnwrapStatic(&rval.toObject());
    if (!unwrappedVal) {
      // A slight lie, but not much of one, for a dead object wrapper.
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of AddonManager.getAddonByID");
      return nullptr;
    }
    globalObj = JS::GetNonCCWObjectGlobal(unwrappedVal);
    JSAutoRealm ar(cx, globalObj);
    GlobalObject promiseGlobal(cx, globalObj);
    if (promiseGlobal.Failed()) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }

    JS::Rooted<JS::Value> valueToResolve(cx, rval);
    if (!JS_WrapValue(cx, &valueToResolve)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    binding_detail::FastErrorResult promiseRv;
    nsCOMPtr<nsIGlobalObject> global =
      do_QueryInterface(promiseGlobal.GetAsSupports());
    if (!global) {
      promiseRv.Throw(NS_ERROR_UNEXPECTED);
      MOZ_ALWAYS_TRUE(promiseRv.MaybeSetPendingException(cx));
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    rvalDecl = Promise::Resolve(global, cx, valueToResolve,
                                    promiseRv);
    if (promiseRv.MaybeSetPendingException(cx)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
  }
  return rvalDecl.forget();
}

already_AddRefed<Promise>
AddonManagerJSImpl::CreateInstall(const addonInstallOptions& options, ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "AddonManager.createInstall", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return nullptr;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);
  JS::RootedVector<JS::Value> argv(cx);
  if (!argv.resize(1)) {
    // That threw an exception on the JSContext, and our CallSetup will do
    // the right thing with that.
    return nullptr;
  }
  unsigned argc = 1;

  do {
    if (!options.ToObjectInternal(cx, argv[0])) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    break;
  } while (false);

  JS::Rooted<JS::Value> callable(cx);
  AddonManagerAtoms* atomsCache = GetAtomCache<AddonManagerAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
       !InitIds(cx, atomsCache)) ||
      !GetCallableProperty(cx, atomsCache->createInstall_id, &callable)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return nullptr;
  }
  JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));
  if (!JS::Call(cx, thisValue, callable,
                JS::HandleValueArray::subarray(argv, 0, argc), &rval)) {
    aRv.NoteJSContextException(cx);
    return nullptr;
  }
  RefPtr<Promise> rvalDecl;
  { // Scope for our GlobalObject, FastErrorResult, JSAutoRealm,
    // etc.

    JS::Rooted<JSObject*> globalObj(cx);
    if (!rval.isObject()) {
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of AddonManager.createInstall");
      return nullptr;
    }
    JSObject* unwrappedVal = js::CheckedUnwrapStatic(&rval.toObject());
    if (!unwrappedVal) {
      // A slight lie, but not much of one, for a dead object wrapper.
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of AddonManager.createInstall");
      return nullptr;
    }
    globalObj = JS::GetNonCCWObjectGlobal(unwrappedVal);
    JSAutoRealm ar(cx, globalObj);
    GlobalObject promiseGlobal(cx, globalObj);
    if (promiseGlobal.Failed()) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }

    JS::Rooted<JS::Value> valueToResolve(cx, rval);
    if (!JS_WrapValue(cx, &valueToResolve)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    binding_detail::FastErrorResult promiseRv;
    nsCOMPtr<nsIGlobalObject> global =
      do_QueryInterface(promiseGlobal.GetAsSupports());
    if (!global) {
      promiseRv.Throw(NS_ERROR_UNEXPECTED);
      MOZ_ALWAYS_TRUE(promiseRv.MaybeSetPendingException(cx));
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    rvalDecl = Promise::Resolve(global, cx, valueToResolve,
                                    promiseRv);
    if (promiseRv.MaybeSetPendingException(cx)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
  }
  return rvalDecl.forget();
}

already_AddRefed<Promise>
AddonManagerJSImpl::SendAbuseReport(const nsAString& addonId, const Record<nsString, nsString>& data, const sendAbuseReportOptions& options, ErrorResult& aRv, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "AddonManager.sendAbuseReport", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ true);
  if (aRv.Failed()) {
    return nullptr;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);
  JS::RootedVector<JS::Value> argv(cx);
  if (!argv.resize(3)) {
    // That threw an exception on the JSContext, and our CallSetup will do
    // the right thing with that.
    return nullptr;
  }
  unsigned argc = 3;

  do {
    if (!options.ToObjectInternal(cx, argv[2])) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    break;
  } while (false);

  do {

    JS::Rooted<JSObject*> returnObj(cx, JS_NewPlainObject(cx));
    if (!returnObj) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    // Scope for 'tmp'
    {
      JS::Rooted<JS::Value> tmp(cx);
      for (auto& entry : data.Entries()) {
        auto& recordValue0 = entry.mValue;
        // Control block to let us common up the JS_DefineUCProperty calls when there
        // are different ways to succeed at wrapping the value.
        do {
          if (!xpc::StringToJsval(cx, recordValue0, &tmp)) {
            aRv.Throw(NS_ERROR_UNEXPECTED);
            return nullptr;
          }
          break;
        } while (false);
        if (!JS_DefineUCProperty(cx, returnObj,
                                 entry.mKey.BeginReading(),
                                 entry.mKey.Length(), tmp,
                                 JSPROP_ENUMERATE)) {
          aRv.Throw(NS_ERROR_UNEXPECTED);
          return nullptr;
        }
      }
    }
    argv[1].setObject(*returnObj);
    break;
  } while (false);

  do {
    if (!xpc::NonVoidStringToJsval(cx, addonId, argv[0])) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    break;
  } while (false);

  JS::Rooted<JS::Value> callable(cx);
  AddonManagerAtoms* atomsCache = GetAtomCache<AddonManagerAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
       !InitIds(cx, atomsCache)) ||
      !GetCallableProperty(cx, atomsCache->sendAbuseReport_id, &callable)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return nullptr;
  }
  JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));
  if (!JS::Call(cx, thisValue, callable,
                JS::HandleValueArray::subarray(argv, 0, argc), &rval)) {
    aRv.NoteJSContextException(cx);
    return nullptr;
  }
  RefPtr<Promise> rvalDecl;
  { // Scope for our GlobalObject, FastErrorResult, JSAutoRealm,
    // etc.

    JS::Rooted<JSObject*> globalObj(cx);
    if (!rval.isObject()) {
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of AddonManager.sendAbuseReport");
      return nullptr;
    }
    JSObject* unwrappedVal = js::CheckedUnwrapStatic(&rval.toObject());
    if (!unwrappedVal) {
      // A slight lie, but not much of one, for a dead object wrapper.
      aRv.ThrowTypeError<MSG_NOT_OBJECT>("return value of AddonManager.sendAbuseReport");
      return nullptr;
    }
    globalObj = JS::GetNonCCWObjectGlobal(unwrappedVal);
    JSAutoRealm ar(cx, globalObj);
    GlobalObject promiseGlobal(cx, globalObj);
    if (promiseGlobal.Failed()) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }

    JS::Rooted<JS::Value> valueToResolve(cx, rval);
    if (!JS_WrapValue(cx, &valueToResolve)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    binding_detail::FastErrorResult promiseRv;
    nsCOMPtr<nsIGlobalObject> global =
      do_QueryInterface(promiseGlobal.GetAsSupports());
    if (!global) {
      promiseRv.Throw(NS_ERROR_UNEXPECTED);
      MOZ_ALWAYS_TRUE(promiseRv.MaybeSetPendingException(cx));
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
    rvalDecl = Promise::Resolve(global, cx, valueToResolve,
                                    promiseRv);
    if (promiseRv.MaybeSetPendingException(cx)) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return nullptr;
    }
  }
  return rvalDecl.forget();
}

void
AddonManagerJSImpl::EventListenerAdded(const nsAString& aType, ErrorResult& aRv, const char* aExecutionReason, ExceptionHandling aExceptionHandling, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "EventListenerAdded", aExceptionHandling, aRealm);
  if (aRv.Failed()) {
    return;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);
  JS::RootedVector<JS::Value> argv(cx);
  if (!argv.resize(1)) {
    // That threw an exception on the JSContext, and our CallSetup will do
    // the right thing with that.
    return;
  }
  unsigned argc = 1;

  do {
    if (!xpc::NonVoidStringToJsval(cx, aType, argv[0])) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return;
    }
    break;
  } while (false);

  JS::Rooted<JS::Value> callable(cx);
  AddonManagerAtoms* atomsCache = GetAtomCache<AddonManagerAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
       !InitIds(cx, atomsCache)) ||
      !GetCallableProperty(cx, atomsCache->eventListenerAdded_id, &callable)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));
  if (!JS::Call(cx, thisValue, callable,
                JS::HandleValueArray::subarray(argv, 0, argc), &rval)) {
    aRv.NoteJSContextException(cx);
    return;
  }
}

void
AddonManagerJSImpl::EventListenerRemoved(const nsAString& aType, ErrorResult& aRv, const char* aExecutionReason, ExceptionHandling aExceptionHandling, JS::Realm* aRealm)
{
  CallSetup s(this, aRv, "EventListenerRemoved", aExceptionHandling, aRealm);
  if (aRv.Failed()) {
    return;
  }
  MOZ_ASSERT(s.GetContext());
  BindingCallContext& cx = s.GetCallContext();

  JS::Rooted<JS::Value> rval(cx);
  JS::RootedVector<JS::Value> argv(cx);
  if (!argv.resize(1)) {
    // That threw an exception on the JSContext, and our CallSetup will do
    // the right thing with that.
    return;
  }
  unsigned argc = 1;

  do {
    if (!xpc::NonVoidStringToJsval(cx, aType, argv[0])) {
      aRv.Throw(NS_ERROR_UNEXPECTED);
      return;
    }
    break;
  } while (false);

  JS::Rooted<JS::Value> callable(cx);
  AddonManagerAtoms* atomsCache = GetAtomCache<AddonManagerAtoms>(cx);
  if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
       !InitIds(cx, atomsCache)) ||
      !GetCallableProperty(cx, atomsCache->eventListenerRemoved_id, &callable)) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }
  JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));
  if (!JS::Call(cx, thisValue, callable,
                JS::HandleValueArray::subarray(argv, 0, argc), &rval)) {
    aRv.NoteJSContextException(cx);
    return;
  }
}

bool
AddonManagerJSImpl::InitIds(JSContext* cx, AddonManagerAtoms* atomsCache)
{
  MOZ_ASSERT(reinterpret_cast<jsid*>(atomsCache)->isVoid());

  // Initialize these in reverse order so that any failure leaves the first one
  // uninitialized.
  if (!atomsCache->eventListenerRemoved_id.init(cx, "eventListenerRemoved") ||
      !atomsCache->eventListenerAdded_id.init(cx, "eventListenerAdded") ||
      !atomsCache->sendAbuseReport_id.init(cx, "sendAbuseReport") ||
      !atomsCache->createInstall_id.init(cx, "createInstall") ||
      !atomsCache->getAddonByID_id.init(cx, "getAddonByID")) {
    return false;
  }
  return true;
}



NS_IMPL_CYCLE_COLLECTION_INHERITED(AddonManager, mozilla::DOMEventTargetHelper, mImpl, mParent)
NS_IMPL_ADDREF_INHERITED(AddonManager, mozilla::DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(AddonManager, mozilla::DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AddonManager)
NS_INTERFACE_MAP_END_INHERITING(mozilla::DOMEventTargetHelper)

AddonManager::AddonManager(JS::Handle<JSObject*> aJSImplObject, JS::Handle<JSObject*> aJSImplGlobal, nsIGlobalObject* aParent)
  : mozilla::DOMEventTargetHelper(aParent),
    mImpl(new AddonManagerJSImpl(nullptr, aJSImplObject, aJSImplGlobal, /* aIncumbentGlobal = */ nullptr)),
    mParent(aParent)
{
}


AddonManager::~AddonManager()
{
}

nsISupports*
AddonManager::GetParentObject() const
{
  return mParent;
}

JSObject*
AddonManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
  JS::Rooted<JSObject*> obj(aCx, AddonManager_Binding::Wrap(aCx, this, aGivenProto));
  if (!obj) {
    return nullptr;
  }

  // Now define it on our chrome object
  JSAutoRealm ar(aCx, mImpl->CallbackGlobalOrNull());
  if (!JS_WrapObject(aCx, &obj)) {
    return nullptr;
  }
  JS::Rooted<JSObject*> callback(aCx, mImpl->CallbackOrNull());
  if (!JS_DefineProperty(aCx, callback, "__DOM_IMPL__", obj, 0)) {
    return nullptr;
  }
  return obj;
}

// Return a raw pointer here to avoid refcounting, but make sure it's safe (the object should be kept alive by the callee).
already_AddRefed<Promise>
AddonManager::GetAddonByID(const nsAString& id, ErrorResult& aRv, JS::Realm* aRealm)
{
  return mImpl->GetAddonByID(id, aRv, aRealm);
}

// Return a raw pointer here to avoid refcounting, but make sure it's safe (the object should be kept alive by the callee).
already_AddRefed<Promise>
AddonManager::CreateInstall(const addonInstallOptions& options, ErrorResult& aRv, JS::Realm* aRealm)
{
  return mImpl->CreateInstall(options, aRv, aRealm);
}

already_AddRefed<Promise>
AddonManager::SendAbuseReport(const nsAString& addonId, const Record<nsString, nsString>& data, const sendAbuseReportOptions& options, ErrorResult& aRv, JS::Realm* aRealm)
{
  return mImpl->SendAbuseReport(addonId, data, options, aRv, aRealm);
}

void
AddonManager::EventListenerAdded(nsAtom* aType)
{
  mozilla::DOMEventTargetHelper::EventListenerAdded(aType);
  mImpl->EventListenerAdded(Substring(nsDependentAtomString(aType), 2), IgnoreErrors());
}


void
AddonManager::EventListenerRemoved(nsAtom* aType)
{
  mozilla::DOMEventTargetHelper::EventListenerRemoved(aType);
  mImpl->EventListenerRemoved(Substring(nsDependentAtomString(aType), 2), IgnoreErrors());
}


bool
AddonManager::_Create(JSContext* cx, unsigned argc, JS::Value* vp)
{
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  if (!args.requireAtLeast(cx, "AddonManager._create", 2)) {
    return false;
  }
  BindingCallContext callCx(cx, "AddonManager._create");
  if (!args[0].isObject()) {
    return callCx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 1");
  }
  if (!args[1].isObject()) {
    return callCx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 2");
  }

  // GlobalObject will go through wrappers as needed for us, and
  // is simpler than the right UnwrapArg incantation.
  GlobalObject global(cx, &args[0].toObject());
  if (global.Failed()) {
    return false;
  }
  nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(global.GetAsSupports());
  MOZ_ASSERT(globalHolder);
  JS::Rooted<JSObject*> arg(cx, &args[1].toObject());
  JS::Rooted<JSObject*> argGlobal(cx, JS::CurrentGlobalOrNull(cx));
  RefPtr<AddonManager> impl = new AddonManager(arg, argGlobal, globalHolder);
  MOZ_ASSERT(js::IsObjectInContextCompartment(arg, cx));
  return GetOrCreateDOMReflector(cx, impl, args.rval());
}


} // namespace mozilla::dom
