dom/bindings/BindingUtils.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/bindings/BindingUtils.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2392 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
     1.5 +/* vim: set ts=2 sw=2 et tw=79: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "BindingUtils.h"
    1.11 +
    1.12 +#include <algorithm>
    1.13 +#include <stdarg.h>
    1.14 +
    1.15 +#include "JavaScriptParent.h"
    1.16 +
    1.17 +#include "mozilla/DebugOnly.h"
    1.18 +#include "mozilla/FloatingPoint.h"
    1.19 +#include "mozilla/Assertions.h"
    1.20 +
    1.21 +#include "AccessCheck.h"
    1.22 +#include "jsfriendapi.h"
    1.23 +#include "js/OldDebugAPI.h"
    1.24 +#include "nsContentUtils.h"
    1.25 +#include "nsIDOMGlobalPropertyInitializer.h"
    1.26 +#include "nsIPrincipal.h"
    1.27 +#include "nsIXPConnect.h"
    1.28 +#include "WrapperFactory.h"
    1.29 +#include "xpcprivate.h"
    1.30 +#include "XPCQuickStubs.h"
    1.31 +#include "XrayWrapper.h"
    1.32 +#include "nsPrintfCString.h"
    1.33 +#include "prprf.h"
    1.34 +
    1.35 +#include "mozilla/dom/ScriptSettings.h"
    1.36 +#include "mozilla/dom/DOMError.h"
    1.37 +#include "mozilla/dom/DOMErrorBinding.h"
    1.38 +#include "mozilla/dom/HTMLObjectElement.h"
    1.39 +#include "mozilla/dom/HTMLObjectElementBinding.h"
    1.40 +#include "mozilla/dom/HTMLSharedObjectElement.h"
    1.41 +#include "mozilla/dom/HTMLEmbedElementBinding.h"
    1.42 +#include "mozilla/dom/HTMLAppletElementBinding.h"
    1.43 +#include "mozilla/dom/Promise.h"
    1.44 +#include "WorkerPrivate.h"
    1.45 +
    1.46 +namespace mozilla {
    1.47 +namespace dom {
    1.48 +
    1.49 +JSErrorFormatString ErrorFormatString[] = {
    1.50 +#define MSG_DEF(_name, _argc, _str) \
    1.51 +  { _str, _argc, JSEXN_TYPEERR },
    1.52 +#include "mozilla/dom/Errors.msg"
    1.53 +#undef MSG_DEF
    1.54 +};
    1.55 +
    1.56 +const JSErrorFormatString*
    1.57 +GetErrorMessage(void* aUserRef, const char* aLocale,
    1.58 +                const unsigned aErrorNumber)
    1.59 +{
    1.60 +  MOZ_ASSERT(aErrorNumber < ArrayLength(ErrorFormatString));
    1.61 +  return &ErrorFormatString[aErrorNumber];
    1.62 +}
    1.63 +
    1.64 +bool
    1.65 +ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, ...)
    1.66 +{
    1.67 +  va_list ap;
    1.68 +  va_start(ap, aErrorNumber);
    1.69 +  JS_ReportErrorNumberVA(aCx, GetErrorMessage, nullptr,
    1.70 +                         static_cast<const unsigned>(aErrorNumber), ap);
    1.71 +  va_end(ap);
    1.72 +  return false;
    1.73 +}
    1.74 +
    1.75 +bool
    1.76 +ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
    1.77 +                 const ErrNum aErrorNumber,
    1.78 +                 const char* aInterfaceName)
    1.79 +{
    1.80 +  NS_ConvertASCIItoUTF16 ifaceName(aInterfaceName);
    1.81 +  // This should only be called for DOM methods/getters/setters, which
    1.82 +  // are JSNative-backed functions, so we can assume that
    1.83 +  // JS_ValueToFunction and JS_GetFunctionDisplayId will both return
    1.84 +  // non-null and that JS_GetStringCharsZ returns non-null.
    1.85 +  JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, aArgs.calleev()));
    1.86 +  MOZ_ASSERT(func);
    1.87 +  JS::Rooted<JSString*> funcName(aCx, JS_GetFunctionDisplayId(func));
    1.88 +  MOZ_ASSERT(funcName);
    1.89 +  JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr,
    1.90 +                         static_cast<const unsigned>(aErrorNumber),
    1.91 +                         JS_GetStringCharsZ(aCx, funcName),
    1.92 +                         ifaceName.get());
    1.93 +  return false;
    1.94 +}
    1.95 +
    1.96 +bool
    1.97 +ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
    1.98 +                 const ErrNum aErrorNumber,
    1.99 +                 prototypes::ID aProtoId)
   1.100 +{
   1.101 +  return ThrowInvalidThis(aCx, aArgs, aErrorNumber,
   1.102 +                          NamesOfInterfacesWithProtos(aProtoId));
   1.103 +}
   1.104 +
   1.105 +bool
   1.106 +ThrowNoSetterArg(JSContext* aCx, prototypes::ID aProtoId)
   1.107 +{
   1.108 +  nsPrintfCString errorMessage("%s attribute setter",
   1.109 +                               NamesOfInterfacesWithProtos(aProtoId));
   1.110 +  return ThrowErrorMessage(aCx, MSG_MISSING_ARGUMENTS, errorMessage.get());
   1.111 +}
   1.112 +
   1.113 +} // namespace dom
   1.114 +
   1.115 +struct ErrorResult::Message {
   1.116 +  nsTArray<nsString> mArgs;
   1.117 +  dom::ErrNum mErrorNumber;
   1.118 +};
   1.119 +
   1.120 +void
   1.121 +ErrorResult::ThrowTypeError(const dom::ErrNum errorNumber, ...)
   1.122 +{
   1.123 +  va_list ap;
   1.124 +  va_start(ap, errorNumber);
   1.125 +  if (IsJSException()) {
   1.126 +    // We have rooted our mJSException, and we don't have the info
   1.127 +    // needed to unroot here, so just bail.
   1.128 +    va_end(ap);
   1.129 +    MOZ_ASSERT(false,
   1.130 +               "Ignoring ThrowTypeError call because we have a JS exception");
   1.131 +    return;
   1.132 +  }
   1.133 +  if (IsTypeError()) {
   1.134 +    delete mMessage;
   1.135 +  }
   1.136 +  mResult = NS_ERROR_TYPE_ERR;
   1.137 +  Message* message = new Message();
   1.138 +  message->mErrorNumber = errorNumber;
   1.139 +  uint16_t argCount =
   1.140 +    dom::GetErrorMessage(nullptr, nullptr, errorNumber)->argCount;
   1.141 +  MOZ_ASSERT(argCount <= 10);
   1.142 +  argCount = std::min<uint16_t>(argCount, 10);
   1.143 +  while (argCount--) {
   1.144 +    message->mArgs.AppendElement(*va_arg(ap, nsString*));
   1.145 +  }
   1.146 +  mMessage = message;
   1.147 +  va_end(ap);
   1.148 +}
   1.149 +
   1.150 +void
   1.151 +ErrorResult::ReportTypeError(JSContext* aCx)
   1.152 +{
   1.153 +  MOZ_ASSERT(mMessage, "ReportTypeError() can be called only once");
   1.154 +
   1.155 +  Message* message = mMessage;
   1.156 +  const uint32_t argCount = message->mArgs.Length();
   1.157 +  const jschar* args[11];
   1.158 +  for (uint32_t i = 0; i < argCount; ++i) {
   1.159 +    args[i] = message->mArgs.ElementAt(i).get();
   1.160 +  }
   1.161 +  args[argCount] = nullptr;
   1.162 +
   1.163 +  JS_ReportErrorNumberUCArray(aCx, dom::GetErrorMessage, nullptr,
   1.164 +                              static_cast<const unsigned>(message->mErrorNumber),
   1.165 +                              argCount > 0 ? args : nullptr);
   1.166 +
   1.167 +  ClearMessage();
   1.168 +}
   1.169 +
   1.170 +void
   1.171 +ErrorResult::ClearMessage()
   1.172 +{
   1.173 +  if (IsTypeError()) {
   1.174 +    delete mMessage;
   1.175 +    mMessage = nullptr;
   1.176 +  }
   1.177 +}
   1.178 +
   1.179 +void
   1.180 +ErrorResult::ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn)
   1.181 +{
   1.182 +  MOZ_ASSERT(mMightHaveUnreportedJSException,
   1.183 +             "Why didn't you tell us you planned to throw a JS exception?");
   1.184 +
   1.185 +  if (IsTypeError()) {
   1.186 +    delete mMessage;
   1.187 +  }
   1.188 +
   1.189 +  // Make sure mJSException is initialized _before_ we try to root it.  But
   1.190 +  // don't set it to exn yet, because we don't want to do that until after we
   1.191 +  // root.
   1.192 +  mJSException = JS::UndefinedValue();
   1.193 +  if (!js::AddRawValueRoot(cx, &mJSException, "ErrorResult::mJSException")) {
   1.194 +    // Don't use NS_ERROR_DOM_JS_EXCEPTION, because that indicates we have
   1.195 +    // in fact rooted mJSException.
   1.196 +    mResult = NS_ERROR_OUT_OF_MEMORY;
   1.197 +  } else {
   1.198 +    mJSException = exn;
   1.199 +    mResult = NS_ERROR_DOM_JS_EXCEPTION;
   1.200 +  }
   1.201 +}
   1.202 +
   1.203 +void
   1.204 +ErrorResult::ReportJSException(JSContext* cx)
   1.205 +{
   1.206 +  MOZ_ASSERT(!mMightHaveUnreportedJSException,
   1.207 +             "Why didn't you tell us you planned to handle JS exceptions?");
   1.208 +
   1.209 +  JS::Rooted<JS::Value> exception(cx, mJSException);
   1.210 +  if (JS_WrapValue(cx, &exception)) {
   1.211 +    JS_SetPendingException(cx, exception);
   1.212 +  }
   1.213 +  mJSException = exception;
   1.214 +  // If JS_WrapValue failed, not much we can do about it...  No matter
   1.215 +  // what, go ahead and unroot mJSException.
   1.216 +  js::RemoveRawValueRoot(cx, &mJSException);
   1.217 +}
   1.218 +
   1.219 +void
   1.220 +ErrorResult::ReportJSExceptionFromJSImplementation(JSContext* aCx)
   1.221 +{
   1.222 +  MOZ_ASSERT(!mMightHaveUnreportedJSException,
   1.223 +             "Why didn't you tell us you planned to handle JS exceptions?");
   1.224 +
   1.225 +  dom::DOMError* domError;
   1.226 +  nsresult rv = UNWRAP_OBJECT(DOMError, &mJSException.toObject(), domError);
   1.227 +  if (NS_FAILED(rv)) {
   1.228 +    // Unwrapping really shouldn't fail here, if mExceptionHandling is set to
   1.229 +    // eRethrowContentExceptions then the CallSetup destructor only stores an
   1.230 +    // exception if it unwraps to DOMError. If we reach this then either
   1.231 +    // mExceptionHandling wasn't set to eRethrowContentExceptions and we
   1.232 +    // shouldn't be calling ReportJSExceptionFromJSImplementation or something
   1.233 +    // went really wrong.
   1.234 +    NS_RUNTIMEABORT("We stored a non-DOMError exception!");
   1.235 +  }
   1.236 +
   1.237 +  nsString message;
   1.238 +  domError->GetMessage(message);
   1.239 +
   1.240 +  JS_ReportError(aCx, "%hs", message.get());
   1.241 +  js::RemoveRawValueRoot(aCx, &mJSException);
   1.242 +
   1.243 +  // We no longer have a useful exception but we do want to signal that an error
   1.244 +  // occured.
   1.245 +  mResult = NS_ERROR_FAILURE;
   1.246 +}
   1.247 +
   1.248 +void
   1.249 +ErrorResult::StealJSException(JSContext* cx,
   1.250 +                              JS::MutableHandle<JS::Value> value)
   1.251 +{
   1.252 +  MOZ_ASSERT(!mMightHaveUnreportedJSException,
   1.253 +             "Must call WouldReportJSException unconditionally in all codepaths that might call StealJSException");
   1.254 +  MOZ_ASSERT(IsJSException(), "No exception to steal");
   1.255 +
   1.256 +  value.set(mJSException);
   1.257 +  js::RemoveRawValueRoot(cx, &mJSException);
   1.258 +  mResult = NS_OK;
   1.259 +}
   1.260 +
   1.261 +void
   1.262 +ErrorResult::ReportNotEnoughArgsError(JSContext* cx,
   1.263 +                                      const char* ifaceName,
   1.264 +                                      const char* memberName)
   1.265 +{
   1.266 +  MOZ_ASSERT(ErrorCode() == NS_ERROR_XPC_NOT_ENOUGH_ARGS);
   1.267 +
   1.268 +  nsPrintfCString errorMessage("%s.%s", ifaceName, memberName);
   1.269 +  ThrowErrorMessage(cx, dom::MSG_MISSING_ARGUMENTS, errorMessage.get());
   1.270 +}
   1.271 +
   1.272 +namespace dom {
   1.273 +
   1.274 +bool
   1.275 +DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
   1.276 +                const ConstantSpec* cs)
   1.277 +{
   1.278 +  JS::Rooted<JS::Value> value(cx);
   1.279 +  for (; cs->name; ++cs) {
   1.280 +    value = cs->value;
   1.281 +    bool ok =
   1.282 +      JS_DefineProperty(cx, obj, cs->name, value,
   1.283 +                        JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
   1.284 +    if (!ok) {
   1.285 +      return false;
   1.286 +    }
   1.287 +  }
   1.288 +  return true;
   1.289 +}
   1.290 +
   1.291 +static inline bool
   1.292 +Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSFunctionSpec* spec) {
   1.293 +  return JS_DefineFunctions(cx, obj, spec);
   1.294 +}
   1.295 +static inline bool
   1.296 +Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSPropertySpec* spec) {
   1.297 +  return JS_DefineProperties(cx, obj, spec);
   1.298 +}
   1.299 +static inline bool
   1.300 +Define(JSContext* cx, JS::Handle<JSObject*> obj, const ConstantSpec* spec) {
   1.301 +  return DefineConstants(cx, obj, spec);
   1.302 +}
   1.303 +
   1.304 +template<typename T>
   1.305 +bool
   1.306 +DefinePrefable(JSContext* cx, JS::Handle<JSObject*> obj,
   1.307 +               const Prefable<T>* props)
   1.308 +{
   1.309 +  MOZ_ASSERT(props);
   1.310 +  MOZ_ASSERT(props->specs);
   1.311 +  do {
   1.312 +    // Define if enabled
   1.313 +    if (props->isEnabled(cx, obj)) {
   1.314 +      if (!Define(cx, obj, props->specs)) {
   1.315 +        return false;
   1.316 +      }
   1.317 +    }
   1.318 +  } while ((++props)->specs);
   1.319 +  return true;
   1.320 +}
   1.321 +
   1.322 +bool
   1.323 +DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
   1.324 +                            const Prefable<const JSPropertySpec>* props)
   1.325 +{
   1.326 +  return DefinePrefable(cx, obj, props);
   1.327 +}
   1.328 +
   1.329 +
   1.330 +// We should use JSFunction objects for interface objects, but we need a custom
   1.331 +// hasInstance hook because we have new interface objects on prototype chains of
   1.332 +// old (XPConnect-based) bindings. Because Function.prototype.toString throws if
   1.333 +// passed a non-Function object we also need to provide our own toString method
   1.334 +// for interface objects.
   1.335 +
   1.336 +enum {
   1.337 +  TOSTRING_CLASS_RESERVED_SLOT = 0,
   1.338 +  TOSTRING_NAME_RESERVED_SLOT = 1
   1.339 +};
   1.340 +
   1.341 +static bool
   1.342 +InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp)
   1.343 +{
   1.344 +  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   1.345 +  JS::Rooted<JSObject*> callee(cx, &args.callee());
   1.346 +
   1.347 +  if (!args.thisv().isObject()) {
   1.348 +    JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
   1.349 +                         JSMSG_CANT_CONVERT_TO, "null", "object");
   1.350 +    return false;
   1.351 +  }
   1.352 +
   1.353 +  JS::Value v = js::GetFunctionNativeReserved(callee,
   1.354 +                                              TOSTRING_CLASS_RESERVED_SLOT);
   1.355 +  const JSClass* clasp = static_cast<const JSClass*>(v.toPrivate());
   1.356 +
   1.357 +  v = js::GetFunctionNativeReserved(callee, TOSTRING_NAME_RESERVED_SLOT);
   1.358 +  JSString* jsname = static_cast<JSString*>(JSVAL_TO_STRING(v));
   1.359 +  size_t length;
   1.360 +  const jschar* name = JS_GetInternedStringCharsAndLength(jsname, &length);
   1.361 +
   1.362 +  if (js::GetObjectJSClass(&args.thisv().toObject()) != clasp) {
   1.363 +    JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
   1.364 +                         JSMSG_INCOMPATIBLE_PROTO,
   1.365 +                         NS_ConvertUTF16toUTF8(name).get(), "toString",
   1.366 +                         "object");
   1.367 +    return false;
   1.368 +  }
   1.369 +
   1.370 +  nsString str;
   1.371 +  str.AppendLiteral("function ");
   1.372 +  str.Append(name, length);
   1.373 +  str.AppendLiteral("() {");
   1.374 +  str.Append('\n');
   1.375 +  str.AppendLiteral("    [native code]");
   1.376 +  str.Append('\n');
   1.377 +  str.AppendLiteral("}");
   1.378 +
   1.379 +  return xpc::NonVoidStringToJsval(cx, str, args.rval());
   1.380 +}
   1.381 +
   1.382 +bool
   1.383 +Constructor(JSContext* cx, unsigned argc, JS::Value* vp)
   1.384 +{
   1.385 +  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   1.386 +  const JS::Value& v =
   1.387 +    js::GetFunctionNativeReserved(&args.callee(),
   1.388 +                                  CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
   1.389 +  const JSNativeHolder* nativeHolder =
   1.390 +    static_cast<const JSNativeHolder*>(v.toPrivate());
   1.391 +  return (nativeHolder->mNative)(cx, argc, vp);
   1.392 +}
   1.393 +
   1.394 +static JSObject*
   1.395 +CreateConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name,
   1.396 +                  const JSNativeHolder* nativeHolder, unsigned ctorNargs)
   1.397 +{
   1.398 +  JSFunction* fun = js::NewFunctionWithReserved(cx, Constructor, ctorNargs,
   1.399 +                                                JSFUN_CONSTRUCTOR, global,
   1.400 +                                                name);
   1.401 +  if (!fun) {
   1.402 +    return nullptr;
   1.403 +  }
   1.404 +
   1.405 +  JSObject* constructor = JS_GetFunctionObject(fun);
   1.406 +  js::SetFunctionNativeReserved(constructor,
   1.407 +                                CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT,
   1.408 +                                js::PrivateValue(const_cast<JSNativeHolder*>(nativeHolder)));
   1.409 +  return constructor;
   1.410 +}
   1.411 +
   1.412 +static bool
   1.413 +DefineConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name,
   1.414 +                  JS::Handle<JSObject*> constructor)
   1.415 +{
   1.416 +  bool alreadyDefined;
   1.417 +  if (!JS_AlreadyHasOwnProperty(cx, global, name, &alreadyDefined)) {
   1.418 +    return false;
   1.419 +  }
   1.420 +
   1.421 +  // This is Enumerable: False per spec.
   1.422 +  return alreadyDefined ||
   1.423 +         JS_DefineProperty(cx, global, name, constructor, 0);
   1.424 +}
   1.425 +
   1.426 +static JSObject*
   1.427 +CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
   1.428 +                      JS::Handle<JSObject*> constructorProto,
   1.429 +                      const JSClass* constructorClass,
   1.430 +                      const JSNativeHolder* constructorNative,
   1.431 +                      unsigned ctorNargs, const NamedConstructor* namedConstructors,
   1.432 +                      JS::Handle<JSObject*> proto,
   1.433 +                      const NativeProperties* properties,
   1.434 +                      const NativeProperties* chromeOnlyProperties,
   1.435 +                      const char* name, bool defineOnGlobal)
   1.436 +{
   1.437 +  JS::Rooted<JSObject*> constructor(cx);
   1.438 +  if (constructorClass) {
   1.439 +    MOZ_ASSERT(constructorProto);
   1.440 +    constructor = JS_NewObject(cx, constructorClass, constructorProto, global);
   1.441 +  } else {
   1.442 +    MOZ_ASSERT(constructorNative);
   1.443 +    MOZ_ASSERT(constructorProto == JS_GetFunctionPrototype(cx, global));
   1.444 +    constructor = CreateConstructor(cx, global, name, constructorNative,
   1.445 +                                    ctorNargs);
   1.446 +  }
   1.447 +  if (!constructor) {
   1.448 +    return nullptr;
   1.449 +  }
   1.450 +
   1.451 +  if (constructorClass) {
   1.452 +    // Have to shadow Function.prototype.toString, since that throws
   1.453 +    // on things that are not js::FunctionClass.
   1.454 +    JS::Rooted<JSFunction*> toString(cx,
   1.455 +      js::DefineFunctionWithReserved(cx, constructor,
   1.456 +                                     "toString",
   1.457 +                                     InterfaceObjectToString,
   1.458 +                                     0, 0));
   1.459 +    if (!toString) {
   1.460 +      return nullptr;
   1.461 +    }
   1.462 +
   1.463 +    JSString *str = ::JS_InternString(cx, name);
   1.464 +    if (!str) {
   1.465 +      return nullptr;
   1.466 +    }
   1.467 +    JSObject* toStringObj = JS_GetFunctionObject(toString);
   1.468 +    js::SetFunctionNativeReserved(toStringObj, TOSTRING_CLASS_RESERVED_SLOT,
   1.469 +                                  PRIVATE_TO_JSVAL(const_cast<JSClass *>(constructorClass)));
   1.470 +
   1.471 +    js::SetFunctionNativeReserved(toStringObj, TOSTRING_NAME_RESERVED_SLOT,
   1.472 +                                  STRING_TO_JSVAL(str));
   1.473 +
   1.474 +    if (!JS_DefineProperty(cx, constructor, "length", ctorNargs,
   1.475 +                           JSPROP_READONLY | JSPROP_PERMANENT)) {
   1.476 +      return nullptr;
   1.477 +    }
   1.478 +  }
   1.479 +
   1.480 +  if (properties) {
   1.481 +    if (properties->staticMethods &&
   1.482 +        !DefinePrefable(cx, constructor, properties->staticMethods)) {
   1.483 +      return nullptr;
   1.484 +    }
   1.485 +
   1.486 +    if (properties->staticAttributes &&
   1.487 +        !DefinePrefable(cx, constructor, properties->staticAttributes)) {
   1.488 +      return nullptr;
   1.489 +    }
   1.490 +
   1.491 +    if (properties->constants &&
   1.492 +        !DefinePrefable(cx, constructor, properties->constants)) {
   1.493 +      return nullptr;
   1.494 +    }
   1.495 +  }
   1.496 +
   1.497 +  if (chromeOnlyProperties) {
   1.498 +    if (chromeOnlyProperties->staticMethods &&
   1.499 +        !DefinePrefable(cx, constructor, chromeOnlyProperties->staticMethods)) {
   1.500 +      return nullptr;
   1.501 +    }
   1.502 +
   1.503 +    if (chromeOnlyProperties->staticAttributes &&
   1.504 +        !DefinePrefable(cx, constructor,
   1.505 +                        chromeOnlyProperties->staticAttributes)) {
   1.506 +      return nullptr;
   1.507 +    }
   1.508 +
   1.509 +    if (chromeOnlyProperties->constants &&
   1.510 +        !DefinePrefable(cx, constructor, chromeOnlyProperties->constants)) {
   1.511 +      return nullptr;
   1.512 +    }
   1.513 +  }
   1.514 +
   1.515 +  if (proto && !JS_LinkConstructorAndPrototype(cx, constructor, proto)) {
   1.516 +    return nullptr;
   1.517 +  }
   1.518 +
   1.519 +  if (defineOnGlobal && !DefineConstructor(cx, global, name, constructor)) {
   1.520 +    return nullptr;
   1.521 +  }
   1.522 +
   1.523 +  if (namedConstructors) {
   1.524 +    int namedConstructorSlot = DOM_INTERFACE_SLOTS_BASE;
   1.525 +    while (namedConstructors->mName) {
   1.526 +      JS::Rooted<JSObject*> namedConstructor(cx,
   1.527 +        CreateConstructor(cx, global, namedConstructors->mName,
   1.528 +                          &namedConstructors->mHolder,
   1.529 +                          namedConstructors->mNargs));
   1.530 +      if (!namedConstructor ||
   1.531 +          !JS_DefineProperty(cx, namedConstructor, "prototype",
   1.532 +                             proto, JSPROP_PERMANENT | JSPROP_READONLY,
   1.533 +                             JS_PropertyStub, JS_StrictPropertyStub) ||
   1.534 +          (defineOnGlobal &&
   1.535 +           !DefineConstructor(cx, global, namedConstructors->mName,
   1.536 +                              namedConstructor))) {
   1.537 +        return nullptr;
   1.538 +      }
   1.539 +      js::SetReservedSlot(constructor, namedConstructorSlot++,
   1.540 +                          JS::ObjectValue(*namedConstructor));
   1.541 +      ++namedConstructors;
   1.542 +    }
   1.543 +  }
   1.544 +
   1.545 +  return constructor;
   1.546 +}
   1.547 +
   1.548 +bool
   1.549 +DefineWebIDLBindingPropertiesOnXPCObject(JSContext* cx,
   1.550 +                                         JS::Handle<JSObject*> obj,
   1.551 +                                         const NativeProperties* properties,
   1.552 +                                         bool defineUnforgeableAttributes)
   1.553 +{
   1.554 +  if (properties->methods &&
   1.555 +      !DefinePrefable(cx, obj, properties->methods)) {
   1.556 +    return false;
   1.557 +  }
   1.558 +
   1.559 +  if (properties->attributes &&
   1.560 +      !DefinePrefable(cx, obj, properties->attributes)) {
   1.561 +    return false;
   1.562 +  }
   1.563 +
   1.564 +  if (defineUnforgeableAttributes && properties->unforgeableAttributes &&
   1.565 +      !DefinePrefable(cx, obj, properties->unforgeableAttributes)) {
   1.566 +    return false;
   1.567 +  }
   1.568 +
   1.569 +  return true;
   1.570 +}
   1.571 +
   1.572 +static JSObject*
   1.573 +CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
   1.574 +                               JS::Handle<JSObject*> parentProto,
   1.575 +                               const JSClass* protoClass,
   1.576 +                               const NativeProperties* properties,
   1.577 +                               const NativeProperties* chromeOnlyProperties)
   1.578 +{
   1.579 +  JS::Rooted<JSObject*> ourProto(cx,
   1.580 +    JS_NewObjectWithUniqueType(cx, protoClass, parentProto, global));
   1.581 +  if (!ourProto) {
   1.582 +    return nullptr;
   1.583 +  }
   1.584 +
   1.585 +  if (properties) {
   1.586 +    if (properties->methods &&
   1.587 +        !DefinePrefable(cx, ourProto, properties->methods)) {
   1.588 +      return nullptr;
   1.589 +    }
   1.590 +
   1.591 +    if (properties->attributes &&
   1.592 +        !DefinePrefable(cx, ourProto, properties->attributes)) {
   1.593 +      return nullptr;
   1.594 +    }
   1.595 +
   1.596 +    if (properties->constants &&
   1.597 +        !DefinePrefable(cx, ourProto, properties->constants)) {
   1.598 +      return nullptr;
   1.599 +    }
   1.600 +  }
   1.601 +
   1.602 +  if (chromeOnlyProperties) {
   1.603 +    if (chromeOnlyProperties->methods &&
   1.604 +        !DefinePrefable(cx, ourProto, chromeOnlyProperties->methods)) {
   1.605 +      return nullptr;
   1.606 +    }
   1.607 +
   1.608 +    if (chromeOnlyProperties->attributes &&
   1.609 +        !DefinePrefable(cx, ourProto, chromeOnlyProperties->attributes)) {
   1.610 +      return nullptr;
   1.611 +    }
   1.612 +
   1.613 +    if (chromeOnlyProperties->constants &&
   1.614 +        !DefinePrefable(cx, ourProto, chromeOnlyProperties->constants)) {
   1.615 +      return nullptr;
   1.616 +    }
   1.617 +  }
   1.618 +
   1.619 +  return ourProto;
   1.620 +}
   1.621 +
   1.622 +void
   1.623 +CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
   1.624 +                       JS::Handle<JSObject*> protoProto,
   1.625 +                       const JSClass* protoClass, JS::Heap<JSObject*>* protoCache,
   1.626 +                       JS::Handle<JSObject*> constructorProto,
   1.627 +                       const JSClass* constructorClass, const JSNativeHolder* constructor,
   1.628 +                       unsigned ctorNargs, const NamedConstructor* namedConstructors,
   1.629 +                       JS::Heap<JSObject*>* constructorCache, const DOMClass* domClass,
   1.630 +                       const NativeProperties* properties,
   1.631 +                       const NativeProperties* chromeOnlyProperties,
   1.632 +                       const char* name, bool defineOnGlobal)
   1.633 +{
   1.634 +  MOZ_ASSERT(protoClass || constructorClass || constructor,
   1.635 +             "Need at least one class or a constructor!");
   1.636 +  MOZ_ASSERT(!((properties &&
   1.637 +                (properties->methods || properties->attributes)) ||
   1.638 +               (chromeOnlyProperties &&
   1.639 +                (chromeOnlyProperties->methods ||
   1.640 +                 chromeOnlyProperties->attributes))) || protoClass,
   1.641 +             "Methods or properties but no protoClass!");
   1.642 +  MOZ_ASSERT(!((properties &&
   1.643 +                (properties->staticMethods || properties->staticAttributes)) ||
   1.644 +               (chromeOnlyProperties &&
   1.645 +                (chromeOnlyProperties->staticMethods ||
   1.646 +                 chromeOnlyProperties->staticAttributes))) ||
   1.647 +             constructorClass || constructor,
   1.648 +             "Static methods but no constructorClass or constructor!");
   1.649 +  MOZ_ASSERT(bool(name) == bool(constructorClass || constructor),
   1.650 +             "Must have name precisely when we have an interface object");
   1.651 +  MOZ_ASSERT(!constructorClass || !constructor);
   1.652 +  MOZ_ASSERT(!protoClass == !protoCache,
   1.653 +             "If, and only if, there is an interface prototype object we need "
   1.654 +             "to cache it");
   1.655 +  MOZ_ASSERT(!(constructorClass || constructor) == !constructorCache,
   1.656 +             "If, and only if, there is an interface object we need to cache "
   1.657 +             "it");
   1.658 +
   1.659 +  JS::Rooted<JSObject*> proto(cx);
   1.660 +  if (protoClass) {
   1.661 +    proto =
   1.662 +      CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
   1.663 +                                     properties, chromeOnlyProperties);
   1.664 +    if (!proto) {
   1.665 +      return;
   1.666 +    }
   1.667 +
   1.668 +    js::SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT,
   1.669 +                        JS::PrivateValue(const_cast<DOMClass*>(domClass)));
   1.670 +
   1.671 +    *protoCache = proto;
   1.672 +  }
   1.673 +  else {
   1.674 +    MOZ_ASSERT(!proto);
   1.675 +  }
   1.676 +
   1.677 +  JSObject* interface;
   1.678 +  if (constructorClass || constructor) {
   1.679 +    interface = CreateInterfaceObject(cx, global, constructorProto,
   1.680 +                                      constructorClass, constructor,
   1.681 +                                      ctorNargs, namedConstructors, proto,
   1.682 +                                      properties, chromeOnlyProperties, name,
   1.683 +                                      defineOnGlobal);
   1.684 +    if (!interface) {
   1.685 +      if (protoCache) {
   1.686 +        // If we fail we need to make sure to clear the value of protoCache we
   1.687 +        // set above.
   1.688 +        *protoCache = nullptr;
   1.689 +      }
   1.690 +      return;
   1.691 +    }
   1.692 +    *constructorCache = interface;
   1.693 +  }
   1.694 +}
   1.695 +
   1.696 +bool
   1.697 +NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
   1.698 +                                         JS::Handle<JSObject*> aScope,
   1.699 +                                         JS::MutableHandle<JS::Value> aRetval,
   1.700 +                                         xpcObjectHelper& aHelper,
   1.701 +                                         const nsIID* aIID,
   1.702 +                                         bool aAllowNativeWrapper)
   1.703 +{
   1.704 +  js::AssertSameCompartment(aCx, aScope);
   1.705 +  nsresult rv;
   1.706 +  // Inline some logic from XPCConvert::NativeInterfaceToJSObject that we need
   1.707 +  // on all threads.
   1.708 +  nsWrapperCache *cache = aHelper.GetWrapperCache();
   1.709 +
   1.710 +  if (cache && cache->IsDOMBinding()) {
   1.711 +      JS::Rooted<JSObject*> obj(aCx, cache->GetWrapper());
   1.712 +      if (!obj) {
   1.713 +          obj = cache->WrapObject(aCx);
   1.714 +      }
   1.715 +
   1.716 +      if (obj && aAllowNativeWrapper && !JS_WrapObject(aCx, &obj)) {
   1.717 +        return false;
   1.718 +      }
   1.719 +
   1.720 +      if (obj) {
   1.721 +        aRetval.setObject(*obj);
   1.722 +        return true;
   1.723 +      }
   1.724 +  }
   1.725 +
   1.726 +  MOZ_ASSERT(NS_IsMainThread());
   1.727 +
   1.728 +  if (!XPCConvert::NativeInterface2JSObject(aRetval, nullptr, aHelper, aIID,
   1.729 +                                            nullptr, aAllowNativeWrapper, &rv)) {
   1.730 +    // I can't tell if NativeInterface2JSObject throws JS exceptions
   1.731 +    // or not.  This is a sloppy stab at the right semantics; the
   1.732 +    // method really ought to be fixed to behave consistently.
   1.733 +    if (!JS_IsExceptionPending(aCx)) {
   1.734 +      Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
   1.735 +    }
   1.736 +    return false;
   1.737 +  }
   1.738 +  return true;
   1.739 +}
   1.740 +
   1.741 +bool
   1.742 +TryPreserveWrapper(JSObject* obj)
   1.743 +{
   1.744 +  MOZ_ASSERT(IsDOMObject(obj));
   1.745 +
   1.746 +  if (nsISupports* native = UnwrapDOMObjectToISupports(obj)) {
   1.747 +    nsWrapperCache* cache = nullptr;
   1.748 +    CallQueryInterface(native, &cache);
   1.749 +    if (cache) {
   1.750 +      cache->PreserveWrapper(native);
   1.751 +    }
   1.752 +    return true;
   1.753 +  }
   1.754 +
   1.755 +  // If this DOMClass is not cycle collected, then it isn't wrappercached,
   1.756 +  // so it does not need to be preserved. If it is cycle collected, then
   1.757 +  // we can't tell if it is wrappercached or not, so we just return false.
   1.758 +  const DOMClass* domClass = GetDOMClass(obj);
   1.759 +  return domClass && !domClass->mParticipant;
   1.760 +}
   1.761 +
   1.762 +// Can only be called with the immediate prototype of the instance object. Can
   1.763 +// only be called on the prototype of an object known to be a DOM instance.
   1.764 +bool
   1.765 +InstanceClassHasProtoAtDepth(JSObject* protoObject, uint32_t protoID,
   1.766 +                             uint32_t depth)
   1.767 +{
   1.768 +  const DOMClass* domClass = static_cast<const DOMClass*>(
   1.769 +    js::GetReservedSlot(protoObject, DOM_PROTO_INSTANCE_CLASS_SLOT).toPrivate());
   1.770 +  return (uint32_t)domClass->mInterfaceChain[depth] == protoID;
   1.771 +}
   1.772 +
   1.773 +// Only set allowNativeWrapper to false if you really know you need it, if in
   1.774 +// doubt use true. Setting it to false disables security wrappers.
   1.775 +bool
   1.776 +XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
   1.777 +                   xpcObjectHelper& helper, const nsIID* iid,
   1.778 +                   bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval)
   1.779 +{
   1.780 +  if (!NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval, helper, iid,
   1.781 +                                                allowNativeWrapper)) {
   1.782 +    return false;
   1.783 +  }
   1.784 +
   1.785 +#ifdef DEBUG
   1.786 +  JSObject* jsobj = rval.toObjectOrNull();
   1.787 +  if (jsobj && !js::GetObjectParent(jsobj))
   1.788 +    NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
   1.789 +                 "Why did we recreate this wrapper?");
   1.790 +#endif
   1.791 +
   1.792 +  return true;
   1.793 +}
   1.794 +
   1.795 +bool
   1.796 +VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
   1.797 +               JS::MutableHandle<JS::Value> aRetval)
   1.798 +{
   1.799 +  nsresult rv;
   1.800 +  if (!XPCVariant::VariantDataToJS(aVariant, &rv, aRetval)) {
   1.801 +    // Does it throw?  Who knows
   1.802 +    if (!JS_IsExceptionPending(aCx)) {
   1.803 +      Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
   1.804 +    }
   1.805 +    return false;
   1.806 +  }
   1.807 +
   1.808 +  return true;
   1.809 +}
   1.810 +
   1.811 +bool
   1.812 +QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
   1.813 +{
   1.814 +  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   1.815 +  JS::Rooted<JS::Value> thisv(cx, JS_THIS(cx, vp));
   1.816 +  if (thisv.isNull())
   1.817 +    return false;
   1.818 +
   1.819 +  // Get the object. It might be a security wrapper, in which case we do a checked
   1.820 +  // unwrap.
   1.821 +  JS::Rooted<JSObject*> origObj(cx, &thisv.toObject());
   1.822 +  JSObject* obj = js::CheckedUnwrap(origObj, /* stopAtOuter = */ false);
   1.823 +  if (!obj) {
   1.824 +      JS_ReportError(cx, "Permission denied to access object");
   1.825 +      return false;
   1.826 +  }
   1.827 +
   1.828 +  // Switch this to UnwrapDOMObjectToISupports once our global objects are
   1.829 +  // using new bindings.
   1.830 +  JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*obj));
   1.831 +  nsISupports* native = nullptr;
   1.832 +  nsCOMPtr<nsISupports> nativeRef;
   1.833 +  xpc_qsUnwrapArg<nsISupports>(cx, val, &native,
   1.834 +                               static_cast<nsISupports**>(getter_AddRefs(nativeRef)),
   1.835 +                               &val);
   1.836 +  if (!native) {
   1.837 +    return Throw(cx, NS_ERROR_FAILURE);
   1.838 +  }
   1.839 +
   1.840 +  if (argc < 1) {
   1.841 +    return Throw(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
   1.842 +  }
   1.843 +
   1.844 +  if (!args[0].isObject()) {
   1.845 +    return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
   1.846 +  }
   1.847 +
   1.848 +  nsIJSID* iid;
   1.849 +  SelfRef iidRef;
   1.850 +  if (NS_FAILED(xpc_qsUnwrapArg<nsIJSID>(cx, args[0], &iid, &iidRef.ptr,
   1.851 +                                         args[0]))) {
   1.852 +    return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
   1.853 +  }
   1.854 +  MOZ_ASSERT(iid);
   1.855 +
   1.856 +  if (iid->GetID()->Equals(NS_GET_IID(nsIClassInfo))) {
   1.857 +    nsresult rv;
   1.858 +    nsCOMPtr<nsIClassInfo> ci = do_QueryInterface(native, &rv);
   1.859 +    if (NS_FAILED(rv)) {
   1.860 +      return Throw(cx, rv);
   1.861 +    }
   1.862 +
   1.863 +    return WrapObject(cx, ci, &NS_GET_IID(nsIClassInfo), args.rval());
   1.864 +  }
   1.865 +
   1.866 +  nsCOMPtr<nsISupports> unused;
   1.867 +  nsresult rv = native->QueryInterface(*iid->GetID(), getter_AddRefs(unused));
   1.868 +  if (NS_FAILED(rv)) {
   1.869 +    return Throw(cx, rv);
   1.870 +  }
   1.871 +
   1.872 +  *vp = thisv;
   1.873 +  return true;
   1.874 +}
   1.875 +
   1.876 +void
   1.877 +GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
   1.878 +                 nsWrapperCache* aCache, nsIJSID* aIID,
   1.879 +                 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
   1.880 +{
   1.881 +  const nsID* iid = aIID->GetID();
   1.882 +
   1.883 +  nsRefPtr<nsISupports> result;
   1.884 +  aError = aRequestor->GetInterface(*iid, getter_AddRefs(result));
   1.885 +  if (aError.Failed()) {
   1.886 +    return;
   1.887 +  }
   1.888 +
   1.889 +  if (!WrapObject(aCx, result, iid, aRetval)) {
   1.890 +    aError.Throw(NS_ERROR_FAILURE);
   1.891 +  }
   1.892 +}
   1.893 +
   1.894 +bool
   1.895 +ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
   1.896 +{
   1.897 +  return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
   1.898 +}
   1.899 +
   1.900 +bool
   1.901 +ThrowConstructorWithoutNew(JSContext* cx, const char* name)
   1.902 +{
   1.903 +  return ThrowErrorMessage(cx, MSG_CONSTRUCTOR_WITHOUT_NEW, name);
   1.904 +}
   1.905 +
   1.906 +inline const NativePropertyHooks*
   1.907 +GetNativePropertyHooks(JSContext *cx, JS::Handle<JSObject*> obj,
   1.908 +                       DOMObjectType& type)
   1.909 +{
   1.910 +  const DOMClass* domClass = GetDOMClass(obj);
   1.911 +  if (domClass) {
   1.912 +    type = eInstance;
   1.913 +    return domClass->mNativeHooks;
   1.914 +  }
   1.915 +
   1.916 +  if (JS_ObjectIsFunction(cx, obj)) {
   1.917 +    MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
   1.918 +    type = eInterface;
   1.919 +    const JS::Value& v =
   1.920 +      js::GetFunctionNativeReserved(obj,
   1.921 +                                    CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
   1.922 +    const JSNativeHolder* nativeHolder =
   1.923 +      static_cast<const JSNativeHolder*>(v.toPrivate());
   1.924 +    return nativeHolder->mPropertyHooks;
   1.925 +  }
   1.926 +
   1.927 +  MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj)));
   1.928 +  const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
   1.929 +    DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
   1.930 +  type = ifaceAndProtoJSClass->mType;
   1.931 +  return ifaceAndProtoJSClass->mNativeHooks;
   1.932 +}
   1.933 +
   1.934 +// Try to resolve a property as an unforgeable property from the given
   1.935 +// NativeProperties, if it's there.  nativeProperties is allowed to be null (in
   1.936 +// which case we of course won't resolve anything).
   1.937 +static bool
   1.938 +XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
   1.939 +                               JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
   1.940 +                               JS::MutableHandle<JSPropertyDescriptor> desc,
   1.941 +                               const NativeProperties* nativeProperties);
   1.942 +
   1.943 +static bool
   1.944 +XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
   1.945 +                          const NativePropertyHooks* nativePropertyHooks,
   1.946 +                          DOMObjectType type, JS::Handle<JSObject*> obj,
   1.947 +                          JS::Handle<jsid> id,
   1.948 +                          JS::MutableHandle<JSPropertyDescriptor> desc);
   1.949 +
   1.950 +bool
   1.951 +XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
   1.952 +                       JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
   1.953 +                       JS::MutableHandle<JSPropertyDescriptor> desc)
   1.954 +{
   1.955 +  DOMObjectType type;
   1.956 +  const NativePropertyHooks *nativePropertyHooks =
   1.957 +    GetNativePropertyHooks(cx, obj, type);
   1.958 +
   1.959 +  if (type != eInstance) {
   1.960 +    // For prototype objects and interface objects, just return their
   1.961 +    // normal set of properties.
   1.962 +    return XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type,
   1.963 +                                     obj, id, desc);
   1.964 +  }
   1.965 +
   1.966 +  // Check for unforgeable properties before doing mResolveOwnProperty weirdness
   1.967 +  const NativePropertiesHolder& nativeProperties =
   1.968 +    nativePropertyHooks->mNativeProperties;
   1.969 +  if (!XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc,
   1.970 +                                      nativeProperties.regular)) {
   1.971 +    return false;
   1.972 +  }
   1.973 +  if (desc.object()) {
   1.974 +    return true;
   1.975 +  }
   1.976 +  if (!XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc,
   1.977 +                                      nativeProperties.chromeOnly)) {
   1.978 +    return false;
   1.979 +  }
   1.980 +  if (desc.object()) {
   1.981 +    return true;
   1.982 +  }
   1.983 +
   1.984 +  return !nativePropertyHooks->mResolveOwnProperty ||
   1.985 +         nativePropertyHooks->mResolveOwnProperty(cx, wrapper, obj, id, desc);
   1.986 +}
   1.987 +
   1.988 +static bool
   1.989 +XrayResolveAttribute(JSContext* cx, JS::Handle<JSObject*> wrapper,
   1.990 +                     JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
   1.991 +                     const Prefable<const JSPropertySpec>* attributes, jsid* attributeIds,
   1.992 +                     const JSPropertySpec* attributeSpecs, JS::MutableHandle<JSPropertyDescriptor> desc)
   1.993 +{
   1.994 +  for (; attributes->specs; ++attributes) {
   1.995 +    if (attributes->isEnabled(cx, obj)) {
   1.996 +      // Set i to be the index into our full list of ids/specs that we're
   1.997 +      // looking at now.
   1.998 +      size_t i = attributes->specs - attributeSpecs;
   1.999 +      for ( ; attributeIds[i] != JSID_VOID; ++i) {
  1.1000 +        if (id == attributeIds[i]) {
  1.1001 +          const JSPropertySpec& attrSpec = attributeSpecs[i];
  1.1002 +          // Because of centralization, we need to make sure we fault in the
  1.1003 +          // JitInfos as well. At present, until the JSAPI changes, the easiest
  1.1004 +          // way to do this is wrap them up as functions ourselves.
  1.1005 +          desc.setAttributes(attrSpec.flags & ~JSPROP_NATIVE_ACCESSORS);
  1.1006 +          // They all have getters, so we can just make it.
  1.1007 +          JS::Rooted<JSFunction*> fun(cx,
  1.1008 +                                      JS_NewFunctionById(cx, (JSNative)attrSpec.getter.propertyOp.op,
  1.1009 +                                                         0, 0, wrapper, id));
  1.1010 +          if (!fun)
  1.1011 +            return false;
  1.1012 +          SET_JITINFO(fun, attrSpec.getter.propertyOp.info);
  1.1013 +          JSObject *funobj = JS_GetFunctionObject(fun);
  1.1014 +          desc.setGetterObject(funobj);
  1.1015 +          desc.attributesRef() |= JSPROP_GETTER;
  1.1016 +          if (attrSpec.setter.propertyOp.op) {
  1.1017 +            // We have a setter! Make it.
  1.1018 +            fun = JS_NewFunctionById(cx, (JSNative)attrSpec.setter.propertyOp.op, 1, 0,
  1.1019 +                                     wrapper, id);
  1.1020 +            if (!fun)
  1.1021 +              return false;
  1.1022 +            SET_JITINFO(fun, attrSpec.setter.propertyOp.info);
  1.1023 +            funobj = JS_GetFunctionObject(fun);
  1.1024 +            desc.setSetterObject(funobj);
  1.1025 +            desc.attributesRef() |= JSPROP_SETTER;
  1.1026 +          } else {
  1.1027 +            desc.setSetter(nullptr);
  1.1028 +          }
  1.1029 +          desc.object().set(wrapper);
  1.1030 +          return true;
  1.1031 +        }
  1.1032 +      }
  1.1033 +    }
  1.1034 +  }
  1.1035 +  return true;
  1.1036 +}
  1.1037 +
  1.1038 +/* static */ bool
  1.1039 +XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1.1040 +                               JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
  1.1041 +                               JS::MutableHandle<JSPropertyDescriptor> desc,
  1.1042 +                               const NativeProperties* nativeProperties)
  1.1043 +{
  1.1044 +  return !nativeProperties || !nativeProperties->unforgeableAttributes ||
  1.1045 +         XrayResolveAttribute(cx, wrapper, obj, id,
  1.1046 +                              nativeProperties->unforgeableAttributes,
  1.1047 +                              nativeProperties->unforgeableAttributeIds,
  1.1048 +                              nativeProperties->unforgeableAttributeSpecs,
  1.1049 +                              desc);
  1.1050 +}
  1.1051 +
  1.1052 +static bool
  1.1053 +XrayResolveProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1.1054 +                    JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
  1.1055 +                    JS::MutableHandle<JSPropertyDescriptor> desc, DOMObjectType type,
  1.1056 +                    const NativeProperties* nativeProperties)
  1.1057 +{
  1.1058 +  const Prefable<const JSFunctionSpec>* methods;
  1.1059 +  jsid* methodIds;
  1.1060 +  const JSFunctionSpec* methodsSpecs;
  1.1061 +  if (type == eInterface) {
  1.1062 +    methods = nativeProperties->staticMethods;
  1.1063 +    methodIds = nativeProperties->staticMethodIds;
  1.1064 +    methodsSpecs = nativeProperties->staticMethodsSpecs;
  1.1065 +  } else {
  1.1066 +    methods = nativeProperties->methods;
  1.1067 +    methodIds = nativeProperties->methodIds;
  1.1068 +    methodsSpecs = nativeProperties->methodsSpecs;
  1.1069 +  }
  1.1070 +  if (methods) {
  1.1071 +    const Prefable<const JSFunctionSpec>* method;
  1.1072 +    for (method = methods; method->specs; ++method) {
  1.1073 +      if (method->isEnabled(cx, obj)) {
  1.1074 +        // Set i to be the index into our full list of ids/specs that we're
  1.1075 +        // looking at now.
  1.1076 +        size_t i = method->specs - methodsSpecs;
  1.1077 +        for ( ; methodIds[i] != JSID_VOID; ++i) {
  1.1078 +          if (id == methodIds[i]) {
  1.1079 +            const JSFunctionSpec& methodSpec = methodsSpecs[i];
  1.1080 +            JSFunction *fun;
  1.1081 +            if (methodSpec.selfHostedName) {
  1.1082 +              fun = JS::GetSelfHostedFunction(cx, methodSpec.selfHostedName, id, methodSpec.nargs);
  1.1083 +              if (!fun) {
  1.1084 +                return false;
  1.1085 +              }
  1.1086 +              MOZ_ASSERT(!methodSpec.call.op, "Bad FunctionSpec declaration: non-null native");
  1.1087 +              MOZ_ASSERT(!methodSpec.call.info, "Bad FunctionSpec declaration: non-null jitinfo");
  1.1088 +            } else {
  1.1089 +              fun = JS_NewFunctionById(cx, methodSpec.call.op, methodSpec.nargs, 0, wrapper, id);
  1.1090 +              if (!fun) {
  1.1091 +                return false;
  1.1092 +              }
  1.1093 +              SET_JITINFO(fun, methodSpec.call.info);
  1.1094 +            }
  1.1095 +            JSObject *funobj = JS_GetFunctionObject(fun);
  1.1096 +            desc.value().setObject(*funobj);
  1.1097 +            desc.setAttributes(methodSpec.flags);
  1.1098 +            desc.object().set(wrapper);
  1.1099 +            desc.setSetter(nullptr);
  1.1100 +            desc.setGetter(nullptr);
  1.1101 +           return true;
  1.1102 +          }
  1.1103 +        }
  1.1104 +      }
  1.1105 +    }
  1.1106 +  }
  1.1107 +
  1.1108 +  if (type == eInterface) {
  1.1109 +    if (nativeProperties->staticAttributes) {
  1.1110 +      if (!XrayResolveAttribute(cx, wrapper, obj, id,
  1.1111 +                                nativeProperties->staticAttributes,
  1.1112 +                                nativeProperties->staticAttributeIds,
  1.1113 +                                nativeProperties->staticAttributeSpecs, desc)) {
  1.1114 +        return false;
  1.1115 +      }
  1.1116 +      if (desc.object()) {
  1.1117 +        return true;
  1.1118 +      }
  1.1119 +    }
  1.1120 +  } else {
  1.1121 +    if (nativeProperties->attributes) {
  1.1122 +      if (!XrayResolveAttribute(cx, wrapper, obj, id,
  1.1123 +                                nativeProperties->attributes,
  1.1124 +                                nativeProperties->attributeIds,
  1.1125 +                                nativeProperties->attributeSpecs, desc)) {
  1.1126 +        return false;
  1.1127 +      }
  1.1128 +      if (desc.object()) {
  1.1129 +        return true;
  1.1130 +      }
  1.1131 +    }
  1.1132 +  }
  1.1133 +
  1.1134 +  if (nativeProperties->constants) {
  1.1135 +    const Prefable<const ConstantSpec>* constant;
  1.1136 +    for (constant = nativeProperties->constants; constant->specs; ++constant) {
  1.1137 +      if (constant->isEnabled(cx, obj)) {
  1.1138 +        // Set i to be the index into our full list of ids/specs that we're
  1.1139 +        // looking at now.
  1.1140 +        size_t i = constant->specs - nativeProperties->constantSpecs;
  1.1141 +        for ( ; nativeProperties->constantIds[i] != JSID_VOID; ++i) {
  1.1142 +          if (id == nativeProperties->constantIds[i]) {
  1.1143 +            desc.setAttributes(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
  1.1144 +            desc.object().set(wrapper);
  1.1145 +            desc.value().set(nativeProperties->constantSpecs[i].value);
  1.1146 +            return true;
  1.1147 +          }
  1.1148 +        }
  1.1149 +      }
  1.1150 +    }
  1.1151 +  }
  1.1152 +
  1.1153 +  return true;
  1.1154 +}
  1.1155 +
  1.1156 +static bool
  1.1157 +ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1.1158 +                              JS::Handle<JSObject*> obj,
  1.1159 +                              size_t protoAndIfaceCacheIndex, unsigned attrs,
  1.1160 +                              JS::MutableHandle<JSPropertyDescriptor> desc)
  1.1161 +{
  1.1162 +  JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
  1.1163 +  {
  1.1164 +    JSAutoCompartment ac(cx, global);
  1.1165 +    ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
  1.1166 +    JSObject* protoOrIface =
  1.1167 +      protoAndIfaceCache.EntrySlotIfExists(protoAndIfaceCacheIndex);
  1.1168 +    if (!protoOrIface) {
  1.1169 +      return false;
  1.1170 +    }
  1.1171 +    desc.object().set(wrapper);
  1.1172 +    desc.setAttributes(attrs);
  1.1173 +    desc.setGetter(JS_PropertyStub);
  1.1174 +    desc.setSetter(JS_StrictPropertyStub);
  1.1175 +    desc.value().set(JS::ObjectValue(*protoOrIface));
  1.1176 +  }
  1.1177 +  return JS_WrapPropertyDescriptor(cx, desc);
  1.1178 +}
  1.1179 +
  1.1180 +/* static */ bool
  1.1181 +XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1.1182 +                          const NativePropertyHooks* nativePropertyHooks,
  1.1183 +                          DOMObjectType type, JS::Handle<JSObject*> obj,
  1.1184 +                          JS::Handle<jsid> id,
  1.1185 +                          JS::MutableHandle<JSPropertyDescriptor> desc)
  1.1186 +{
  1.1187 +  if (type == eInterface && IdEquals(id, "prototype")) {
  1.1188 +    return nativePropertyHooks->mPrototypeID == prototypes::id::_ID_Count ||
  1.1189 +           ResolvePrototypeOrConstructor(cx, wrapper, obj,
  1.1190 +                                         nativePropertyHooks->mPrototypeID,
  1.1191 +                                         JSPROP_PERMANENT | JSPROP_READONLY,
  1.1192 +                                         desc);
  1.1193 +  }
  1.1194 +
  1.1195 +  if (type == eInterfacePrototype && IdEquals(id, "constructor")) {
  1.1196 +    return nativePropertyHooks->mConstructorID == constructors::id::_ID_Count ||
  1.1197 +           ResolvePrototypeOrConstructor(cx, wrapper, obj,
  1.1198 +                                         nativePropertyHooks->mConstructorID,
  1.1199 +                                         0, desc);
  1.1200 +  }
  1.1201 +
  1.1202 +  const NativePropertiesHolder& nativeProperties =
  1.1203 +    nativePropertyHooks->mNativeProperties;
  1.1204 +
  1.1205 +  if (nativeProperties.regular &&
  1.1206 +      !XrayResolveProperty(cx, wrapper, obj, id, desc, type,
  1.1207 +                           nativeProperties.regular)) {
  1.1208 +    return false;
  1.1209 +  }
  1.1210 +
  1.1211 +  if (!desc.object() &&
  1.1212 +      nativeProperties.chromeOnly &&
  1.1213 +      xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
  1.1214 +      !XrayResolveProperty(cx, wrapper, obj, id, desc, type,
  1.1215 +                           nativeProperties.chromeOnly)) {
  1.1216 +    return false;
  1.1217 +  }
  1.1218 +
  1.1219 +  return true;
  1.1220 +}
  1.1221 +
  1.1222 +bool
  1.1223 +XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1.1224 +                          JS::Handle<JSObject*> obj,
  1.1225 +                          JS::Handle<jsid> id, JS::MutableHandle<JSPropertyDescriptor> desc)
  1.1226 +{
  1.1227 +  DOMObjectType type;
  1.1228 +  const NativePropertyHooks* nativePropertyHooks =
  1.1229 +    GetNativePropertyHooks(cx, obj, type);
  1.1230 +
  1.1231 +  if (type == eInstance) {
  1.1232 +    // Force the type to be eInterfacePrototype, since we need to walk the
  1.1233 +    // prototype chain.
  1.1234 +    type = eInterfacePrototype;
  1.1235 +  }
  1.1236 +
  1.1237 +  if (type == eInterfacePrototype) {
  1.1238 +    do {
  1.1239 +      if (!XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type,
  1.1240 +                                     obj, id, desc)) {
  1.1241 +        return false;
  1.1242 +      }
  1.1243 +
  1.1244 +      if (desc.object()) {
  1.1245 +        return true;
  1.1246 +      }
  1.1247 +    } while ((nativePropertyHooks = nativePropertyHooks->mProtoHooks));
  1.1248 +
  1.1249 +    return true;
  1.1250 +  }
  1.1251 +
  1.1252 +  return XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type, obj,
  1.1253 +                                   id, desc);
  1.1254 +}
  1.1255 +
  1.1256 +bool
  1.1257 +XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1.1258 +                   JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
  1.1259 +                   JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined)
  1.1260 +{
  1.1261 +  if (!js::IsProxy(obj))
  1.1262 +      return true;
  1.1263 +
  1.1264 +  MOZ_ASSERT(IsDOMProxy(obj), "What kind of proxy is this?");
  1.1265 +
  1.1266 +  DOMProxyHandler* handler =
  1.1267 +    static_cast<DOMProxyHandler*>(js::GetProxyHandler(obj));
  1.1268 +  return handler->defineProperty(cx, wrapper, id, desc, defined);
  1.1269 +}
  1.1270 +
  1.1271 +bool
  1.1272 +XrayEnumerateAttributes(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1.1273 +                        JS::Handle<JSObject*> obj,
  1.1274 +                        const Prefable<const JSPropertySpec>* attributes,
  1.1275 +                        jsid* attributeIds, const JSPropertySpec* attributeSpecs,
  1.1276 +                        unsigned flags, JS::AutoIdVector& props)
  1.1277 +{
  1.1278 +  for (; attributes->specs; ++attributes) {
  1.1279 +    if (attributes->isEnabled(cx, obj)) {
  1.1280 +      // Set i to be the index into our full list of ids/specs that we're
  1.1281 +      // looking at now.
  1.1282 +      size_t i = attributes->specs - attributeSpecs;
  1.1283 +      for ( ; attributeIds[i] != JSID_VOID; ++i) {
  1.1284 +        if (((flags & JSITER_HIDDEN) ||
  1.1285 +             (attributeSpecs[i].flags & JSPROP_ENUMERATE)) &&
  1.1286 +            !props.append(attributeIds[i])) {
  1.1287 +          return false;
  1.1288 +        }
  1.1289 +      }
  1.1290 +    }
  1.1291 +  }
  1.1292 +  return true;
  1.1293 +}
  1.1294 +
  1.1295 +bool
  1.1296 +XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1.1297 +                        JS::Handle<JSObject*> obj,
  1.1298 +                        unsigned flags, JS::AutoIdVector& props,
  1.1299 +                        DOMObjectType type,
  1.1300 +                        const NativeProperties* nativeProperties)
  1.1301 +{
  1.1302 +  const Prefable<const JSFunctionSpec>* methods;
  1.1303 +  jsid* methodIds;
  1.1304 +  const JSFunctionSpec* methodsSpecs;
  1.1305 +  if (type == eInterface) {
  1.1306 +    methods = nativeProperties->staticMethods;
  1.1307 +    methodIds = nativeProperties->staticMethodIds;
  1.1308 +    methodsSpecs = nativeProperties->staticMethodsSpecs;
  1.1309 +  } else {
  1.1310 +    methods = nativeProperties->methods;
  1.1311 +    methodIds = nativeProperties->methodIds;
  1.1312 +    methodsSpecs = nativeProperties->methodsSpecs;
  1.1313 +  }
  1.1314 +  if (methods) {
  1.1315 +    const Prefable<const JSFunctionSpec>* method;
  1.1316 +    for (method = methods; method->specs; ++method) {
  1.1317 +      if (method->isEnabled(cx, obj)) {
  1.1318 +        // Set i to be the index into our full list of ids/specs that we're
  1.1319 +        // looking at now.
  1.1320 +        size_t i = method->specs - methodsSpecs;
  1.1321 +        for ( ; methodIds[i] != JSID_VOID; ++i) {
  1.1322 +          if (((flags & JSITER_HIDDEN) ||
  1.1323 +               (methodsSpecs[i].flags & JSPROP_ENUMERATE)) &&
  1.1324 +              !props.append(methodIds[i])) {
  1.1325 +            return false;
  1.1326 +          }
  1.1327 +        }
  1.1328 +      }
  1.1329 +    }
  1.1330 +  }
  1.1331 +
  1.1332 +  if (type == eInterface) {
  1.1333 +    if (nativeProperties->staticAttributes &&
  1.1334 +        !XrayEnumerateAttributes(cx, wrapper, obj,
  1.1335 +                                 nativeProperties->staticAttributes,
  1.1336 +                                 nativeProperties->staticAttributeIds,
  1.1337 +                                 nativeProperties->staticAttributeSpecs,
  1.1338 +                                 flags, props)) {
  1.1339 +      return false;
  1.1340 +    }
  1.1341 +  } else {
  1.1342 +    if (nativeProperties->attributes &&
  1.1343 +        !XrayEnumerateAttributes(cx, wrapper, obj,
  1.1344 +                                 nativeProperties->attributes,
  1.1345 +                                 nativeProperties->attributeIds,
  1.1346 +                                 nativeProperties->attributeSpecs,
  1.1347 +                                 flags, props)) {
  1.1348 +      return false;
  1.1349 +    }
  1.1350 +    if (nativeProperties->unforgeableAttributes &&
  1.1351 +        !XrayEnumerateAttributes(cx, wrapper, obj,
  1.1352 +                                 nativeProperties->unforgeableAttributes,
  1.1353 +                                 nativeProperties->unforgeableAttributeIds,
  1.1354 +                                 nativeProperties->unforgeableAttributeSpecs,
  1.1355 +                                 flags, props)) {
  1.1356 +      return false;
  1.1357 +    }
  1.1358 +  }
  1.1359 +
  1.1360 +  if (nativeProperties->constants) {
  1.1361 +    const Prefable<const ConstantSpec>* constant;
  1.1362 +    for (constant = nativeProperties->constants; constant->specs; ++constant) {
  1.1363 +      if (constant->isEnabled(cx, obj)) {
  1.1364 +        // Set i to be the index into our full list of ids/specs that we're
  1.1365 +        // looking at now.
  1.1366 +        size_t i = constant->specs - nativeProperties->constantSpecs;
  1.1367 +        for ( ; nativeProperties->constantIds[i] != JSID_VOID; ++i) {
  1.1368 +          if (!props.append(nativeProperties->constantIds[i])) {
  1.1369 +            return false;
  1.1370 +          }
  1.1371 +        }
  1.1372 +      }
  1.1373 +    }
  1.1374 +  }
  1.1375 +
  1.1376 +  return true;
  1.1377 +}
  1.1378 +
  1.1379 +bool
  1.1380 +XrayEnumerateNativeProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1.1381 +                              const NativePropertyHooks* nativePropertyHooks,
  1.1382 +                              DOMObjectType type, JS::Handle<JSObject*> obj,
  1.1383 +                              unsigned flags, JS::AutoIdVector& props)
  1.1384 +{
  1.1385 +  if (type == eInterface &&
  1.1386 +      nativePropertyHooks->mPrototypeID != prototypes::id::_ID_Count &&
  1.1387 +      !AddStringToIDVector(cx, props, "prototype")) {
  1.1388 +    return false;
  1.1389 +  }
  1.1390 +
  1.1391 +  if (type == eInterfacePrototype &&
  1.1392 +      nativePropertyHooks->mConstructorID != constructors::id::_ID_Count &&
  1.1393 +      (flags & JSITER_HIDDEN) &&
  1.1394 +      !AddStringToIDVector(cx, props, "constructor")) {
  1.1395 +    return false;
  1.1396 +  }
  1.1397 +
  1.1398 +  const NativePropertiesHolder& nativeProperties =
  1.1399 +    nativePropertyHooks->mNativeProperties;
  1.1400 +
  1.1401 +  if (nativeProperties.regular &&
  1.1402 +      !XrayEnumerateProperties(cx, wrapper, obj, flags, props, type,
  1.1403 +                               nativeProperties.regular)) {
  1.1404 +    return false;
  1.1405 +  }
  1.1406 +
  1.1407 +  if (nativeProperties.chromeOnly &&
  1.1408 +      xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
  1.1409 +      !XrayEnumerateProperties(cx, wrapper, obj, flags, props, type,
  1.1410 +                               nativeProperties.chromeOnly)) {
  1.1411 +    return false;
  1.1412 +  }
  1.1413 +
  1.1414 +  return true;
  1.1415 +}
  1.1416 +
  1.1417 +bool
  1.1418 +XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1.1419 +                        JS::Handle<JSObject*> obj,
  1.1420 +                        unsigned flags, JS::AutoIdVector& props)
  1.1421 +{
  1.1422 +  DOMObjectType type;
  1.1423 +  const NativePropertyHooks* nativePropertyHooks =
  1.1424 +    GetNativePropertyHooks(cx, obj, type);
  1.1425 +
  1.1426 +  if (type == eInstance) {
  1.1427 +    if (nativePropertyHooks->mEnumerateOwnProperties &&
  1.1428 +        !nativePropertyHooks->mEnumerateOwnProperties(cx, wrapper, obj,
  1.1429 +                                                      props)) {
  1.1430 +      return false;
  1.1431 +    }
  1.1432 +
  1.1433 +    if (flags & JSITER_OWNONLY) {
  1.1434 +      return true;
  1.1435 +    }
  1.1436 +
  1.1437 +    // Force the type to be eInterfacePrototype, since we need to walk the
  1.1438 +    // prototype chain.
  1.1439 +    type = eInterfacePrototype;
  1.1440 +  }
  1.1441 +
  1.1442 +  if (type == eInterfacePrototype) {
  1.1443 +    do {
  1.1444 +      if (!XrayEnumerateNativeProperties(cx, wrapper, nativePropertyHooks, type,
  1.1445 +                                         obj, flags, props)) {
  1.1446 +        return false;
  1.1447 +      }
  1.1448 +
  1.1449 +      if (flags & JSITER_OWNONLY) {
  1.1450 +        return true;
  1.1451 +      }
  1.1452 +    } while ((nativePropertyHooks = nativePropertyHooks->mProtoHooks));
  1.1453 +
  1.1454 +    return true;
  1.1455 +  }
  1.1456 +
  1.1457 +  return XrayEnumerateNativeProperties(cx, wrapper, nativePropertyHooks, type,
  1.1458 +                                       obj, flags, props);
  1.1459 +}
  1.1460 +
  1.1461 +NativePropertyHooks sWorkerNativePropertyHooks = {
  1.1462 +  nullptr,
  1.1463 +  nullptr,
  1.1464 +  {
  1.1465 +    nullptr,
  1.1466 +    nullptr
  1.1467 +  },
  1.1468 +  prototypes::id::_ID_Count,
  1.1469 +  constructors::id::_ID_Count,
  1.1470 +  nullptr
  1.1471 +};
  1.1472 +
  1.1473 +bool
  1.1474 +GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
  1.1475 +                       JS::Handle<jsid> id, bool* found,
  1.1476 +                       JS::Value* vp)
  1.1477 +{
  1.1478 +  JS::Rooted<JSObject*> proto(cx);
  1.1479 +  if (!js::GetObjectProto(cx, proxy, &proto)) {
  1.1480 +    return false;
  1.1481 +  }
  1.1482 +  if (!proto) {
  1.1483 +    *found = false;
  1.1484 +    return true;
  1.1485 +  }
  1.1486 +
  1.1487 +  bool hasProp;
  1.1488 +  if (!JS_HasPropertyById(cx, proto, id, &hasProp)) {
  1.1489 +    return false;
  1.1490 +  }
  1.1491 +
  1.1492 +  *found = hasProp;
  1.1493 +  if (!hasProp || !vp) {
  1.1494 +    return true;
  1.1495 +  }
  1.1496 +
  1.1497 +  JS::Rooted<JS::Value> value(cx);
  1.1498 +  if (!JS_ForwardGetPropertyTo(cx, proto, id, proxy, &value)) {
  1.1499 +    return false;
  1.1500 +  }
  1.1501 +
  1.1502 +  *vp = value;
  1.1503 +  return true;
  1.1504 +}
  1.1505 +
  1.1506 +bool
  1.1507 +HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
  1.1508 +                       JS::Handle<jsid> id)
  1.1509 +{
  1.1510 +  JS::Rooted<JSObject*> obj(cx, proxy);
  1.1511 +  Maybe<JSAutoCompartment> ac;
  1.1512 +  if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
  1.1513 +    obj = js::UncheckedUnwrap(obj);
  1.1514 +    ac.construct(cx, obj);
  1.1515 +  }
  1.1516 +
  1.1517 +  bool found;
  1.1518 +  // We ignore an error from GetPropertyOnPrototype.  We pass nullptr
  1.1519 +  // for vp so that GetPropertyOnPrototype won't actually do a get.
  1.1520 +  return !GetPropertyOnPrototype(cx, obj, id, &found, nullptr) || found;
  1.1521 +}
  1.1522 +
  1.1523 +bool
  1.1524 +AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
  1.1525 +                       nsTArray<nsString>& names,
  1.1526 +                       bool shadowPrototypeProperties,
  1.1527 +                       JS::AutoIdVector& props)
  1.1528 +{
  1.1529 +  for (uint32_t i = 0; i < names.Length(); ++i) {
  1.1530 +    JS::Rooted<JS::Value> v(cx);
  1.1531 +    if (!xpc::NonVoidStringToJsval(cx, names[i], &v)) {
  1.1532 +      return false;
  1.1533 +    }
  1.1534 +
  1.1535 +    JS::Rooted<jsid> id(cx);
  1.1536 +    if (!JS_ValueToId(cx, v, &id)) {
  1.1537 +      return false;
  1.1538 +    }
  1.1539 +
  1.1540 +    if (shadowPrototypeProperties || !HasPropertyOnPrototype(cx, proxy, id)) {
  1.1541 +      if (!props.append(id)) {
  1.1542 +        return false;
  1.1543 +      }
  1.1544 +    }
  1.1545 +  }
  1.1546 +
  1.1547 +  return true;
  1.1548 +}
  1.1549 +
  1.1550 +bool
  1.1551 +DictionaryBase::ParseJSON(JSContext* aCx,
  1.1552 +                          const nsAString& aJSON,
  1.1553 +                          JS::MutableHandle<JS::Value> aVal)
  1.1554 +{
  1.1555 +  if (aJSON.IsEmpty()) {
  1.1556 +    return true;
  1.1557 +  }
  1.1558 +  return JS_ParseJSON(aCx,
  1.1559 +                      static_cast<const jschar*>(PromiseFlatString(aJSON).get()),
  1.1560 +                      aJSON.Length(), aVal);
  1.1561 +}
  1.1562 +
  1.1563 +static JSString*
  1.1564 +ConcatJSString(JSContext* cx, const char* pre, JS::Handle<JSString*> str, const char* post)
  1.1565 +{
  1.1566 +  if (!str) {
  1.1567 +    return nullptr;
  1.1568 +  }
  1.1569 +
  1.1570 +  JS::Rooted<JSString*> preString(cx, JS_NewStringCopyN(cx, pre, strlen(pre)));
  1.1571 +  JS::Rooted<JSString*> postString(cx, JS_NewStringCopyN(cx, post, strlen(post)));
  1.1572 +  if (!preString || !postString) {
  1.1573 +    return nullptr;
  1.1574 +  }
  1.1575 +
  1.1576 +  preString = JS_ConcatStrings(cx, preString, str);
  1.1577 +  if (!preString) {
  1.1578 +    return nullptr;
  1.1579 +  }
  1.1580 +
  1.1581 +  return JS_ConcatStrings(cx, preString, postString);
  1.1582 +}
  1.1583 +
  1.1584 +bool
  1.1585 +NativeToString(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1.1586 +               JS::Handle<JSObject*> obj, const char* pre,
  1.1587 +               const char* post,
  1.1588 +               JS::MutableHandle<JS::Value> v)
  1.1589 +{
  1.1590 +  JS::Rooted<JSPropertyDescriptor> toStringDesc(cx);
  1.1591 +  toStringDesc.object().set(nullptr);
  1.1592 +  toStringDesc.setAttributes(0);
  1.1593 +  toStringDesc.setGetter(nullptr);
  1.1594 +  toStringDesc.setSetter(nullptr);
  1.1595 +  toStringDesc.value().set(JS::UndefinedValue());
  1.1596 +  JS::Rooted<jsid> id(cx,
  1.1597 +    nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING));
  1.1598 +  if (!XrayResolveNativeProperty(cx, wrapper, obj, id, &toStringDesc)) {
  1.1599 +    return false;
  1.1600 +  }
  1.1601 +
  1.1602 +  JS::Rooted<JSString*> str(cx);
  1.1603 +  {
  1.1604 +    JSAutoCompartment ac(cx, obj);
  1.1605 +    if (toStringDesc.object()) {
  1.1606 +      JS::Rooted<JS::Value> toString(cx, toStringDesc.value());
  1.1607 +      if (!JS_WrapValue(cx, &toString)) {
  1.1608 +        return false;
  1.1609 +      }
  1.1610 +      MOZ_ASSERT(JS_ObjectIsCallable(cx, &toString.toObject()));
  1.1611 +      JS::Rooted<JS::Value> toStringResult(cx);
  1.1612 +      if (JS_CallFunctionValue(cx, obj, toString, JS::HandleValueArray::empty(),
  1.1613 +                               &toStringResult)) {
  1.1614 +        str = toStringResult.toString();
  1.1615 +      } else {
  1.1616 +        str = nullptr;
  1.1617 +      }
  1.1618 +    } else {
  1.1619 +      const js::Class* clasp = js::GetObjectClass(obj);
  1.1620 +      if (IsDOMClass(clasp)) {
  1.1621 +        str = JS_NewStringCopyZ(cx, clasp->name);
  1.1622 +        str = ConcatJSString(cx, "[object ", str, "]");
  1.1623 +      } else if (IsDOMIfaceAndProtoClass(clasp)) {
  1.1624 +        const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
  1.1625 +          DOMIfaceAndProtoJSClass::FromJSClass(clasp);
  1.1626 +        str = JS_NewStringCopyZ(cx, ifaceAndProtoJSClass->mToString);
  1.1627 +      } else {
  1.1628 +        MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
  1.1629 +        JS::Rooted<JSFunction*> fun(cx, JS_GetObjectFunction(obj));
  1.1630 +        str = JS_DecompileFunction(cx, fun, 0);
  1.1631 +      }
  1.1632 +      str = ConcatJSString(cx, pre, str, post);
  1.1633 +    }
  1.1634 +  }
  1.1635 +
  1.1636 +  if (!str) {
  1.1637 +    return false;
  1.1638 +  }
  1.1639 +
  1.1640 +  v.setString(str);
  1.1641 +  return JS_WrapValue(cx, v);
  1.1642 +}
  1.1643 +
  1.1644 +// Dynamically ensure that two objects don't end up with the same reserved slot.
  1.1645 +class MOZ_STACK_CLASS AutoCloneDOMObjectSlotGuard
  1.1646 +{
  1.1647 +public:
  1.1648 +  AutoCloneDOMObjectSlotGuard(JSContext* aCx, JSObject* aOld, JSObject* aNew)
  1.1649 +    : mOldReflector(aCx, aOld), mNewReflector(aCx, aNew)
  1.1650 +  {
  1.1651 +    MOZ_ASSERT(js::GetReservedSlot(aOld, DOM_OBJECT_SLOT) ==
  1.1652 +                 js::GetReservedSlot(aNew, DOM_OBJECT_SLOT));
  1.1653 +  }
  1.1654 +
  1.1655 +  ~AutoCloneDOMObjectSlotGuard()
  1.1656 +  {
  1.1657 +    if (js::GetReservedSlot(mOldReflector, DOM_OBJECT_SLOT).toPrivate()) {
  1.1658 +      js::SetReservedSlot(mNewReflector, DOM_OBJECT_SLOT,
  1.1659 +                          JS::PrivateValue(nullptr));
  1.1660 +    }
  1.1661 +  }
  1.1662 +
  1.1663 +private:
  1.1664 +  JS::Rooted<JSObject*> mOldReflector;
  1.1665 +  JS::Rooted<JSObject*> mNewReflector;
  1.1666 +};
  1.1667 +
  1.1668 +nsresult
  1.1669 +ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg)
  1.1670 +{
  1.1671 +  js::AssertSameCompartment(aCx, aObjArg);
  1.1672 +
  1.1673 +  // Check if we're near the stack limit before we get anywhere near the
  1.1674 +  // transplanting code.
  1.1675 +  JS_CHECK_RECURSION(aCx, return NS_ERROR_FAILURE);
  1.1676 +
  1.1677 +  JS::Rooted<JSObject*> aObj(aCx, aObjArg);
  1.1678 +  const DOMClass* domClass = GetDOMClass(aObj);
  1.1679 +
  1.1680 +  JS::Rooted<JSObject*> oldParent(aCx, JS_GetParent(aObj));
  1.1681 +  JS::Rooted<JSObject*> newParent(aCx, domClass->mGetParent(aCx, aObj));
  1.1682 +
  1.1683 +  JSAutoCompartment oldAc(aCx, oldParent);
  1.1684 +
  1.1685 +  JSCompartment* oldCompartment = js::GetObjectCompartment(oldParent);
  1.1686 +  JSCompartment* newCompartment = js::GetObjectCompartment(newParent);
  1.1687 +  if (oldCompartment == newCompartment) {
  1.1688 +    if (!JS_SetParent(aCx, aObj, newParent)) {
  1.1689 +      MOZ_CRASH();
  1.1690 +    }
  1.1691 +    return NS_OK;
  1.1692 +  }
  1.1693 +
  1.1694 +  // Telemetry.
  1.1695 +  xpc::RecordDonatedNode(oldCompartment);
  1.1696 +  xpc::RecordAdoptedNode(newCompartment);
  1.1697 +
  1.1698 +  nsISupports* native = UnwrapDOMObjectToISupports(aObj);
  1.1699 +  if (!native) {
  1.1700 +    return NS_OK;
  1.1701 +  }
  1.1702 +
  1.1703 +  bool isProxy = js::IsProxy(aObj);
  1.1704 +  JS::Rooted<JSObject*> expandoObject(aCx);
  1.1705 +  if (isProxy) {
  1.1706 +    expandoObject = DOMProxyHandler::GetAndClearExpandoObject(aObj);
  1.1707 +  }
  1.1708 +
  1.1709 +  JSAutoCompartment newAc(aCx, newParent);
  1.1710 +
  1.1711 +  // First we clone the reflector. We get a copy of its properties and clone its
  1.1712 +  // expando chain. The only part that is dangerous here is that if we have to
  1.1713 +  // return early we must avoid ending up with two reflectors pointing to the
  1.1714 +  // same native. Other than that, the objects we create will just go away.
  1.1715 +
  1.1716 +  JS::Rooted<JSObject*> global(aCx,
  1.1717 +                               js::GetGlobalForObjectCrossCompartment(newParent));
  1.1718 +  JS::Handle<JSObject*> proto = (domClass->mGetProto)(aCx, global);
  1.1719 +  if (!proto) {
  1.1720 +    return NS_ERROR_FAILURE;
  1.1721 +  }
  1.1722 +
  1.1723 +  JS::Rooted<JSObject*> newobj(aCx, JS_CloneObject(aCx, aObj, proto, newParent));
  1.1724 +  if (!newobj) {
  1.1725 +    return NS_ERROR_FAILURE;
  1.1726 +  }
  1.1727 +
  1.1728 +  js::SetReservedSlot(newobj, DOM_OBJECT_SLOT,
  1.1729 +                      js::GetReservedSlot(aObj, DOM_OBJECT_SLOT));
  1.1730 +
  1.1731 +  // At this point, both |aObj| and |newobj| point to the same native
  1.1732 +  // which is bad, because one of them will end up being finalized with a
  1.1733 +  // native it does not own. |cloneGuard| ensures that if we exit before
  1.1734 +  // clearing |aObj|'s reserved slot the reserved slot of |newobj| will be
  1.1735 +  // set to null. |aObj| will go away soon, because we swap it with
  1.1736 +  // another object during the transplant and let that object die.
  1.1737 +  JS::Rooted<JSObject*> propertyHolder(aCx);
  1.1738 +  {
  1.1739 +    AutoCloneDOMObjectSlotGuard cloneGuard(aCx, aObj, newobj);
  1.1740 +
  1.1741 +    JS::Rooted<JSObject*> copyFrom(aCx, isProxy ? expandoObject : aObj);
  1.1742 +    if (copyFrom) {
  1.1743 +      propertyHolder = JS_NewObjectWithGivenProto(aCx, nullptr, JS::NullPtr(),
  1.1744 +                                                  newParent);
  1.1745 +      if (!propertyHolder) {
  1.1746 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1747 +      }
  1.1748 +
  1.1749 +      if (!JS_CopyPropertiesFrom(aCx, propertyHolder, copyFrom)) {
  1.1750 +        return NS_ERROR_FAILURE;
  1.1751 +      }
  1.1752 +    } else {
  1.1753 +      propertyHolder = nullptr;
  1.1754 +    }
  1.1755 +
  1.1756 +    // Expandos from other compartments are attached to the target JS object.
  1.1757 +    // Copy them over, and let the old ones die a natural death.
  1.1758 +    if (!xpc::XrayUtils::CloneExpandoChain(aCx, newobj, aObj)) {
  1.1759 +      return NS_ERROR_FAILURE;
  1.1760 +    }
  1.1761 +
  1.1762 +    // We've set up |newobj|, so we make it own the native by nulling
  1.1763 +    // out the reserved slot of |obj|.
  1.1764 +    //
  1.1765 +    // NB: It's important to do this _after_ copying the properties to
  1.1766 +    // propertyHolder. Otherwise, an object with |foo.x === foo| will
  1.1767 +    // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
  1.1768 +    js::SetReservedSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
  1.1769 +  }
  1.1770 +
  1.1771 +  aObj = xpc::TransplantObject(aCx, aObj, newobj);
  1.1772 +  if (!aObj) {
  1.1773 +    MOZ_CRASH();
  1.1774 +  }
  1.1775 +
  1.1776 +  nsWrapperCache* cache = nullptr;
  1.1777 +  CallQueryInterface(native, &cache);
  1.1778 +  bool preserving = cache->PreservingWrapper();
  1.1779 +  cache->SetPreservingWrapper(false);
  1.1780 +  cache->SetWrapper(aObj);
  1.1781 +  cache->SetPreservingWrapper(preserving);
  1.1782 +
  1.1783 +  if (propertyHolder) {
  1.1784 +    JS::Rooted<JSObject*> copyTo(aCx);
  1.1785 +    if (isProxy) {
  1.1786 +      copyTo = DOMProxyHandler::EnsureExpandoObject(aCx, aObj);
  1.1787 +    } else {
  1.1788 +      copyTo = aObj;
  1.1789 +    }
  1.1790 +
  1.1791 +    if (!copyTo || !JS_CopyPropertiesFrom(aCx, copyTo, propertyHolder)) {
  1.1792 +      MOZ_CRASH();
  1.1793 +    }
  1.1794 +  }
  1.1795 +
  1.1796 +  nsObjectLoadingContent* htmlobject;
  1.1797 +  nsresult rv = UNWRAP_OBJECT(HTMLObjectElement, aObj, htmlobject);
  1.1798 +  if (NS_FAILED(rv)) {
  1.1799 +    rv = UnwrapObject<prototypes::id::HTMLEmbedElement,
  1.1800 +                      HTMLSharedObjectElement>(aObj, htmlobject);
  1.1801 +    if (NS_FAILED(rv)) {
  1.1802 +      rv = UnwrapObject<prototypes::id::HTMLAppletElement,
  1.1803 +                        HTMLSharedObjectElement>(aObj, htmlobject);
  1.1804 +      if (NS_FAILED(rv)) {
  1.1805 +        htmlobject = nullptr;
  1.1806 +      }
  1.1807 +    }
  1.1808 +  }
  1.1809 +  if (htmlobject) {
  1.1810 +    htmlobject->SetupProtoChain(aCx, aObj);
  1.1811 +  }
  1.1812 +
  1.1813 +  // Now we can just fix up the parent and return the wrapper
  1.1814 +
  1.1815 +  if (newParent && !JS_SetParent(aCx, aObj, newParent)) {
  1.1816 +    MOZ_CRASH();
  1.1817 +  }
  1.1818 +
  1.1819 +  return NS_OK;
  1.1820 +}
  1.1821 +
  1.1822 +GlobalObject::GlobalObject(JSContext* aCx, JSObject* aObject)
  1.1823 +  : mGlobalJSObject(aCx),
  1.1824 +    mCx(aCx),
  1.1825 +    mGlobalObject(nullptr)
  1.1826 +{
  1.1827 +  JS::Rooted<JSObject*> obj(aCx, aObject);
  1.1828 +  if (js::IsWrapper(obj)) {
  1.1829 +    obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
  1.1830 +    if (!obj) {
  1.1831 +      // We should never end up here on a worker thread, since there shouldn't
  1.1832 +      // be any security wrappers to worry about.
  1.1833 +      if (!MOZ_LIKELY(NS_IsMainThread())) {
  1.1834 +        MOZ_CRASH();
  1.1835 +      }
  1.1836 +
  1.1837 +      Throw(aCx, NS_ERROR_XPC_SECURITY_MANAGER_VETO);
  1.1838 +      return;
  1.1839 +    }
  1.1840 +  }
  1.1841 +
  1.1842 +  mGlobalJSObject = js::GetGlobalForObjectCrossCompartment(obj);
  1.1843 +}
  1.1844 +
  1.1845 +nsISupports*
  1.1846 +GlobalObject::GetAsSupports() const
  1.1847 +{
  1.1848 +  if (mGlobalObject) {
  1.1849 +    return mGlobalObject;
  1.1850 +  }
  1.1851 +
  1.1852 +  if (!NS_IsMainThread()) {
  1.1853 +    mGlobalObject = UnwrapDOMObjectToISupports(mGlobalJSObject);
  1.1854 +    return mGlobalObject;
  1.1855 +  }
  1.1856 +
  1.1857 +  JS::Rooted<JS::Value> val(mCx, JS::ObjectValue(*mGlobalJSObject));
  1.1858 +
  1.1859 +  // Switch this to UnwrapDOMObjectToISupports once our global objects are
  1.1860 +  // using new bindings.
  1.1861 +  nsresult rv = xpc_qsUnwrapArg<nsISupports>(mCx, val, &mGlobalObject,
  1.1862 +                                             static_cast<nsISupports**>(getter_AddRefs(mGlobalObjectRef)),
  1.1863 +                                             &val);
  1.1864 +  if (NS_FAILED(rv)) {
  1.1865 +    mGlobalObject = nullptr;
  1.1866 +    Throw(mCx, NS_ERROR_XPC_BAD_CONVERT_JS);
  1.1867 +  }
  1.1868 +
  1.1869 +  return mGlobalObject;
  1.1870 +}
  1.1871 +
  1.1872 +bool
  1.1873 +InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
  1.1874 +                     JS::Handle<JSObject*> instance,
  1.1875 +                     bool* bp)
  1.1876 +{
  1.1877 +  const DOMIfaceAndProtoJSClass* clasp =
  1.1878 +    DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
  1.1879 +
  1.1880 +  const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
  1.1881 +
  1.1882 +  MOZ_ASSERT(!domClass || clasp->mPrototypeID != prototypes::id::_ID_Count,
  1.1883 +             "Why do we have a hasInstance hook if we don't have a prototype "
  1.1884 +             "ID?");
  1.1885 +
  1.1886 +  if (domClass &&
  1.1887 +      domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
  1.1888 +    *bp = true;
  1.1889 +    return true;
  1.1890 +  }
  1.1891 +
  1.1892 +  JS::Rooted<JSObject*> unwrapped(cx, js::CheckedUnwrap(instance, true));
  1.1893 +  if (unwrapped && jsipc::JavaScriptParent::IsCPOW(unwrapped)) {
  1.1894 +    bool boolp = false;
  1.1895 +    if (!jsipc::JavaScriptParent::DOMInstanceOf(cx, unwrapped, clasp->mPrototypeID,
  1.1896 +                                                clasp->mDepth, &boolp)) {
  1.1897 +      return false;
  1.1898 +    }
  1.1899 +    *bp = boolp;
  1.1900 +    return true;
  1.1901 +  }
  1.1902 +
  1.1903 +  JS::Rooted<JS::Value> protov(cx);
  1.1904 +  DebugOnly<bool> ok = JS_GetProperty(cx, obj, "prototype", &protov);
  1.1905 +  MOZ_ASSERT(ok, "Someone messed with our prototype property?");
  1.1906 +
  1.1907 +  JS::Rooted<JSObject*> interfacePrototype(cx, &protov.toObject());
  1.1908 +  MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(interfacePrototype)),
  1.1909 +             "Someone messed with our prototype property?");
  1.1910 +
  1.1911 +  JS::Rooted<JSObject*> proto(cx);
  1.1912 +  if (!JS_GetPrototype(cx, instance, &proto)) {
  1.1913 +    return false;
  1.1914 +  }
  1.1915 +
  1.1916 +  while (proto) {
  1.1917 +    if (proto == interfacePrototype) {
  1.1918 +      *bp = true;
  1.1919 +      return true;
  1.1920 +    }
  1.1921 +
  1.1922 +    if (!JS_GetPrototype(cx, proto, &proto)) {
  1.1923 +      return false;
  1.1924 +    }
  1.1925 +  }
  1.1926 +
  1.1927 +  *bp = false;
  1.1928 +  return true;
  1.1929 +}
  1.1930 +
  1.1931 +bool
  1.1932 +InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp,
  1.1933 +                     bool* bp)
  1.1934 +{
  1.1935 +  if (!vp.isObject()) {
  1.1936 +    *bp = false;
  1.1937 +    return true;
  1.1938 +  }
  1.1939 +
  1.1940 +  JS::Rooted<JSObject*> instanceObject(cx, &vp.toObject());
  1.1941 +  return InterfaceHasInstance(cx, obj, instanceObject, bp);
  1.1942 +}
  1.1943 +
  1.1944 +bool
  1.1945 +InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
  1.1946 +                     JS::Handle<JSObject*> instance,
  1.1947 +                     bool* bp)
  1.1948 +{
  1.1949 +  const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
  1.1950 +
  1.1951 +  MOZ_ASSERT(!domClass || prototypeID != prototypes::id::_ID_Count,
  1.1952 +             "Why do we have a hasInstance hook if we don't have a prototype "
  1.1953 +             "ID?");
  1.1954 +
  1.1955 +  *bp = (domClass && domClass->mInterfaceChain[depth] == prototypeID);
  1.1956 +  return true;
  1.1957 +}
  1.1958 +
  1.1959 +bool
  1.1960 +ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj)
  1.1961 +{
  1.1962 +  JS::Rooted<JSObject*> rootedObj(cx, obj);
  1.1963 +  GlobalObject global(cx, rootedObj);
  1.1964 +  if (global.Failed()) {
  1.1965 +    return false;
  1.1966 +  }
  1.1967 +  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.GetAsSupports());
  1.1968 +  if (window && window->GetDoc()) {
  1.1969 +    window->GetDoc()->WarnOnceAbout(nsIDocument::eLenientThis);
  1.1970 +  }
  1.1971 +  return true;
  1.1972 +}
  1.1973 +
  1.1974 +bool
  1.1975 +GetWindowForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
  1.1976 +                                nsPIDOMWindow** window)
  1.1977 +{
  1.1978 +  // Be very careful to not get tricked here.
  1.1979 +  MOZ_ASSERT(NS_IsMainThread());
  1.1980 +  if (!xpc::AccessCheck::isChrome(js::GetObjectCompartment(obj))) {
  1.1981 +    NS_RUNTIMEABORT("Should have a chrome object here");
  1.1982 +  }
  1.1983 +
  1.1984 +  // Look up the content-side object.
  1.1985 +  JS::Rooted<JS::Value> domImplVal(cx);
  1.1986 +  if (!JS_GetProperty(cx, obj, "__DOM_IMPL__", &domImplVal)) {
  1.1987 +    return false;
  1.1988 +  }
  1.1989 +
  1.1990 +  if (!domImplVal.isObject()) {
  1.1991 +    ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Value");
  1.1992 +    return false;
  1.1993 +  }
  1.1994 +
  1.1995 +  // Go ahead and get the global from it.  GlobalObject will handle
  1.1996 +  // doing unwrapping as needed.
  1.1997 +  GlobalObject global(cx, &domImplVal.toObject());
  1.1998 +  if (global.Failed()) {
  1.1999 +    return false;
  1.2000 +  }
  1.2001 +
  1.2002 +  // It's OK if we have null here: that just means the content-side
  1.2003 +  // object really wasn't associated with any window.
  1.2004 +  nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(global.GetAsSupports()));
  1.2005 +  win.forget(window);
  1.2006 +  return true;
  1.2007 +}
  1.2008 +
  1.2009 +already_AddRefed<nsPIDOMWindow>
  1.2010 +ConstructJSImplementation(JSContext* aCx, const char* aContractId,
  1.2011 +                          const GlobalObject& aGlobal,
  1.2012 +                          JS::MutableHandle<JSObject*> aObject,
  1.2013 +                          ErrorResult& aRv)
  1.2014 +{
  1.2015 +  // Get the window to use as a parent and for initialization.
  1.2016 +  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
  1.2017 +  if (!window) {
  1.2018 +    aRv.Throw(NS_ERROR_FAILURE);
  1.2019 +    return nullptr;
  1.2020 +  }
  1.2021 +
  1.2022 +  ConstructJSImplementation(aCx, aContractId, window, aObject, aRv);
  1.2023 +
  1.2024 +  if (aRv.Failed()) {
  1.2025 +    return nullptr;
  1.2026 +  }
  1.2027 +  return window.forget();
  1.2028 +}
  1.2029 +
  1.2030 +void
  1.2031 +ConstructJSImplementation(JSContext* aCx, const char* aContractId,
  1.2032 +                          nsPIDOMWindow* aWindow,
  1.2033 +                          JS::MutableHandle<JSObject*> aObject,
  1.2034 +                          ErrorResult& aRv)
  1.2035 +{
  1.2036 +  // Make sure to divorce ourselves from the calling JS while creating and
  1.2037 +  // initializing the object, so exceptions from that will get reported
  1.2038 +  // properly, since those are never exceptions that a spec wants to be thrown.
  1.2039 +  {
  1.2040 +    AutoNoJSAPI nojsapi;
  1.2041 +
  1.2042 +    // Get the XPCOM component containing the JS implementation.
  1.2043 +    nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId);
  1.2044 +    if (!implISupports) {
  1.2045 +      NS_WARNING("Failed to get JS implementation for contract");
  1.2046 +      aRv.Throw(NS_ERROR_FAILURE);
  1.2047 +      return;
  1.2048 +    }
  1.2049 +    // Initialize the object, if it implements nsIDOMGlobalPropertyInitializer.
  1.2050 +    nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
  1.2051 +      do_QueryInterface(implISupports);
  1.2052 +    if (gpi) {
  1.2053 +      JS::Rooted<JS::Value> initReturn(aCx);
  1.2054 +      nsresult rv = gpi->Init(aWindow, &initReturn);
  1.2055 +      if (NS_FAILED(rv)) {
  1.2056 +        aRv.Throw(rv);
  1.2057 +        return;
  1.2058 +      }
  1.2059 +      // With JS-implemented WebIDL, the return value of init() is not used to determine
  1.2060 +      // if init() failed, so init() should only return undefined. Any kind of permission
  1.2061 +      // or pref checking must happen by adding an attribute to the WebIDL interface.
  1.2062 +      if (!initReturn.isUndefined()) {
  1.2063 +        MOZ_ASSERT(false, "The init() method for JS-implemented WebIDL should not return anything");
  1.2064 +        MOZ_CRASH();
  1.2065 +      }
  1.2066 +    }
  1.2067 +    // Extract the JS implementation from the XPCOM object.
  1.2068 +    nsCOMPtr<nsIXPConnectWrappedJS> implWrapped =
  1.2069 +      do_QueryInterface(implISupports);
  1.2070 +    MOZ_ASSERT(implWrapped, "Failed to get wrapped JS from XPCOM component.");
  1.2071 +    if (!implWrapped) {
  1.2072 +      aRv.Throw(NS_ERROR_FAILURE);
  1.2073 +      return;
  1.2074 +    }
  1.2075 +    aObject.set(implWrapped->GetJSObject());
  1.2076 +    if (!aObject) {
  1.2077 +      aRv.Throw(NS_ERROR_FAILURE);
  1.2078 +    }
  1.2079 +  }
  1.2080 +}
  1.2081 +
  1.2082 +bool
  1.2083 +NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
  1.2084 +                         JS::MutableHandle<JS::Value> rval)
  1.2085 +{
  1.2086 +    // ByteStrings are not UTF-8 encoded.
  1.2087 +    JSString* jsStr = JS_NewStringCopyN(cx, str.Data(), str.Length());
  1.2088 +
  1.2089 +    if (!jsStr)
  1.2090 +        return false;
  1.2091 +
  1.2092 +    rval.setString(jsStr);
  1.2093 +    return true;
  1.2094 +}
  1.2095 +
  1.2096 +bool
  1.2097 +ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
  1.2098 +                           JS::MutableHandle<JS::Value> pval, bool nullable,
  1.2099 +                           nsACString& result)
  1.2100 +{
  1.2101 +  JS::Rooted<JSString*> s(cx);
  1.2102 +  if (v.isString()) {
  1.2103 +    s = v.toString();
  1.2104 +  } else {
  1.2105 +
  1.2106 +    if (nullable && v.isNullOrUndefined()) {
  1.2107 +      result.SetIsVoid(true);
  1.2108 +      return true;
  1.2109 +    }
  1.2110 +
  1.2111 +    s = JS::ToString(cx, v);
  1.2112 +    if (!s) {
  1.2113 +      return false;
  1.2114 +    }
  1.2115 +    pval.set(JS::StringValue(s));  // Root the new string.
  1.2116 +  }
  1.2117 +
  1.2118 +  size_t length;
  1.2119 +  const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &length);
  1.2120 +  if (!chars) {
  1.2121 +    return false;
  1.2122 +  }
  1.2123 +
  1.2124 +  // Conversion from Javascript string to ByteString is only valid if all
  1.2125 +  // characters < 256.
  1.2126 +  for (size_t i = 0; i < length; i++) {
  1.2127 +    if (chars[i] > 255) {
  1.2128 +      // The largest unsigned 64 bit number (18,446,744,073,709,551,615) has
  1.2129 +      // 20 digits, plus one more for the null terminator.
  1.2130 +      char index[21];
  1.2131 +      static_assert(sizeof(size_t) <= 8, "index array too small");
  1.2132 +      PR_snprintf(index, sizeof(index), "%d", i);
  1.2133 +      // A jschar is 16 bits long.  The biggest unsigned 16 bit
  1.2134 +      // number (65,535) has 5 digits, plus one more for the null
  1.2135 +      // terminator.
  1.2136 +      char badChar[6];
  1.2137 +      static_assert(sizeof(jschar) <= 2, "badChar array too small");
  1.2138 +      PR_snprintf(badChar, sizeof(badChar), "%d", chars[i]);
  1.2139 +      ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badChar);
  1.2140 +      return false;
  1.2141 +    }
  1.2142 +  }
  1.2143 +
  1.2144 +  if (length >= UINT32_MAX) {
  1.2145 +    return false;
  1.2146 +  }
  1.2147 +  result.SetCapacity(length+1);
  1.2148 +  JS_EncodeStringToBuffer(cx, s, result.BeginWriting(), length);
  1.2149 +  result.BeginWriting()[length] = '\0';
  1.2150 +  result.SetLength(length);
  1.2151 +
  1.2152 +  return true;
  1.2153 +}
  1.2154 +
  1.2155 +bool
  1.2156 +IsInPrivilegedApp(JSContext* aCx, JSObject* aObj)
  1.2157 +{
  1.2158 +  using mozilla::dom::workers::GetWorkerPrivateFromContext;
  1.2159 +  if (!NS_IsMainThread()) {
  1.2160 +    return GetWorkerPrivateFromContext(aCx)->IsInPrivilegedApp();
  1.2161 +  }
  1.2162 +
  1.2163 +  nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aObj);
  1.2164 +  uint16_t appStatus = principal->GetAppStatus();
  1.2165 +  return (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED ||
  1.2166 +          appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED);
  1.2167 +}
  1.2168 +
  1.2169 +bool
  1.2170 +IsInCertifiedApp(JSContext* aCx, JSObject* aObj)
  1.2171 +{
  1.2172 +  using mozilla::dom::workers::GetWorkerPrivateFromContext;
  1.2173 +  if (!NS_IsMainThread()) {
  1.2174 +    return GetWorkerPrivateFromContext(aCx)->IsInCertifiedApp();
  1.2175 +  }
  1.2176 +
  1.2177 +  nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aObj);
  1.2178 +  return principal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED;
  1.2179 +}
  1.2180 +
  1.2181 +void
  1.2182 +TraceGlobal(JSTracer* aTrc, JSObject* aObj)
  1.2183 +{
  1.2184 +  MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL);
  1.2185 +  mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
  1.2186 +}
  1.2187 +
  1.2188 +void
  1.2189 +FinalizeGlobal(JSFreeOp* aFreeOp, JSObject* aObj)
  1.2190 +{
  1.2191 +  MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL);
  1.2192 +  mozilla::dom::DestroyProtoAndIfaceCache(aObj);
  1.2193 +}
  1.2194 +
  1.2195 +bool
  1.2196 +ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
  1.2197 +              JS::Handle<jsid> aId, JS::MutableHandle<JSObject*> aObjp)
  1.2198 +{
  1.2199 +  bool resolved;
  1.2200 +  if (!JS_ResolveStandardClass(aCx, aObj, aId, &resolved)) {
  1.2201 +    return false;
  1.2202 +  }
  1.2203 +
  1.2204 +  aObjp.set(resolved ? aObj.get() : nullptr);
  1.2205 +  return true;
  1.2206 +}
  1.2207 +
  1.2208 +bool
  1.2209 +EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj)
  1.2210 +{
  1.2211 +  return JS_EnumerateStandardClasses(aCx, aObj);
  1.2212 +}
  1.2213 +
  1.2214 +bool
  1.2215 +GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp)
  1.2216 +{
  1.2217 +  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  1.2218 +  const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  1.2219 +  prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
  1.2220 +  if (!args.thisv().isObject()) {
  1.2221 +    return ThrowInvalidThis(cx, args,
  1.2222 +                            MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE,
  1.2223 +                            protoID);
  1.2224 +  }
  1.2225 +  JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
  1.2226 +
  1.2227 +  void* self;
  1.2228 +  {
  1.2229 +    nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
  1.2230 +    if (NS_FAILED(rv)) {
  1.2231 +      return ThrowInvalidThis(cx, args,
  1.2232 +                              GetInvalidThisErrorForGetter(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO),
  1.2233 +                              protoID);
  1.2234 +    }
  1.2235 +  }
  1.2236 +
  1.2237 +  MOZ_ASSERT(info->type() == JSJitInfo::Getter);
  1.2238 +  JSJitGetterOp getter = info->getter;
  1.2239 +  return getter(cx, obj, self, JSJitGetterCallArgs(args));
  1.2240 +}
  1.2241 +
  1.2242 +bool
  1.2243 +GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp)
  1.2244 +{
  1.2245 +  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  1.2246 +  const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  1.2247 +  prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
  1.2248 +  if (!args.thisv().isObject()) {
  1.2249 +    return ThrowInvalidThis(cx, args,
  1.2250 +                            MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE,
  1.2251 +                            protoID);
  1.2252 +  }
  1.2253 +  JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
  1.2254 +
  1.2255 +  void* self;
  1.2256 +  {
  1.2257 +    nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
  1.2258 +    if (NS_FAILED(rv)) {
  1.2259 +      return ThrowInvalidThis(cx, args,
  1.2260 +                              GetInvalidThisErrorForSetter(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO),
  1.2261 +                              protoID);
  1.2262 +    }
  1.2263 +  }
  1.2264 +  if (args.length() == 0) {
  1.2265 +    return ThrowNoSetterArg(cx, protoID);
  1.2266 +  }
  1.2267 +  MOZ_ASSERT(info->type() == JSJitInfo::Setter);
  1.2268 +  JSJitSetterOp setter = info->setter;
  1.2269 +  if (!setter(cx, obj, self, JSJitSetterCallArgs(args))) {
  1.2270 +    return false;
  1.2271 +  }
  1.2272 +  args.rval().set(JSVAL_VOID);
  1.2273 +  return true;
  1.2274 +}
  1.2275 +
  1.2276 +bool
  1.2277 +GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp)
  1.2278 +{
  1.2279 +  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  1.2280 +  const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  1.2281 +  prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
  1.2282 +  if (!args.thisv().isObject()) {
  1.2283 +    return ThrowInvalidThis(cx, args,
  1.2284 +                            MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE,
  1.2285 +                            protoID);
  1.2286 +  }
  1.2287 +  JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
  1.2288 +
  1.2289 +  void* self;
  1.2290 +  {
  1.2291 +    nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
  1.2292 +    if (NS_FAILED(rv)) {
  1.2293 +      return ThrowInvalidThis(cx, args,
  1.2294 +                              GetInvalidThisErrorForMethod(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO),
  1.2295 +                              protoID);
  1.2296 +    }
  1.2297 +  }
  1.2298 +  MOZ_ASSERT(info->type() == JSJitInfo::Method);
  1.2299 +  JSJitMethodOp method = info->method;
  1.2300 +  return method(cx, obj, self, JSJitMethodCallArgs(args));
  1.2301 +}
  1.2302 +
  1.2303 +bool
  1.2304 +GenericPromiseReturningBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp)
  1.2305 +{
  1.2306 +  // Make sure to save the callee before someone maybe messes with rval().
  1.2307 +  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  1.2308 +  JS::Rooted<JSObject*> callee(cx, &args.callee());
  1.2309 +
  1.2310 +  // We could invoke GenericBindingMethod here, but that involves an
  1.2311 +  // extra call.  Manually inline it instead.
  1.2312 +  const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  1.2313 +  prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
  1.2314 +  if (!args.thisv().isObject()) {
  1.2315 +    ThrowInvalidThis(cx, args,
  1.2316 +                     MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE,
  1.2317 +                     protoID);
  1.2318 +    return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
  1.2319 +                                     args.rval());
  1.2320 +  }
  1.2321 +  JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
  1.2322 +
  1.2323 +  void* self;
  1.2324 +  {
  1.2325 +    nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
  1.2326 +    if (NS_FAILED(rv)) {
  1.2327 +      ThrowInvalidThis(cx, args,
  1.2328 +                       GetInvalidThisErrorForMethod(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO),
  1.2329 +                       protoID);
  1.2330 +      return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
  1.2331 +                                       args.rval());
  1.2332 +    }
  1.2333 +  }
  1.2334 +  MOZ_ASSERT(info->type() == JSJitInfo::Method);
  1.2335 +  JSJitMethodOp method = info->method;
  1.2336 +  bool ok = method(cx, obj, self, JSJitMethodCallArgs(args));
  1.2337 +  if (ok) {
  1.2338 +    return true;
  1.2339 +  }
  1.2340 +
  1.2341 +  return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
  1.2342 +                                   args.rval());
  1.2343 +}
  1.2344 +
  1.2345 +bool
  1.2346 +StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp)
  1.2347 +{
  1.2348 +  // Make sure to save the callee before someone maybe messes with rval().
  1.2349 +  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  1.2350 +  JS::Rooted<JSObject*> callee(cx, &args.callee());
  1.2351 +
  1.2352 +  const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  1.2353 +  MOZ_ASSERT(info);
  1.2354 +  MOZ_ASSERT(info->type() == JSJitInfo::StaticMethod);
  1.2355 +
  1.2356 +  bool ok = info->staticMethod(cx, argc, vp);
  1.2357 +  if (ok) {
  1.2358 +    return true;
  1.2359 +  }
  1.2360 +
  1.2361 +  return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
  1.2362 +                                   args.rval());
  1.2363 +}
  1.2364 +
  1.2365 +bool
  1.2366 +ConvertExceptionToPromise(JSContext* cx,
  1.2367 +                          JSObject* promiseScope,
  1.2368 +                          JS::MutableHandle<JS::Value> rval)
  1.2369 +{
  1.2370 +  GlobalObject global(cx, promiseScope);
  1.2371 +  if (global.Failed()) {
  1.2372 +    return false;
  1.2373 +  }
  1.2374 +
  1.2375 +  JS::Rooted<JS::Value> exn(cx);
  1.2376 +  if (!JS_GetPendingException(cx, &exn)) {
  1.2377 +    return false;
  1.2378 +  }
  1.2379 +
  1.2380 +  JS_ClearPendingException(cx);
  1.2381 +  ErrorResult rv;
  1.2382 +  nsRefPtr<Promise> promise = Promise::Reject(global, cx, exn, rv);
  1.2383 +  if (rv.Failed()) {
  1.2384 +    // We just give up.  Make sure to not leak memory on the
  1.2385 +    // ErrorResult, but then just put the original exception back.
  1.2386 +    ThrowMethodFailedWithDetails(cx, rv, "", "");
  1.2387 +    JS_SetPendingException(cx, exn);
  1.2388 +    return false;
  1.2389 +  }
  1.2390 +
  1.2391 +  return WrapNewBindingObject(cx, promise, rval);
  1.2392 +}
  1.2393 +
  1.2394 +} // namespace dom
  1.2395 +} // namespace mozilla

mercurial