LCOV - code coverage report
Current view: top level - dom/bindings - BindingUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 593 1699 34.9 %
Date: 2017-07-14 16:53:18 Functions: 64 203 31.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "BindingUtils.h"
       8             : 
       9             : #include <algorithm>
      10             : #include <stdarg.h>
      11             : 
      12             : #include "mozilla/Assertions.h"
      13             : #include "mozilla/DebugOnly.h"
      14             : #include "mozilla/FloatingPoint.h"
      15             : #include "mozilla/Preferences.h"
      16             : #include "mozilla/SizePrintfMacros.h"
      17             : #include "mozilla/Unused.h"
      18             : #include "mozilla/UseCounter.h"
      19             : 
      20             : #include "AccessCheck.h"
      21             : #include "jsfriendapi.h"
      22             : #include "nsContentCreatorFunctions.h"
      23             : #include "nsContentUtils.h"
      24             : #include "nsGlobalWindow.h"
      25             : #include "nsIDocShell.h"
      26             : #include "nsIDOMGlobalPropertyInitializer.h"
      27             : #include "nsIParserService.h"
      28             : #include "nsIPermissionManager.h"
      29             : #include "nsIPrincipal.h"
      30             : #include "nsIXPConnect.h"
      31             : #include "nsUTF8Utils.h"
      32             : #include "WorkerPrivate.h"
      33             : #include "WorkerRunnable.h"
      34             : #include "WrapperFactory.h"
      35             : #include "xpcprivate.h"
      36             : #include "XrayWrapper.h"
      37             : #include "nsPrintfCString.h"
      38             : #include "mozilla/Sprintf.h"
      39             : #include "nsGlobalWindow.h"
      40             : 
      41             : #include "mozilla/dom/ScriptSettings.h"
      42             : #include "mozilla/dom/CustomElementRegistry.h"
      43             : #include "mozilla/dom/DOMError.h"
      44             : #include "mozilla/dom/DOMErrorBinding.h"
      45             : #include "mozilla/dom/DOMException.h"
      46             : #include "mozilla/dom/ElementBinding.h"
      47             : #include "mozilla/dom/HTMLObjectElement.h"
      48             : #include "mozilla/dom/HTMLObjectElementBinding.h"
      49             : #include "mozilla/dom/HTMLSharedObjectElement.h"
      50             : #include "mozilla/dom/HTMLElementBinding.h"
      51             : #include "mozilla/dom/HTMLEmbedElementBinding.h"
      52             : #include "mozilla/dom/HTMLAppletElementBinding.h"
      53             : #include "mozilla/dom/Promise.h"
      54             : #include "mozilla/dom/ResolveSystemBinding.h"
      55             : #include "mozilla/dom/WebIDLGlobalNameHash.h"
      56             : #include "mozilla/dom/WorkerPrivate.h"
      57             : #include "mozilla/dom/WorkerScope.h"
      58             : #include "mozilla/dom/XrayExpandoClass.h"
      59             : #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
      60             : #include "nsDOMClassInfo.h"
      61             : #include "ipc/ErrorIPCUtils.h"
      62             : #include "mozilla/UseCounter.h"
      63             : #include "mozilla/dom/DocGroup.h"
      64             : 
      65             : namespace mozilla {
      66             : namespace dom {
      67             : 
      68             : using namespace workers;
      69             : 
      70             : // Forward declare GetConstructorObject methods.
      71             : #define HTML_TAG(_tag, _classname, _interfacename)                             \
      72             : namespace HTML##_interfacename##ElementBinding {                               \
      73             :   JSObject* GetConstructorObject(JSContext*);                                  \
      74             : }
      75             : #define HTML_OTHER(_tag)
      76             : #include "nsHTMLTagList.h"
      77             : #undef HTML_TAG
      78             : #undef HTML_OTHER
      79             : 
      80             : typedef JSObject* (*constructorGetterCallback)(JSContext*);
      81             : 
      82             : // Mapping of html tag and GetConstructorObject methods.
      83             : #define HTML_TAG(_tag, _classname, _interfacename) HTML##_interfacename##ElementBinding::GetConstructorObject,
      84             : #define HTML_OTHER(_tag) nullptr,
      85             : // We use eHTMLTag_foo (where foo is the tag) which is defined in nsHTMLTags.h
      86             : // to index into this array.
      87             : static const constructorGetterCallback sConstructorGetterCallback[] = {
      88             :   HTMLUnknownElementBinding::GetConstructorObject,
      89             : #include "nsHTMLTagList.h"
      90             : #undef HTML_TAG
      91             : #undef HTML_OTHER
      92             : };
      93             : 
      94             : const JSErrorFormatString ErrorFormatString[] = {
      95             : #define MSG_DEF(_name, _argc, _exn, _str) \
      96             :   { #_name, _str, _argc, _exn },
      97             : #include "mozilla/dom/Errors.msg"
      98             : #undef MSG_DEF
      99             : };
     100             : 
     101             : #define MSG_DEF(_name, _argc, _exn, _str) \
     102             :   static_assert(_argc < JS::MaxNumErrorArguments, \
     103             :                 #_name " must only have as many error arguments as the JS engine can support");
     104             : #include "mozilla/dom/Errors.msg"
     105             : #undef MSG_DEF
     106             : 
     107             : const JSErrorFormatString*
     108           0 : GetErrorMessage(void* aUserRef, const unsigned aErrorNumber)
     109             : {
     110           0 :   MOZ_ASSERT(aErrorNumber < ArrayLength(ErrorFormatString));
     111           0 :   return &ErrorFormatString[aErrorNumber];
     112             : }
     113             : 
     114             : uint16_t
     115           0 : GetErrorArgCount(const ErrNum aErrorNumber)
     116             : {
     117           0 :   return GetErrorMessage(nullptr, aErrorNumber)->argCount;
     118             : }
     119             : 
     120             : void
     121           0 : binding_detail::ThrowErrorMessage(JSContext* aCx, const unsigned aErrorNumber, ...)
     122             : {
     123             :   va_list ap;
     124           0 :   va_start(ap, aErrorNumber);
     125           0 :   JS_ReportErrorNumberUTF8VA(aCx, GetErrorMessage, nullptr, aErrorNumber, ap);
     126           0 :   va_end(ap);
     127           0 : }
     128             : 
     129             : bool
     130           0 : ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
     131             :                  bool aSecurityError, const char* aInterfaceName)
     132             : {
     133           0 :   NS_ConvertASCIItoUTF16 ifaceName(aInterfaceName);
     134             :   // This should only be called for DOM methods/getters/setters, which
     135             :   // are JSNative-backed functions, so we can assume that
     136             :   // JS_ValueToFunction and JS_GetFunctionDisplayId will both return
     137             :   // non-null and that JS_GetStringCharsZ returns non-null.
     138           0 :   JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, aArgs.calleev()));
     139           0 :   MOZ_ASSERT(func);
     140           0 :   JS::Rooted<JSString*> funcName(aCx, JS_GetFunctionDisplayId(func));
     141           0 :   MOZ_ASSERT(funcName);
     142           0 :   nsAutoJSString funcNameStr;
     143           0 :   if (!funcNameStr.init(aCx, funcName)) {
     144           0 :     return false;
     145             :   }
     146           0 :   const ErrNum errorNumber = aSecurityError ?
     147             :                              MSG_METHOD_THIS_UNWRAPPING_DENIED :
     148           0 :                              MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
     149           0 :   MOZ_RELEASE_ASSERT(GetErrorArgCount(errorNumber) <= 2);
     150           0 :   JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr,
     151             :                          static_cast<const unsigned>(errorNumber),
     152           0 :                          funcNameStr.get(), ifaceName.get());
     153           0 :   return false;
     154             : }
     155             : 
     156             : bool
     157           0 : ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
     158             :                  bool aSecurityError,
     159             :                  prototypes::ID aProtoId)
     160             : {
     161           0 :   return ThrowInvalidThis(aCx, aArgs, aSecurityError,
     162           0 :                           NamesOfInterfacesWithProtos(aProtoId));
     163             : }
     164             : 
     165             : bool
     166           0 : ThrowNoSetterArg(JSContext* aCx, prototypes::ID aProtoId)
     167             : {
     168             :   nsPrintfCString errorMessage("%s attribute setter",
     169           0 :                                NamesOfInterfacesWithProtos(aProtoId));
     170           0 :   return ThrowErrorMessage(aCx, MSG_MISSING_ARGUMENTS, errorMessage.get());
     171             : }
     172             : 
     173             : } // namespace dom
     174             : 
     175             : namespace binding_danger {
     176             : 
     177             : template<typename CleanupPolicy>
     178             : struct TErrorResult<CleanupPolicy>::Message {
     179           0 :   Message() { MOZ_COUNT_CTOR(TErrorResult::Message); }
     180           0 :   ~Message() { MOZ_COUNT_DTOR(TErrorResult::Message); }
     181             : 
     182             :   nsTArray<nsString> mArgs;
     183             :   dom::ErrNum mErrorNumber;
     184             : 
     185           0 :   bool HasCorrectNumberOfArguments()
     186             :   {
     187           0 :     return GetErrorArgCount(mErrorNumber) == mArgs.Length();
     188             :   }
     189             : };
     190             : 
     191             : template<typename CleanupPolicy>
     192             : nsTArray<nsString>&
     193           0 : TErrorResult<CleanupPolicy>::CreateErrorMessageHelper(const dom::ErrNum errorNumber,
     194             :                                                       nsresult errorType)
     195             : {
     196           0 :   AssertInOwningThread();
     197           0 :   mResult = errorType;
     198             : 
     199           0 :   mMessage = new Message();
     200           0 :   mMessage->mErrorNumber = errorNumber;
     201           0 :   return mMessage->mArgs;
     202             : }
     203             : 
     204             : template<typename CleanupPolicy>
     205             : void
     206           0 : TErrorResult<CleanupPolicy>::SerializeMessage(IPC::Message* aMsg) const
     207             : {
     208             :   using namespace IPC;
     209           0 :   AssertInOwningThread();
     210           0 :   MOZ_ASSERT(mUnionState == HasMessage);
     211           0 :   MOZ_ASSERT(mMessage);
     212           0 :   WriteParam(aMsg, mMessage->mArgs);
     213           0 :   WriteParam(aMsg, mMessage->mErrorNumber);
     214           0 : }
     215             : 
     216             : template<typename CleanupPolicy>
     217             : bool
     218           0 : TErrorResult<CleanupPolicy>::DeserializeMessage(const IPC::Message* aMsg,
     219             :                                                 PickleIterator* aIter)
     220             : {
     221             :   using namespace IPC;
     222           0 :   AssertInOwningThread();
     223           0 :   nsAutoPtr<Message> readMessage(new Message());
     224           0 :   if (!ReadParam(aMsg, aIter, &readMessage->mArgs) ||
     225           0 :       !ReadParam(aMsg, aIter, &readMessage->mErrorNumber)) {
     226           0 :     return false;
     227             :   }
     228           0 :   if (!readMessage->HasCorrectNumberOfArguments()) {
     229           0 :     return false;
     230             :   }
     231             : 
     232           0 :   MOZ_ASSERT(mUnionState == HasNothing);
     233           0 :   mMessage = readMessage.forget();
     234             : #ifdef DEBUG
     235           0 :   mUnionState = HasMessage;
     236             : #endif // DEBUG
     237           0 :   return true;
     238             : }
     239             : 
     240             : template<typename CleanupPolicy>
     241             : void
     242           0 : TErrorResult<CleanupPolicy>::SetPendingExceptionWithMessage(JSContext* aCx)
     243             : {
     244           0 :   AssertInOwningThread();
     245           0 :   MOZ_ASSERT(mMessage, "SetPendingExceptionWithMessage() can be called only once");
     246           0 :   MOZ_ASSERT(mUnionState == HasMessage);
     247             : 
     248           0 :   Message* message = mMessage;
     249           0 :   MOZ_RELEASE_ASSERT(message->HasCorrectNumberOfArguments());
     250           0 :   const uint32_t argCount = message->mArgs.Length();
     251             :   const char16_t* args[JS::MaxNumErrorArguments + 1];
     252           0 :   for (uint32_t i = 0; i < argCount; ++i) {
     253           0 :     args[i] = message->mArgs.ElementAt(i).get();
     254             :   }
     255           0 :   args[argCount] = nullptr;
     256             : 
     257           0 :   JS_ReportErrorNumberUCArray(aCx, dom::GetErrorMessage, nullptr,
     258           0 :                               static_cast<const unsigned>(message->mErrorNumber),
     259             :                               argCount > 0 ? args : nullptr);
     260             : 
     261           0 :   ClearMessage();
     262           0 :   mResult = NS_OK;
     263           0 : }
     264             : 
     265             : template<typename CleanupPolicy>
     266             : void
     267           0 : TErrorResult<CleanupPolicy>::ClearMessage()
     268             : {
     269           0 :   AssertInOwningThread();
     270           0 :   MOZ_ASSERT(IsErrorWithMessage());
     271           0 :   delete mMessage;
     272           0 :   mMessage = nullptr;
     273             : #ifdef DEBUG
     274           0 :   mUnionState = HasNothing;
     275             : #endif // DEBUG
     276           0 : }
     277             : 
     278             : template<typename CleanupPolicy>
     279             : void
     280           0 : TErrorResult<CleanupPolicy>::ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn)
     281             : {
     282           0 :   AssertInOwningThread();
     283           0 :   MOZ_ASSERT(mMightHaveUnreportedJSException,
     284             :              "Why didn't you tell us you planned to throw a JS exception?");
     285             : 
     286           0 :   ClearUnionData();
     287             : 
     288             :   // Make sure mJSException is initialized _before_ we try to root it.  But
     289             :   // don't set it to exn yet, because we don't want to do that until after we
     290             :   // root.
     291           0 :   mJSException.setUndefined();
     292           0 :   if (!js::AddRawValueRoot(cx, &mJSException, "TErrorResult::mJSException")) {
     293             :     // Don't use NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION, because that
     294             :     // indicates we have in fact rooted mJSException.
     295           0 :     mResult = NS_ERROR_OUT_OF_MEMORY;
     296             :   } else {
     297           0 :     mJSException = exn;
     298           0 :     mResult = NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION;
     299             : #ifdef DEBUG
     300           0 :     mUnionState = HasJSException;
     301             : #endif // DEBUG
     302             :   }
     303           0 : }
     304             : 
     305             : template<typename CleanupPolicy>
     306             : void
     307           0 : TErrorResult<CleanupPolicy>::SetPendingJSException(JSContext* cx)
     308             : {
     309           0 :   AssertInOwningThread();
     310           0 :   MOZ_ASSERT(!mMightHaveUnreportedJSException,
     311             :              "Why didn't you tell us you planned to handle JS exceptions?");
     312           0 :   MOZ_ASSERT(mUnionState == HasJSException);
     313             : 
     314           0 :   JS::Rooted<JS::Value> exception(cx, mJSException);
     315           0 :   if (JS_WrapValue(cx, &exception)) {
     316           0 :     JS_SetPendingException(cx, exception);
     317             :   }
     318           0 :   mJSException = exception;
     319             :   // If JS_WrapValue failed, not much we can do about it...  No matter
     320             :   // what, go ahead and unroot mJSException.
     321           0 :   js::RemoveRawValueRoot(cx, &mJSException);
     322             : 
     323           0 :   mResult = NS_OK;
     324             : #ifdef DEBUG
     325           0 :   mUnionState = HasNothing;
     326             : #endif // DEBUG
     327           0 : }
     328             : 
     329             : template<typename CleanupPolicy>
     330           0 : struct TErrorResult<CleanupPolicy>::DOMExceptionInfo {
     331           0 :   DOMExceptionInfo(nsresult rv, const nsACString& message)
     332             :     : mMessage(message)
     333           0 :     , mRv(rv)
     334           0 :   {}
     335             : 
     336             :   nsCString mMessage;
     337             :   nsresult mRv;
     338             : };
     339             : 
     340             : template<typename CleanupPolicy>
     341             : void
     342           0 : TErrorResult<CleanupPolicy>::SerializeDOMExceptionInfo(IPC::Message* aMsg) const
     343             : {
     344             :   using namespace IPC;
     345           0 :   AssertInOwningThread();
     346           0 :   MOZ_ASSERT(mDOMExceptionInfo);
     347           0 :   MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
     348           0 :   WriteParam(aMsg, mDOMExceptionInfo->mMessage);
     349           0 :   WriteParam(aMsg, mDOMExceptionInfo->mRv);
     350           0 : }
     351             : 
     352             : template<typename CleanupPolicy>
     353             : bool
     354           0 : TErrorResult<CleanupPolicy>::DeserializeDOMExceptionInfo(const IPC::Message* aMsg,
     355             :                                                          PickleIterator* aIter)
     356             : {
     357             :   using namespace IPC;
     358           0 :   AssertInOwningThread();
     359           0 :   nsCString message;
     360             :   nsresult rv;
     361           0 :   if (!ReadParam(aMsg, aIter, &message) ||
     362           0 :       !ReadParam(aMsg, aIter, &rv)) {
     363           0 :     return false;
     364             :   }
     365             : 
     366           0 :   MOZ_ASSERT(mUnionState == HasNothing);
     367           0 :   MOZ_ASSERT(IsDOMException());
     368           0 :   mDOMExceptionInfo = new DOMExceptionInfo(rv, message);
     369             : #ifdef DEBUG
     370           0 :   mUnionState = HasDOMExceptionInfo;
     371             : #endif // DEBUG
     372           0 :   return true;
     373             : }
     374             : 
     375             : template<typename CleanupPolicy>
     376             : void
     377           0 : TErrorResult<CleanupPolicy>::ThrowDOMException(nsresult rv,
     378             :                                                const nsACString& message)
     379             : {
     380           0 :   AssertInOwningThread();
     381           0 :   ClearUnionData();
     382             : 
     383           0 :   mResult = NS_ERROR_INTERNAL_ERRORRESULT_DOMEXCEPTION;
     384           0 :   mDOMExceptionInfo = new DOMExceptionInfo(rv, message);
     385             : #ifdef DEBUG
     386           0 :   mUnionState = HasDOMExceptionInfo;
     387             : #endif
     388           0 : }
     389             : 
     390             : template<typename CleanupPolicy>
     391             : void
     392           0 : TErrorResult<CleanupPolicy>::SetPendingDOMException(JSContext* cx)
     393             : {
     394           0 :   AssertInOwningThread();
     395           0 :   MOZ_ASSERT(mDOMExceptionInfo,
     396             :              "SetPendingDOMException() can be called only once");
     397           0 :   MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
     398             : 
     399           0 :   dom::Throw(cx, mDOMExceptionInfo->mRv, mDOMExceptionInfo->mMessage);
     400             : 
     401           0 :   ClearDOMExceptionInfo();
     402           0 :   mResult = NS_OK;
     403           0 : }
     404             : 
     405             : template<typename CleanupPolicy>
     406             : void
     407           0 : TErrorResult<CleanupPolicy>::ClearDOMExceptionInfo()
     408             : {
     409           0 :   AssertInOwningThread();
     410           0 :   MOZ_ASSERT(IsDOMException());
     411           0 :   MOZ_ASSERT(mUnionState == HasDOMExceptionInfo || !mDOMExceptionInfo);
     412           0 :   delete mDOMExceptionInfo;
     413           0 :   mDOMExceptionInfo = nullptr;
     414             : #ifdef DEBUG
     415           0 :   mUnionState = HasNothing;
     416             : #endif // DEBUG
     417           0 : }
     418             : 
     419             : template<typename CleanupPolicy>
     420             : void
     421        1616 : TErrorResult<CleanupPolicy>::ClearUnionData()
     422             : {
     423        1616 :   AssertInOwningThread();
     424        1616 :   if (IsJSException()) {
     425           0 :     JSContext* cx = dom::danger::GetJSContext();
     426           0 :     MOZ_ASSERT(cx);
     427           0 :     mJSException.setUndefined();
     428           0 :     js::RemoveRawValueRoot(cx, &mJSException);
     429             : #ifdef DEBUG
     430           0 :     mUnionState = HasNothing;
     431             : #endif // DEBUG
     432        1616 :   } else if (IsErrorWithMessage()) {
     433           0 :     ClearMessage();
     434        1616 :   } else if (IsDOMException()) {
     435           0 :     ClearDOMExceptionInfo();
     436             :   }
     437        1616 : }
     438             : 
     439             : template<typename CleanupPolicy>
     440             : void
     441           0 : TErrorResult<CleanupPolicy>::SetPendingGenericErrorException(JSContext* cx)
     442             : {
     443           0 :   AssertInOwningThread();
     444           0 :   MOZ_ASSERT(!IsErrorWithMessage());
     445           0 :   MOZ_ASSERT(!IsJSException());
     446           0 :   MOZ_ASSERT(!IsDOMException());
     447           0 :   dom::Throw(cx, ErrorCode());
     448           0 :   mResult = NS_OK;
     449           0 : }
     450             : 
     451             : template<typename CleanupPolicy>
     452             : TErrorResult<CleanupPolicy>&
     453           0 : TErrorResult<CleanupPolicy>::operator=(TErrorResult<CleanupPolicy>&& aRHS)
     454             : {
     455           0 :   AssertInOwningThread();
     456           0 :   aRHS.AssertInOwningThread();
     457             :   // Clear out any union members we may have right now, before we
     458             :   // start writing to it.
     459           0 :   ClearUnionData();
     460             : 
     461             : #ifdef DEBUG
     462           0 :   mMightHaveUnreportedJSException = aRHS.mMightHaveUnreportedJSException;
     463           0 :   aRHS.mMightHaveUnreportedJSException = false;
     464             : #endif
     465           0 :   if (aRHS.IsErrorWithMessage()) {
     466           0 :     mMessage = aRHS.mMessage;
     467           0 :     aRHS.mMessage = nullptr;
     468           0 :   } else if (aRHS.IsJSException()) {
     469           0 :     JSContext* cx = dom::danger::GetJSContext();
     470           0 :     MOZ_ASSERT(cx);
     471           0 :     mJSException.setUndefined();
     472           0 :     if (!js::AddRawValueRoot(cx, &mJSException, "TErrorResult::mJSException")) {
     473           0 :       MOZ_CRASH("Could not root mJSException, we're about to OOM");
     474             :     }
     475           0 :     mJSException = aRHS.mJSException;
     476           0 :     aRHS.mJSException.setUndefined();
     477           0 :     js::RemoveRawValueRoot(cx, &aRHS.mJSException);
     478           0 :   } else if (aRHS.IsDOMException()) {
     479           0 :     mDOMExceptionInfo = aRHS.mDOMExceptionInfo;
     480           0 :     aRHS.mDOMExceptionInfo = nullptr;
     481             :   } else {
     482             :     // Null out the union on both sides for hygiene purposes.
     483           0 :     mMessage = aRHS.mMessage = nullptr;
     484             :   }
     485             : 
     486             : #ifdef DEBUG
     487           0 :   mUnionState = aRHS.mUnionState;
     488           0 :   aRHS.mUnionState = HasNothing;
     489             : #endif // DEBUG
     490             : 
     491             :   // Note: It's important to do this last, since this affects the condition
     492             :   // checks above!
     493           0 :   mResult = aRHS.mResult;
     494           0 :   aRHS.mResult = NS_OK;
     495           0 :   return *this;
     496             : }
     497             : 
     498             : template<typename CleanupPolicy>
     499             : void
     500           0 : TErrorResult<CleanupPolicy>::CloneTo(TErrorResult& aRv) const
     501             : {
     502           0 :   AssertInOwningThread();
     503           0 :   aRv.AssertInOwningThread();
     504             : 
     505           0 :   aRv.ClearUnionData();
     506           0 :   aRv.mResult = mResult;
     507             : #ifdef DEBUG
     508           0 :   aRv.mMightHaveUnreportedJSException = mMightHaveUnreportedJSException;
     509             : #endif
     510             : 
     511           0 :   if (IsErrorWithMessage()) {
     512             : #ifdef DEBUG
     513           0 :     aRv.mUnionState = HasMessage;
     514             : #endif
     515           0 :     aRv.mMessage = new Message();
     516           0 :     aRv.mMessage->mArgs = mMessage->mArgs;
     517           0 :     aRv.mMessage->mErrorNumber = mMessage->mErrorNumber;
     518           0 :   } else if (IsDOMException()) {
     519             : #ifdef DEBUG
     520           0 :     aRv.mUnionState = HasDOMExceptionInfo;
     521             : #endif
     522           0 :     aRv.mDOMExceptionInfo = new DOMExceptionInfo(mDOMExceptionInfo->mRv,
     523           0 :                                                  mDOMExceptionInfo->mMessage);
     524           0 :   } else if (IsJSException()) {
     525             : #ifdef DEBUG
     526           0 :     aRv.mUnionState = HasJSException;
     527             : #endif
     528           0 :     JSContext* cx = dom::danger::GetJSContext();
     529           0 :     JS::Rooted<JS::Value> exception(cx, mJSException);
     530           0 :     aRv.ThrowJSException(cx, exception);
     531             :   }
     532           0 : }
     533             : 
     534             : template<typename CleanupPolicy>
     535             : void
     536        1616 : TErrorResult<CleanupPolicy>::SuppressException()
     537             : {
     538        1616 :   AssertInOwningThread();
     539        1616 :   WouldReportJSException();
     540        1616 :   ClearUnionData();
     541             :   // We don't use AssignErrorCode, because we want to override existing error
     542             :   // states, which AssignErrorCode is not allowed to do.
     543        1616 :   mResult = NS_OK;
     544        1616 : }
     545             : 
     546             : template<typename CleanupPolicy>
     547             : void
     548           0 : TErrorResult<CleanupPolicy>::SetPendingException(JSContext* cx)
     549             : {
     550           0 :   AssertInOwningThread();
     551           0 :   if (IsUncatchableException()) {
     552             :     // Nuke any existing exception on cx, to make sure we're uncatchable.
     553           0 :     JS_ClearPendingException(cx);
     554             :     // Don't do any reporting.  Just return, to create an
     555             :     // uncatchable exception.
     556           0 :     mResult = NS_OK;
     557           0 :     return;
     558             :   }
     559           0 :   if (IsJSContextException()) {
     560             :     // Whatever we need to throw is on the JSContext already.
     561           0 :     MOZ_ASSERT(JS_IsExceptionPending(cx));
     562           0 :     mResult = NS_OK;
     563           0 :     return;
     564             :   }
     565           0 :   if (IsErrorWithMessage()) {
     566           0 :     SetPendingExceptionWithMessage(cx);
     567           0 :     return;
     568             :   }
     569           0 :   if (IsJSException()) {
     570           0 :     SetPendingJSException(cx);
     571           0 :     return;
     572             :   }
     573           0 :   if (IsDOMException()) {
     574           0 :     SetPendingDOMException(cx);
     575           0 :     return;
     576             :   }
     577           0 :   SetPendingGenericErrorException(cx);
     578             : }
     579             : 
     580             : template<typename CleanupPolicy>
     581             : void
     582           0 : TErrorResult<CleanupPolicy>::StealExceptionFromJSContext(JSContext* cx)
     583             : {
     584           0 :   AssertInOwningThread();
     585           0 :   MOZ_ASSERT(mMightHaveUnreportedJSException,
     586             :              "Why didn't you tell us you planned to throw a JS exception?");
     587             : 
     588           0 :   JS::Rooted<JS::Value> exn(cx);
     589           0 :   if (!JS_GetPendingException(cx, &exn)) {
     590           0 :     ThrowUncatchableException();
     591           0 :     return;
     592             :   }
     593             : 
     594           0 :   ThrowJSException(cx, exn);
     595           0 :   JS_ClearPendingException(cx);
     596             : }
     597             : 
     598             : template<typename CleanupPolicy>
     599             : void
     600           0 : TErrorResult<CleanupPolicy>::NoteJSContextException(JSContext* aCx)
     601             : {
     602           0 :   AssertInOwningThread();
     603           0 :   if (JS_IsExceptionPending(aCx)) {
     604           0 :     mResult = NS_ERROR_INTERNAL_ERRORRESULT_EXCEPTION_ON_JSCONTEXT;
     605             :   } else {
     606           0 :     mResult = NS_ERROR_UNCATCHABLE_EXCEPTION;
     607             :   }
     608           0 : }
     609             : 
     610             : template class TErrorResult<JustAssertCleanupPolicy>;
     611             : template class TErrorResult<AssertAndSuppressCleanupPolicy>;
     612             : template class TErrorResult<JustSuppressCleanupPolicy>;
     613             : 
     614             : } // namespace binding_danger
     615             : 
     616             : namespace dom {
     617             : 
     618             : bool
     619          97 : DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
     620             :                 const ConstantSpec* cs)
     621             : {
     622         194 :   JS::Rooted<JS::Value> value(cx);
     623        2167 :   for (; cs->name; ++cs) {
     624        1035 :     value = cs->value;
     625             :     bool ok =
     626        2070 :       JS_DefineProperty(cx, obj, cs->name, value,
     627        1035 :                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
     628        1035 :     if (!ok) {
     629           0 :       return false;
     630             :     }
     631             :   }
     632          97 :   return true;
     633             : }
     634             : 
     635             : static inline bool
     636         719 : Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSFunctionSpec* spec) {
     637         719 :   return JS_DefineFunctions(cx, obj, spec);
     638             : }
     639             : static inline bool
     640         938 : Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSPropertySpec* spec) {
     641         938 :   return JS_DefineProperties(cx, obj, spec);
     642             : }
     643             : static inline bool
     644          95 : Define(JSContext* cx, JS::Handle<JSObject*> obj, const ConstantSpec* spec) {
     645          95 :   return DefineConstants(cx, obj, spec);
     646             : }
     647             : 
     648             : template<typename T>
     649             : bool
     650        1171 : DefinePrefable(JSContext* cx, JS::Handle<JSObject*> obj,
     651             :                const Prefable<T>* props)
     652             : {
     653        1171 :   MOZ_ASSERT(props);
     654        1171 :   MOZ_ASSERT(props->specs);
     655        3962 :   do {
     656             :     // Define if enabled
     657        1981 :     if (props->isEnabled(cx, obj)) {
     658        1752 :       if (!Define(cx, obj, props->specs)) {
     659           0 :         return false;
     660             :       }
     661             :     }
     662        1981 :   } while ((++props)->specs);
     663        1171 :   return true;
     664             : }
     665             : 
     666             : bool
     667           3 : DefineUnforgeableMethods(JSContext* cx, JS::Handle<JSObject*> obj,
     668             :                          const Prefable<const JSFunctionSpec>* props)
     669             : {
     670           3 :   return DefinePrefable(cx, obj, props);
     671             : }
     672             : 
     673             : bool
     674          76 : DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
     675             :                             const Prefable<const JSPropertySpec>* props)
     676             : {
     677          76 :   return DefinePrefable(cx, obj, props);
     678             : }
     679             : 
     680             : 
     681             : // We should use JSFunction objects for interface objects, but we need a custom
     682             : // hasInstance hook because we have new interface objects on prototype chains of
     683             : // old (XPConnect-based) bindings. We also need Xrays and arbitrary numbers of
     684             : // reserved slots (e.g. for named constructors).  So we define a custom
     685             : // funToString ObjectOps member for interface objects.
     686             : JSString*
     687           0 : InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
     688             :                         unsigned /* indent */)
     689             : {
     690           0 :   const js::Class* clasp = js::GetObjectClass(aObject);
     691           0 :   MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
     692             : 
     693             :   const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
     694           0 :     DOMIfaceAndProtoJSClass::FromJSClass(clasp);
     695           0 :   return JS_NewStringCopyZ(aCx, ifaceAndProtoJSClass->mToString);
     696             : }
     697             : 
     698             : bool
     699           0 : Constructor(JSContext* cx, unsigned argc, JS::Value* vp)
     700             : {
     701           0 :   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     702             :   const JS::Value& v =
     703           0 :     js::GetFunctionNativeReserved(&args.callee(),
     704           0 :                                   CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
     705             :   const JSNativeHolder* nativeHolder =
     706           0 :     static_cast<const JSNativeHolder*>(v.toPrivate());
     707           0 :   return (nativeHolder->mNative)(cx, argc, vp);
     708             : }
     709             : 
     710             : static JSObject*
     711           0 : CreateConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name,
     712             :                   const JSNativeHolder* nativeHolder, unsigned ctorNargs)
     713             : {
     714             :   JSFunction* fun = js::NewFunctionWithReserved(cx, Constructor, ctorNargs,
     715           0 :                                                 JSFUN_CONSTRUCTOR, name);
     716           0 :   if (!fun) {
     717           0 :     return nullptr;
     718             :   }
     719             : 
     720           0 :   JSObject* constructor = JS_GetFunctionObject(fun);
     721             :   js::SetFunctionNativeReserved(constructor,
     722             :                                 CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT,
     723           0 :                                 js::PrivateValue(const_cast<JSNativeHolder*>(nativeHolder)));
     724           0 :   return constructor;
     725             : }
     726             : 
     727             : static bool
     728         445 : DefineConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name,
     729             :                   JS::Handle<JSObject*> constructor)
     730             : {
     731             :   bool alreadyDefined;
     732         445 :   if (!JS_AlreadyHasOwnProperty(cx, global, name, &alreadyDefined)) {
     733           0 :     return false;
     734             :   }
     735             : 
     736             :   // This is Enumerable: False per spec.
     737         890 :   return alreadyDefined ||
     738         890 :          JS_DefineProperty(cx, global, name, constructor, JSPROP_RESOLVING);
     739             : }
     740             : 
     741             : static JSObject*
     742         445 : CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
     743             :                       JS::Handle<JSObject*> constructorProto,
     744             :                       const js::Class* constructorClass,
     745             :                       unsigned ctorNargs, const NamedConstructor* namedConstructors,
     746             :                       JS::Handle<JSObject*> proto,
     747             :                       const NativeProperties* properties,
     748             :                       const NativeProperties* chromeOnlyProperties,
     749             :                       const char* name, bool defineOnGlobal)
     750             : {
     751         890 :   JS::Rooted<JSObject*> constructor(cx);
     752         445 :   MOZ_ASSERT(constructorProto);
     753         445 :   MOZ_ASSERT(constructorClass);
     754         890 :   constructor = JS_NewObjectWithGivenProto(cx, Jsvalify(constructorClass),
     755         445 :                                            constructorProto);
     756         445 :   if (!constructor) {
     757           0 :     return nullptr;
     758             :   }
     759             : 
     760         445 :   if (!JS_DefineProperty(cx, constructor, "length", ctorNargs,
     761             :                          JSPROP_READONLY)) {
     762           0 :     return nullptr;
     763             :   }
     764             : 
     765             :   // Might as well intern, since we're going to need an atomized
     766             :   // version of name anyway when we stick our constructor on the
     767             :   // global.
     768         890 :   JS::Rooted<JSString*> nameStr(cx, JS_AtomizeAndPinString(cx, name));
     769         445 :   if (!nameStr) {
     770           0 :     return nullptr;
     771             :   }
     772             : 
     773         445 :   if (!JS_DefineProperty(cx, constructor, "name", nameStr, JSPROP_READONLY)) {
     774           0 :     return nullptr;
     775             :   }
     776             : 
     777         445 :   if (DOMIfaceAndProtoJSClass::FromJSClass(constructorClass)->wantsInterfaceHasInstance) {
     778             :     JS::Rooted<jsid> hasInstanceId(cx,
     779         810 :       SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::hasInstance)));
     780         405 :     if (!JS_DefineFunctionById(cx, constructor, hasInstanceId,
     781             :                                InterfaceHasInstance, 1,
     782             :                                // Flags match those of Function[Symbol.hasInstance]
     783             :                                JSPROP_READONLY | JSPROP_PERMANENT)) {
     784           0 :       return nullptr;
     785             :     }
     786             :   }
     787             : 
     788         445 :   if (properties) {
     789        1401 :     if (properties->HasStaticMethods() &&
     790         691 :         !DefinePrefable(cx, constructor, properties->StaticMethods())) {
     791           0 :       return nullptr;
     792             :     }
     793             : 
     794        1318 :     if (properties->HasStaticAttributes() &&
     795         442 :         !DefinePrefable(cx, constructor, properties->StaticAttributes())) {
     796           0 :       return nullptr;
     797             :     }
     798             : 
     799        1366 :     if (properties->HasConstants() &&
     800         586 :         !DefinePrefable(cx, constructor, properties->Constants())) {
     801           0 :       return nullptr;
     802             :     }
     803             :   }
     804             : 
     805         445 :   if (chromeOnlyProperties) {
     806         374 :     if (chromeOnlyProperties->HasStaticMethods() &&
     807         170 :         !DefinePrefable(cx, constructor,
     808             :                         chromeOnlyProperties->StaticMethods())) {
     809           0 :       return nullptr;
     810             :     }
     811             : 
     812         357 :     if (chromeOnlyProperties->HasStaticAttributes() &&
     813         119 :         !DefinePrefable(cx, constructor,
     814             :                         chromeOnlyProperties->StaticAttributes())) {
     815           0 :       return nullptr;
     816             :     }
     817             : 
     818         360 :     if (chromeOnlyProperties->HasConstants() &&
     819         128 :         !DefinePrefable(cx, constructor, chromeOnlyProperties->Constants())) {
     820           0 :       return nullptr;
     821             :     }
     822             :   }
     823             : 
     824         445 :   if (proto && !JS_LinkConstructorAndPrototype(cx, constructor, proto)) {
     825           0 :     return nullptr;
     826             :   }
     827             : 
     828         445 :   if (defineOnGlobal && !DefineConstructor(cx, global, name, constructor)) {
     829           0 :     return nullptr;
     830             :   }
     831             : 
     832         445 :   if (namedConstructors) {
     833           0 :     int namedConstructorSlot = DOM_INTERFACE_SLOTS_BASE;
     834           0 :     while (namedConstructors->mName) {
     835             :       JS::Rooted<JSObject*> namedConstructor(cx,
     836           0 :         CreateConstructor(cx, global, namedConstructors->mName,
     837             :                           &namedConstructors->mHolder,
     838           0 :                           namedConstructors->mNargs));
     839           0 :       if (!namedConstructor ||
     840           0 :           !JS_DefineProperty(cx, namedConstructor, "prototype",
     841             :                              proto,
     842             :                              JSPROP_PERMANENT | JSPROP_READONLY,
     843           0 :                              JS_STUBGETTER, JS_STUBSETTER) ||
     844           0 :           (defineOnGlobal &&
     845           0 :            !DefineConstructor(cx, global, namedConstructors->mName,
     846             :                               namedConstructor))) {
     847           0 :         return nullptr;
     848             :       }
     849           0 :       js::SetReservedSlot(constructor, namedConstructorSlot++,
     850           0 :                           JS::ObjectValue(*namedConstructor));
     851           0 :       ++namedConstructors;
     852             :     }
     853             :   }
     854             : 
     855         445 :   return constructor;
     856             : }
     857             : 
     858             : static JSObject*
     859         460 : CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
     860             :                                JS::Handle<JSObject*> parentProto,
     861             :                                const js::Class* protoClass,
     862             :                                const NativeProperties* properties,
     863             :                                const NativeProperties* chromeOnlyProperties,
     864             :                                const char* const* unscopableNames,
     865             :                                bool isGlobal)
     866             : {
     867             :   JS::Rooted<JSObject*> ourProto(cx,
     868         920 :     JS_NewObjectWithUniqueType(cx, Jsvalify(protoClass), parentProto));
     869        1388 :   if (!ourProto ||
     870             :       // We don't try to define properties on the global's prototype; those
     871             :       // properties go on the global itself.
     872        1364 :       (!isGlobal &&
     873        1816 :        !DefineProperties(cx, ourProto, properties, chromeOnlyProperties))) {
     874           0 :     return nullptr;
     875             :   }
     876             : 
     877         460 :   if (unscopableNames) {
     878          22 :     JS::Rooted<JSObject*> unscopableObj(cx, JS_NewPlainObject(cx));
     879          11 :     if (!unscopableObj) {
     880           0 :       return nullptr;
     881             :     }
     882             : 
     883          75 :     for (; *unscopableNames; ++unscopableNames) {
     884          32 :       if (!JS_DefineProperty(cx, unscopableObj, *unscopableNames,
     885             :                              JS::TrueHandleValue, JSPROP_ENUMERATE)) {
     886           0 :         return nullptr;
     887             :       }
     888             :     }
     889             : 
     890             :     JS::Rooted<jsid> unscopableId(cx,
     891          22 :       SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::unscopables)));
     892             :     // Readonly and non-enumerable to match Array.prototype.
     893          11 :     if (!JS_DefinePropertyById(cx, ourProto, unscopableId, unscopableObj,
     894             :                                JSPROP_READONLY)) {
     895           0 :       return nullptr;
     896             :     }
     897             :   }
     898             : 
     899         460 :   return ourProto;
     900             : }
     901             : 
     902             : bool
     903         460 : DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
     904             :                  const NativeProperties* properties,
     905             :                  const NativeProperties* chromeOnlyProperties)
     906             : {
     907         460 :   if (properties) {
     908         803 :     if (properties->HasMethods() &&
     909         349 :         !DefinePrefable(cx, obj, properties->Methods())) {
     910           0 :       return false;
     911             :     }
     912             : 
     913         820 :     if (properties->HasAttributes() &&
     914         366 :         !DefinePrefable(cx, obj, properties->Attributes())) {
     915           0 :       return false;
     916             :     }
     917             : 
     918         503 :     if (properties->HasConstants() &&
     919          49 :         !DefinePrefable(cx, obj, properties->Constants())) {
     920           0 :       return false;
     921             :     }
     922             :   }
     923             : 
     924         460 :   if (chromeOnlyProperties) {
     925         212 :     if (chromeOnlyProperties->HasMethods() &&
     926          74 :         !DefinePrefable(cx, obj, chromeOnlyProperties->Methods())) {
     927           0 :       return false;
     928             :     }
     929             : 
     930         236 :     if (chromeOnlyProperties->HasAttributes() &&
     931          98 :         !DefinePrefable(cx, obj, chromeOnlyProperties->Attributes())) {
     932           0 :       return false;
     933             :     }
     934             : 
     935         140 :     if (chromeOnlyProperties->HasConstants() &&
     936           2 :         !DefinePrefable(cx, obj, chromeOnlyProperties->Constants())) {
     937           0 :       return false;
     938             :     }
     939             :   }
     940             : 
     941         460 :   return true;
     942             : }
     943             : 
     944             : void
     945         466 : CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
     946             :                        JS::Handle<JSObject*> protoProto,
     947             :                        const js::Class* protoClass, JS::Heap<JSObject*>* protoCache,
     948             :                        JS::Handle<JSObject*> constructorProto,
     949             :                        const js::Class* constructorClass,
     950             :                        unsigned ctorNargs, const NamedConstructor* namedConstructors,
     951             :                        JS::Heap<JSObject*>* constructorCache,
     952             :                        const NativeProperties* properties,
     953             :                        const NativeProperties* chromeOnlyProperties,
     954             :                        const char* name, bool defineOnGlobal,
     955             :                        const char* const* unscopableNames,
     956             :                        bool isGlobal)
     957             : {
     958         466 :   MOZ_ASSERT(protoClass || constructorClass,
     959             :              "Need at least one class!");
     960         466 :   MOZ_ASSERT(!((properties &&
     961             :                 (properties->HasMethods() || properties->HasAttributes())) ||
     962             :                (chromeOnlyProperties &&
     963             :                 (chromeOnlyProperties->HasMethods() ||
     964             :                  chromeOnlyProperties->HasAttributes()))) || protoClass,
     965             :              "Methods or properties but no protoClass!");
     966         466 :   MOZ_ASSERT(!((properties &&
     967             :                 (properties->HasStaticMethods() ||
     968             :                  properties->HasStaticAttributes())) ||
     969             :                (chromeOnlyProperties &&
     970             :                 (chromeOnlyProperties->HasStaticMethods() ||
     971             :                  chromeOnlyProperties->HasStaticAttributes()))) ||
     972             :              constructorClass,
     973             :              "Static methods but no constructorClass!");
     974         466 :   MOZ_ASSERT(bool(name) == bool(constructorClass),
     975             :              "Must have name precisely when we have an interface object");
     976         466 :   MOZ_ASSERT(!protoClass == !protoCache,
     977             :              "If, and only if, there is an interface prototype object we need "
     978             :              "to cache it");
     979         466 :   MOZ_ASSERT(bool(constructorClass) == bool(constructorCache),
     980             :              "If, and only if, there is an interface object we need to cache "
     981             :              "it");
     982         466 :   MOZ_ASSERT(constructorProto || !constructorClass,
     983             :              "Must have a constructor proto if we plan to create a constructor "
     984             :              "object");
     985             : 
     986         932 :   JS::Rooted<JSObject*> proto(cx);
     987         466 :   if (protoClass) {
     988             :     proto =
     989         920 :       CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
     990             :                                      properties, chromeOnlyProperties,
     991         460 :                                      unscopableNames, isGlobal);
     992         460 :     if (!proto) {
     993           0 :       return;
     994             :     }
     995             : 
     996         460 :     *protoCache = proto;
     997             :   }
     998             :   else {
     999           6 :     MOZ_ASSERT(!proto);
    1000             :   }
    1001             : 
    1002             :   JSObject* interface;
    1003         466 :   if (constructorClass) {
    1004         445 :     interface = CreateInterfaceObject(cx, global, constructorProto,
    1005             :                                       constructorClass, ctorNargs,
    1006             :                                       namedConstructors, proto, properties,
    1007             :                                       chromeOnlyProperties, name,
    1008             :                                       defineOnGlobal);
    1009         445 :     if (!interface) {
    1010           0 :       if (protoCache) {
    1011             :         // If we fail we need to make sure to clear the value of protoCache we
    1012             :         // set above.
    1013           0 :         *protoCache = nullptr;
    1014             :       }
    1015           0 :       return;
    1016             :     }
    1017         445 :     *constructorCache = interface;
    1018             :   }
    1019             : }
    1020             : 
    1021             : bool
    1022         709 : NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
    1023             :                                          JS::Handle<JSObject*> aScope,
    1024             :                                          JS::MutableHandle<JS::Value> aRetval,
    1025             :                                          xpcObjectHelper& aHelper,
    1026             :                                          const nsIID* aIID,
    1027             :                                          bool aAllowNativeWrapper)
    1028             : {
    1029         709 :   js::AssertSameCompartment(aCx, aScope);
    1030             :   nsresult rv;
    1031             :   // Inline some logic from XPCConvert::NativeInterfaceToJSObject that we need
    1032             :   // on all threads.
    1033         709 :   nsWrapperCache *cache = aHelper.GetWrapperCache();
    1034             : 
    1035         709 :   if (cache && cache->IsDOMBinding()) {
    1036         512 :       JS::Rooted<JSObject*> obj(aCx, cache->GetWrapper());
    1037         512 :       if (!obj) {
    1038           0 :         obj = cache->WrapObject(aCx, nullptr);
    1039             :       }
    1040             : 
    1041         512 :       if (obj && aAllowNativeWrapper && !JS_WrapObject(aCx, &obj)) {
    1042           0 :         return false;
    1043             :       }
    1044             : 
    1045         512 :       if (obj) {
    1046         512 :         aRetval.setObject(*obj);
    1047         512 :         return true;
    1048             :       }
    1049             :   }
    1050             : 
    1051         197 :   MOZ_ASSERT(NS_IsMainThread());
    1052             : 
    1053         197 :   if (!XPCConvert::NativeInterface2JSObject(aRetval, nullptr, aHelper, aIID,
    1054             :                                             aAllowNativeWrapper, &rv)) {
    1055             :     // I can't tell if NativeInterface2JSObject throws JS exceptions
    1056             :     // or not.  This is a sloppy stab at the right semantics; the
    1057             :     // method really ought to be fixed to behave consistently.
    1058           0 :     if (!JS_IsExceptionPending(aCx)) {
    1059           0 :       Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
    1060             :     }
    1061           0 :     return false;
    1062             :   }
    1063         197 :   return true;
    1064             : }
    1065             : 
    1066             : bool
    1067          15 : TryPreserveWrapper(JSObject* obj)
    1068             : {
    1069          15 :   MOZ_ASSERT(IsDOMObject(obj));
    1070             : 
    1071          15 :   if (nsISupports* native = UnwrapDOMObjectToISupports(obj)) {
    1072          15 :     nsWrapperCache* cache = nullptr;
    1073          15 :     CallQueryInterface(native, &cache);
    1074          15 :     if (cache) {
    1075          15 :       cache->PreserveWrapper(native);
    1076             :     }
    1077          15 :     return true;
    1078             :   }
    1079             : 
    1080             :   // If this DOMClass is not cycle collected, then it isn't wrappercached,
    1081             :   // so it does not need to be preserved. If it is cycle collected, then
    1082             :   // we can't tell if it is wrappercached or not, so we just return false.
    1083           0 :   const DOMJSClass* domClass = GetDOMClass(obj);
    1084           0 :   return domClass && !domClass->mParticipant;
    1085             : }
    1086             : 
    1087             : // Can only be called with a DOM JSClass.
    1088             : bool
    1089           0 : InstanceClassHasProtoAtDepth(const js::Class* clasp,
    1090             :                              uint32_t protoID, uint32_t depth)
    1091             : {
    1092           0 :   const DOMJSClass* domClass = DOMJSClass::FromJSClass(clasp);
    1093           0 :   return static_cast<uint32_t>(domClass->mInterfaceChain[depth]) == protoID;
    1094             : }
    1095             : 
    1096             : // Only set allowNativeWrapper to false if you really know you need it, if in
    1097             : // doubt use true. Setting it to false disables security wrappers.
    1098             : bool
    1099         709 : XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
    1100             :                    xpcObjectHelper& helper, const nsIID* iid,
    1101             :                    bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval)
    1102             : {
    1103         709 :   if (!NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval, helper, iid,
    1104             :                                                 allowNativeWrapper)) {
    1105           0 :     return false;
    1106             :   }
    1107             : 
    1108             : #ifdef DEBUG
    1109         709 :   JSObject* jsobj = rval.toObjectOrNull();
    1110        1418 :   if (jsobj &&
    1111         709 :       js::GetGlobalForObjectCrossCompartment(jsobj) == jsobj) {
    1112          10 :     NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
    1113             :                  "Why did we recreate this wrapper?");
    1114             :   }
    1115             : #endif
    1116             : 
    1117         709 :   return true;
    1118             : }
    1119             : 
    1120             : bool
    1121           0 : VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
    1122             :                JS::MutableHandle<JS::Value> aRetval)
    1123             : {
    1124             :   nsresult rv;
    1125           0 :   if (!XPCVariant::VariantDataToJS(aVariant, &rv, aRetval)) {
    1126             :     // Does it throw?  Who knows
    1127           0 :     if (!JS_IsExceptionPending(aCx)) {
    1128           0 :       Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
    1129             :     }
    1130           0 :     return false;
    1131             :   }
    1132             : 
    1133           0 :   return true;
    1134             : }
    1135             : 
    1136             : static int
    1137       23526 : CompareIdsAtIndices(const void* aElement1, const void* aElement2, void* aClosure)
    1138             : {
    1139       23526 :   const uint16_t index1 = *static_cast<const uint16_t*>(aElement1);
    1140       23526 :   const uint16_t index2 = *static_cast<const uint16_t*>(aElement2);
    1141       23526 :   const PropertyInfo* infos = static_cast<PropertyInfo*>(aClosure);
    1142             : 
    1143       23526 :   MOZ_ASSERT(JSID_BITS(infos[index1].id) != JSID_BITS(infos[index2].id));
    1144             : 
    1145       23526 :   return JSID_BITS(infos[index1].id) < JSID_BITS(infos[index2].id) ? -1 : 1;
    1146             : }
    1147             : 
    1148             : template <typename SpecT>
    1149             : static bool
    1150         270 : InitIdsInternal(JSContext* cx, const Prefable<SpecT>* pref, PropertyInfo* infos,
    1151             :                 PropertyType type)
    1152             : {
    1153         270 :   MOZ_ASSERT(pref);
    1154         270 :   MOZ_ASSERT(pref->specs);
    1155             : 
    1156             :   // Index of the Prefable that contains the id for the current PropertyInfo.
    1157         270 :   uint32_t prefIndex = 0;
    1158             : 
    1159        1142 :   do {
    1160             :     // We ignore whether the set of ids is enabled and just intern all the IDs,
    1161             :     // because this is only done once per application runtime.
    1162         571 :     const SpecT* spec = pref->specs;
    1163             :     // Index of the property/function/constant spec for our current PropertyInfo
    1164             :     // in the "specs" array of the relevant Prefable.
    1165         571 :     uint32_t specIndex = 0;
    1166        7224 :     do {
    1167        3612 :       if (!JS::PropertySpecNameToPermanentId(cx, spec->name, &infos->id)) {
    1168           0 :         return false;
    1169             :       }
    1170        3612 :       infos->type = type;
    1171        3612 :       infos->prefIndex = prefIndex;
    1172        3612 :       infos->specIndex = specIndex++;
    1173        3612 :       ++infos;
    1174        3612 :     } while ((++spec)->name);
    1175         571 :     ++prefIndex;
    1176         571 :   } while ((++pref)->specs);
    1177             : 
    1178         270 :   return true;
    1179             : }
    1180             : 
    1181             : #define INIT_IDS_IF_DEFINED(TypeName) {                                       \
    1182             :   if (nativeProperties->Has##TypeName##s() &&                                 \
    1183             :       !InitIdsInternal(cx,                                                    \
    1184             :                        nativeProperties->TypeName##s(),                       \
    1185             :                        nativeProperties->TypeName##PropertyInfos(),           \
    1186             :                        e##TypeName)) {                                        \
    1187             :     return false;                                                             \
    1188             :   }                                                                           \
    1189             : }
    1190             : 
    1191             : bool
    1192         141 : InitIds(JSContext* cx, const NativeProperties* nativeProperties)
    1193             : {
    1194         141 :   INIT_IDS_IF_DEFINED(StaticMethod);
    1195         141 :   INIT_IDS_IF_DEFINED(StaticAttribute);
    1196         141 :   INIT_IDS_IF_DEFINED(Method);
    1197         141 :   INIT_IDS_IF_DEFINED(Attribute);
    1198         141 :   INIT_IDS_IF_DEFINED(UnforgeableMethod);
    1199         141 :   INIT_IDS_IF_DEFINED(UnforgeableAttribute);
    1200         141 :   INIT_IDS_IF_DEFINED(Constant);
    1201             : 
    1202             :   // Initialize and sort the index array.
    1203         141 :   uint16_t* indices = nativeProperties->sortedPropertyIndices;
    1204        3753 :   for (unsigned int i = 0; i < nativeProperties->propertyInfoCount; ++i) {
    1205        3612 :     indices[i] = i;
    1206             :   }
    1207             :   // CompareIdsAtIndices() doesn't actually modify the PropertyInfo array, so
    1208             :   // the const_cast here is OK in spite of the signature of NS_QuickSort().
    1209         141 :   NS_QuickSort(indices, nativeProperties->propertyInfoCount, sizeof(uint16_t),
    1210             :                CompareIdsAtIndices,
    1211         282 :                const_cast<PropertyInfo*>(nativeProperties->PropertyInfos()));
    1212             : 
    1213         141 :   return true;
    1214             : }
    1215             : 
    1216             : #undef INIT_IDS_IF_DEFINED
    1217             : 
    1218             : bool
    1219         113 : QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
    1220             : {
    1221         113 :   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    1222         226 :   JS::Rooted<JS::Value> thisv(cx, JS_THIS(cx, vp));
    1223         113 :   if (thisv.isNull())
    1224           0 :     return false;
    1225             : 
    1226             :   // Get the object. It might be a security wrapper, in which case we do a checked
    1227             :   // unwrap.
    1228         226 :   JS::Rooted<JSObject*> origObj(cx, &thisv.toObject());
    1229         226 :   JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(origObj,
    1230         339 :                                                   /* stopAtWindowProxy = */ false));
    1231         113 :   if (!obj) {
    1232           0 :       JS_ReportErrorASCII(cx, "Permission denied to access object");
    1233           0 :       return false;
    1234             :   }
    1235             : 
    1236             :   // Switch this to UnwrapDOMObjectToISupports once our global objects are
    1237             :   // using new bindings.
    1238         226 :   nsCOMPtr<nsISupports> native;
    1239         113 :   UnwrapArg<nsISupports>(cx, obj, getter_AddRefs(native));
    1240         113 :   if (!native) {
    1241           0 :     return Throw(cx, NS_ERROR_FAILURE);
    1242             :   }
    1243             : 
    1244         113 :   if (argc < 1) {
    1245           0 :     return Throw(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
    1246             :   }
    1247             : 
    1248         113 :   if (!args[0].isObject()) {
    1249           0 :     return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
    1250             :   }
    1251             : 
    1252         226 :   nsCOMPtr<nsIJSID> iid;
    1253         113 :   obj = &args[0].toObject();
    1254         113 :   if (NS_FAILED(UnwrapArg<nsIJSID>(cx, obj, getter_AddRefs(iid)))) {
    1255           0 :     return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
    1256             :   }
    1257         113 :   MOZ_ASSERT(iid);
    1258             : 
    1259         113 :   if (iid->GetID()->Equals(NS_GET_IID(nsIClassInfo))) {
    1260             :     nsresult rv;
    1261           0 :     nsCOMPtr<nsIClassInfo> ci = do_QueryInterface(native, &rv);
    1262           0 :     if (NS_FAILED(rv)) {
    1263           0 :       return Throw(cx, rv);
    1264             :     }
    1265             : 
    1266           0 :     return WrapObject(cx, ci, &NS_GET_IID(nsIClassInfo), args.rval());
    1267             :   }
    1268             : 
    1269         226 :   nsCOMPtr<nsISupports> unused;
    1270         113 :   nsresult rv = native->QueryInterface(*iid->GetID(), getter_AddRefs(unused));
    1271         113 :   if (NS_FAILED(rv)) {
    1272           1 :     return Throw(cx, rv);
    1273             :   }
    1274             : 
    1275         112 :   *vp = thisv;
    1276         112 :   return true;
    1277             : }
    1278             : 
    1279             : void
    1280          39 : GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
    1281             :                  nsWrapperCache* aCache, nsIJSID* aIID,
    1282             :                  JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
    1283             : {
    1284          39 :   const nsID* iid = aIID->GetID();
    1285             : 
    1286          78 :   RefPtr<nsISupports> result;
    1287          39 :   aError = aRequestor->GetInterface(*iid, getter_AddRefs(result));
    1288          39 :   if (aError.Failed()) {
    1289           0 :     return;
    1290             :   }
    1291             : 
    1292          39 :   if (!WrapObject(aCx, result, iid, aRetval)) {
    1293           0 :     aError.Throw(NS_ERROR_FAILURE);
    1294             :   }
    1295             : }
    1296             : 
    1297             : bool
    1298           0 : ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
    1299             : {
    1300           0 :   return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
    1301             : }
    1302             : 
    1303             : bool
    1304           0 : ThrowConstructorWithoutNew(JSContext* cx, const char* name)
    1305             : {
    1306           0 :   return ThrowErrorMessage(cx, MSG_CONSTRUCTOR_WITHOUT_NEW, name);
    1307             : }
    1308             : 
    1309             : inline const NativePropertyHooks*
    1310           0 : GetNativePropertyHooksFromConstructorFunction(JS::Handle<JSObject*> obj)
    1311             : {
    1312           0 :   MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
    1313             :   const JS::Value& v =
    1314             :     js::GetFunctionNativeReserved(obj,
    1315           0 :                                   CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
    1316             :   const JSNativeHolder* nativeHolder =
    1317           0 :     static_cast<const JSNativeHolder*>(v.toPrivate());
    1318           0 :   return nativeHolder->mPropertyHooks;
    1319             : }
    1320             : 
    1321             : inline const NativePropertyHooks*
    1322         349 : GetNativePropertyHooks(JSContext *cx, JS::Handle<JSObject*> obj,
    1323             :                        DOMObjectType& type)
    1324             : {
    1325         349 :   const js::Class* clasp = js::GetObjectClass(obj);
    1326             : 
    1327         349 :   const DOMJSClass* domClass = GetDOMClass(clasp);
    1328         349 :   if (domClass) {
    1329         159 :     bool isGlobal = (clasp->flags & JSCLASS_DOM_GLOBAL) != 0;
    1330         159 :     type = isGlobal ? eGlobalInstance : eInstance;
    1331         159 :     return domClass->mNativeHooks;
    1332             :   }
    1333             : 
    1334         190 :   if (JS_ObjectIsFunction(cx, obj)) {
    1335           0 :     type = eInterface;
    1336           0 :     return GetNativePropertyHooksFromConstructorFunction(obj);
    1337             :   }
    1338             : 
    1339         190 :   MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj)));
    1340             :   const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
    1341         190 :     DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
    1342         190 :   type = ifaceAndProtoJSClass->mType;
    1343         190 :   return ifaceAndProtoJSClass->mNativeHooks;
    1344             : }
    1345             : 
    1346             : static JSObject*
    1347         124 : XrayCreateFunction(JSContext* cx, JS::Handle<JSObject*> wrapper,
    1348             :                    JSNativeWrapper native, unsigned nargs, JS::Handle<jsid> id)
    1349             : {
    1350             :   JSFunction* fun;
    1351         124 :   if (JSID_IS_STRING(id)) {
    1352         124 :     fun = js::NewFunctionByIdWithReserved(cx, native.op, nargs, 0, id);
    1353             :   } else {
    1354             :     // Can't pass this id (probably a symbol) to NewFunctionByIdWithReserved;
    1355             :     // just use an empty name for lack of anything better.
    1356           0 :     fun = js::NewFunctionWithReserved(cx, native.op, nargs, 0, nullptr);
    1357             :   }
    1358             : 
    1359         124 :   if (!fun) {
    1360           0 :     return nullptr;
    1361             :   }
    1362             : 
    1363         124 :   SET_JITINFO(fun, native.info);
    1364         124 :   JSObject* obj = JS_GetFunctionObject(fun);
    1365             :   js::SetFunctionNativeReserved(obj, XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT,
    1366         124 :                                 JS::ObjectValue(*wrapper));
    1367             : #ifdef DEBUG
    1368             :   js::SetFunctionNativeReserved(obj, XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_SELF,
    1369         124 :                                 JS::ObjectValue(*obj));
    1370             : #endif
    1371         124 :   return obj;
    1372             : }
    1373             : 
    1374             : struct IdToIndexComparator
    1375             : {
    1376             :   // The id we're searching for.
    1377             :   const jsid& mId;
    1378             :   // The list of ids we're searching in.
    1379             :   const PropertyInfo* mInfos;
    1380             : 
    1381         530 :   explicit IdToIndexComparator(const jsid& aId, const PropertyInfo* aInfos) :
    1382         530 :     mId(aId), mInfos(aInfos) {}
    1383        1898 :   int operator()(const uint16_t aIndex) const {
    1384        1898 :     if (JSID_BITS(mId) == JSID_BITS(mInfos[aIndex].id)) {
    1385         125 :       return 0;
    1386             :     }
    1387        1773 :     return JSID_BITS(mId) < JSID_BITS(mInfos[aIndex].id) ? -1 : 1;
    1388             :   }
    1389             : };
    1390             : 
    1391             : static const PropertyInfo*
    1392         530 : XrayFindOwnPropertyInfo(JSContext* cx, JS::Handle<jsid> id,
    1393             :                         const NativeProperties* nativeProperties)
    1394             : {
    1395        1590 :   if (MOZ_UNLIKELY(nativeProperties->iteratorAliasMethodIndex >= 0) &&
    1396         530 :       id == SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::iterator))) {
    1397           0 :     return nativeProperties->MethodPropertyInfos() +
    1398           0 :            nativeProperties->iteratorAliasMethodIndex;
    1399             :   }
    1400             : 
    1401             :   size_t idx;
    1402         530 :   const uint16_t* sortedPropertyIndices = nativeProperties->sortedPropertyIndices;
    1403         530 :   const PropertyInfo* propertyInfos = nativeProperties->PropertyInfos();
    1404             : 
    1405        1060 :   if (BinarySearchIf(sortedPropertyIndices, 0,
    1406         530 :                      nativeProperties->propertyInfoCount,
    1407        1060 :                      IdToIndexComparator(id, propertyInfos), &idx)) {
    1408         125 :     return propertyInfos + sortedPropertyIndices[idx];
    1409             :   }
    1410             : 
    1411         405 :   return nullptr;
    1412             : }
    1413             : 
    1414             : static bool
    1415          86 : XrayResolveAttribute(JSContext* cx, JS::Handle<JSObject*> wrapper,
    1416             :                      JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
    1417             :                      const Prefable<const JSPropertySpec>& pref,
    1418             :                      const JSPropertySpec& attrSpec,
    1419             :                      JS::MutableHandle<JS::PropertyDescriptor> desc,
    1420             :                      bool& cacheOnHolder)
    1421             : {
    1422          86 :   if (!pref.isEnabled(cx, obj)) {
    1423           0 :     return true;
    1424             :   }
    1425             : 
    1426          86 :   cacheOnHolder = true;
    1427             : 
    1428             :   // Because of centralization, we need to make sure we fault in the JitInfos as
    1429             :   // well. At present, until the JSAPI changes, the easiest way to do this is
    1430             :   // wrap them up as functions ourselves.
    1431          86 :   desc.setAttributes(attrSpec.flags);
    1432             :   // They all have getters, so we can just make it.
    1433             :   JS::Rooted<JSObject*> funobj(cx,
    1434         172 :     XrayCreateFunction(cx, wrapper, attrSpec.accessors.getter.native, 0, id));
    1435          86 :   if (!funobj)
    1436           0 :     return false;
    1437          86 :   desc.setGetterObject(funobj);
    1438          86 :   desc.attributesRef() |= JSPROP_GETTER;
    1439          86 :   if (attrSpec.accessors.setter.native.op) {
    1440             :     // We have a setter! Make it.
    1441             :     funobj =
    1442          22 :       XrayCreateFunction(cx, wrapper, attrSpec.accessors.setter.native, 1, id);
    1443          22 :     if (!funobj)
    1444           0 :       return false;
    1445          22 :     desc.setSetterObject(funobj);
    1446          22 :     desc.attributesRef() |= JSPROP_SETTER;
    1447             :   } else {
    1448          64 :     desc.setSetter(nullptr);
    1449             :   }
    1450          86 :   desc.object().set(wrapper);
    1451          86 :   desc.value().setUndefined();
    1452             : 
    1453          86 :   return true;
    1454             : }
    1455             : 
    1456             : static bool
    1457          16 : XrayResolveMethod(JSContext* cx, JS::Handle<JSObject*> wrapper,
    1458             :                   JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
    1459             :                   const Prefable<const JSFunctionSpec>& pref,
    1460             :                   const JSFunctionSpec& methodSpec,
    1461             :                   JS::MutableHandle<JS::PropertyDescriptor> desc,
    1462             :                   bool& cacheOnHolder)
    1463             : {
    1464          16 :   if (!pref.isEnabled(cx, obj)) {
    1465           0 :     return true;
    1466             :   }
    1467             : 
    1468          16 :   cacheOnHolder = true;
    1469             : 
    1470             :   JSObject *funobj;
    1471          16 :   if (methodSpec.selfHostedName) {
    1472             :     JSFunction* fun =
    1473           0 :       JS::GetSelfHostedFunction(cx, methodSpec.selfHostedName, id,
    1474           0 :                                 methodSpec.nargs);
    1475           0 :     if (!fun) {
    1476           0 :       return false;
    1477             :     }
    1478           0 :     MOZ_ASSERT(!methodSpec.call.op, "Bad FunctionSpec declaration: non-null native");
    1479           0 :     MOZ_ASSERT(!methodSpec.call.info, "Bad FunctionSpec declaration: non-null jitinfo");
    1480           0 :     funobj = JS_GetFunctionObject(fun);
    1481             :   } else {
    1482          16 :     funobj = XrayCreateFunction(cx, wrapper, methodSpec.call,
    1483          32 :                                 methodSpec.nargs, id);
    1484          16 :     if (!funobj) {
    1485           0 :       return false;
    1486             :     }
    1487             :   }
    1488          16 :   desc.value().setObject(*funobj);
    1489          16 :   desc.setAttributes(methodSpec.flags);
    1490          16 :   desc.object().set(wrapper);
    1491          16 :   desc.setSetter(nullptr);
    1492          16 :   desc.setGetter(nullptr);
    1493             : 
    1494          16 :   return true;
    1495             : }
    1496             : 
    1497             : static bool
    1498           0 : XrayResolveConstant(JSContext* cx, JS::Handle<JSObject*> wrapper,
    1499             :                     JS::Handle<JSObject*> obj, JS::Handle<jsid>,
    1500             :                     const Prefable<const ConstantSpec>& pref,
    1501             :                     const ConstantSpec& constantSpec,
    1502             :                     JS::MutableHandle<JS::PropertyDescriptor> desc,
    1503             :                     bool& cacheOnHolder)
    1504             : {
    1505           0 :   if (!pref.isEnabled(cx, obj)) {
    1506           0 :     return true;
    1507             :   }
    1508             : 
    1509           0 :   cacheOnHolder = true;
    1510             : 
    1511           0 :   desc.setAttributes(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
    1512           0 :   desc.object().set(wrapper);
    1513           0 :   desc.value().set(constantSpec.value);
    1514             : 
    1515           0 :   return true;
    1516             : }
    1517             : 
    1518             : #define RESOLVE_CASE(PropType, SpecType, Resolver)                            \
    1519             :   case e##PropType: {                                                         \
    1520             :     MOZ_ASSERT(nativeProperties->Has##PropType##s());                         \
    1521             :     const Prefable<const SpecType>& pref =                                    \
    1522             :       nativeProperties->PropType##s()[propertyInfo.prefIndex];                \
    1523             :     return Resolver(cx, wrapper, obj, id, pref,                               \
    1524             :                     pref.specs[propertyInfo.specIndex], desc, cacheOnHolder); \
    1525             :   }
    1526             : 
    1527             : static bool
    1528         102 : XrayResolveProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
    1529             :                     JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
    1530             :                     JS::MutableHandle<JS::PropertyDescriptor> desc,
    1531             :                     bool& cacheOnHolder, DOMObjectType type,
    1532             :                     const NativeProperties* nativeProperties,
    1533             :                     const PropertyInfo& propertyInfo)
    1534             : {
    1535         102 :   MOZ_ASSERT(type != eGlobalInterfacePrototype);
    1536             : 
    1537             :   // Make sure we resolve for matched object type.
    1538         102 :   switch (propertyInfo.type) {
    1539             :   case eStaticMethod:
    1540             :   case eStaticAttribute:
    1541           0 :     if (type != eInterface) {
    1542           0 :       return true;
    1543             :     }
    1544           0 :     break;
    1545             :   case eMethod:
    1546             :   case eAttribute:
    1547          77 :     if (type != eGlobalInstance && type != eInterfacePrototype) {
    1548           0 :       return true;
    1549             :     }
    1550          77 :     break;
    1551             :   case eUnforgeableMethod:
    1552             :   case eUnforgeableAttribute:
    1553          25 :     if (!IsInstance(type)) {
    1554           0 :       return true;
    1555             :     }
    1556          25 :     break;
    1557             :   case eConstant:
    1558           0 :     if (IsInstance(type)) {
    1559           0 :       return true;
    1560             :     }
    1561           0 :     break;
    1562             :   }
    1563             : 
    1564         102 :   switch (propertyInfo.type) {
    1565           0 :   RESOLVE_CASE(StaticMethod, JSFunctionSpec, XrayResolveMethod)
    1566           0 :   RESOLVE_CASE(StaticAttribute, JSPropertySpec, XrayResolveAttribute)
    1567          16 :   RESOLVE_CASE(Method, JSFunctionSpec, XrayResolveMethod)
    1568          61 :   RESOLVE_CASE(Attribute, JSPropertySpec, XrayResolveAttribute)
    1569           0 :   RESOLVE_CASE(UnforgeableMethod, JSFunctionSpec, XrayResolveMethod)
    1570          25 :   RESOLVE_CASE(UnforgeableAttribute, JSPropertySpec, XrayResolveAttribute)
    1571           0 :   RESOLVE_CASE(Constant, ConstantSpec, XrayResolveConstant)
    1572             :   }
    1573             : 
    1574           0 :   return true;
    1575             : }
    1576             : 
    1577             : #undef RESOLVE_CASE
    1578             : 
    1579             : static bool
    1580           0 : ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle<JSObject*> wrapper,
    1581             :                               JS::Handle<JSObject*> obj,
    1582             :                               size_t protoAndIfaceCacheIndex, unsigned attrs,
    1583             :                               JS::MutableHandle<JS::PropertyDescriptor> desc,
    1584             :                               bool& cacheOnHolder)
    1585             : {
    1586           0 :   JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
    1587             :   {
    1588           0 :     JSAutoCompartment ac(cx, global);
    1589           0 :     ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
    1590             :     // This function is called when resolving the "constructor" and "prototype"
    1591             :     // properties of Xrays for DOM prototypes and constructors respectively.
    1592             :     // This means the relevant Xray exists, which means its _target_ exists.
    1593             :     // And that means we managed to successfullly create the prototype or
    1594             :     // constructor, respectively, and hence must have managed to create the
    1595             :     // thing it's pointing to as well.  So our entry slot must exist.
    1596             :     JSObject* protoOrIface =
    1597           0 :       protoAndIfaceCache.EntrySlotMustExist(protoAndIfaceCacheIndex);
    1598           0 :     MOZ_RELEASE_ASSERT(protoOrIface, "How can this object not exist?");
    1599             : 
    1600           0 :     cacheOnHolder = true;
    1601             : 
    1602           0 :     desc.object().set(wrapper);
    1603           0 :     desc.setAttributes(attrs);
    1604           0 :     desc.setGetter(nullptr);
    1605           0 :     desc.setSetter(nullptr);
    1606           0 :     desc.value().set(JS::ObjectValue(*protoOrIface));
    1607             :   }
    1608           0 :   return JS_WrapPropertyDescriptor(cx, desc);
    1609             : }
    1610             : 
    1611             : #ifdef DEBUG
    1612             : 
    1613             : static void
    1614           0 : DEBUG_CheckXBLCallable(JSContext *cx, JSObject *obj)
    1615             : {
    1616             :     // In general, we shouldn't have cross-compartment wrappers here, because
    1617             :     // we should be running in an XBL scope, and the content prototype should
    1618             :     // contain wrappers to functions defined in the XBL scope. But if the node
    1619             :     // has been adopted into another compartment, those prototypes will now point
    1620             :     // to a different XBL scope (which is ok).
    1621           0 :     MOZ_ASSERT_IF(js::IsCrossCompartmentWrapper(obj),
    1622             :                   xpc::IsContentXBLScope(js::GetObjectCompartment(js::UncheckedUnwrap(obj))));
    1623           0 :     MOZ_ASSERT(JS::IsCallable(obj));
    1624           0 : }
    1625             : 
    1626             : static void
    1627           0 : DEBUG_CheckXBLLookup(JSContext *cx, JS::PropertyDescriptor *desc)
    1628             : {
    1629           0 :     if (!desc->obj)
    1630           0 :         return;
    1631           0 :     if (!desc->value.isUndefined()) {
    1632           0 :         MOZ_ASSERT(desc->value.isObject());
    1633           0 :         DEBUG_CheckXBLCallable(cx, &desc->value.toObject());
    1634             :     }
    1635           0 :     if (desc->getter) {
    1636           0 :         MOZ_ASSERT(desc->attrs & JSPROP_GETTER);
    1637           0 :         DEBUG_CheckXBLCallable(cx, JS_FUNC_TO_DATA_PTR(JSObject *, desc->getter));
    1638             :     }
    1639           0 :     if (desc->setter) {
    1640           0 :         MOZ_ASSERT(desc->attrs & JSPROP_SETTER);
    1641           0 :         DEBUG_CheckXBLCallable(cx, JS_FUNC_TO_DATA_PTR(JSObject *, desc->setter));
    1642             :     }
    1643             : }
    1644             : #else
    1645             : #define DEBUG_CheckXBLLookup(a, b) {}
    1646             : #endif
    1647             : 
    1648             : /* static */ bool
    1649         349 : XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
    1650             :                        JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
    1651             :                        JS::MutableHandle<JS::PropertyDescriptor> desc,
    1652             :                        bool& cacheOnHolder)
    1653             : {
    1654         349 :   cacheOnHolder = false;
    1655             : 
    1656             :   DOMObjectType type;
    1657             :   const NativePropertyHooks *nativePropertyHooks =
    1658         349 :     GetNativePropertyHooks(cx, obj, type);
    1659             :   ResolveOwnProperty resolveOwnProperty =
    1660         349 :     nativePropertyHooks->mResolveOwnProperty;
    1661             : 
    1662         349 :   if (type == eNamedPropertiesObject) {
    1663             :     // None of these should be cached on the holder, since they're dynamic.
    1664           1 :     return resolveOwnProperty(cx, wrapper, obj, id, desc);
    1665             :   }
    1666             : 
    1667             :   const NativePropertiesHolder& nativePropertiesHolder =
    1668         348 :     nativePropertyHooks->mNativeProperties;
    1669         348 :   const NativeProperties* nativeProperties = nullptr;
    1670         348 :   const PropertyInfo* found = nullptr;
    1671             : 
    1672         348 :   if ((nativeProperties = nativePropertiesHolder.regular)) {
    1673         348 :     found = XrayFindOwnPropertyInfo(cx, id, nativeProperties);
    1674             :   }
    1675         584 :   if (!found &&
    1676         530 :       (nativeProperties = nativePropertiesHolder.chromeOnly) &&
    1677         182 :       xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper))) {
    1678         182 :     found = XrayFindOwnPropertyInfo(cx, id, nativeProperties);
    1679             :   }
    1680             : 
    1681         348 :   if (IsInstance(type)) {
    1682             :     // Check for unforgeable properties first to prevent names provided by
    1683             :     // resolveOwnProperty callback from shadowing them.
    1684         231 :     if (found && (found->type == eUnforgeableMethod ||
    1685          72 :                   found->type == eUnforgeableAttribute)) {
    1686          25 :       if (!XrayResolveProperty(cx, wrapper, obj, id, desc, cacheOnHolder, type,
    1687             :                                nativeProperties, *found)) {
    1688         134 :         return false;
    1689             :       }
    1690             : 
    1691          25 :       if (desc.object()) {
    1692          25 :         return true;
    1693             :       }
    1694             :     }
    1695             : 
    1696         134 :     if (resolveOwnProperty) {
    1697          89 :       if (!resolveOwnProperty(cx, wrapper, obj, id, desc)) {
    1698           0 :         return false;
    1699             :       }
    1700             : 
    1701          89 :       if (desc.object()) {
    1702             :         // None of these should be cached on the holder, since they're dynamic.
    1703           6 :         return true;
    1704             :       }
    1705             :     }
    1706             : 
    1707             :     // If we're a special scope for in-content XBL, our script expects to see
    1708             :     // the bound XBL methods and attributes when accessing content. However,
    1709             :     // these members are implemented in content via custom-spliced prototypes,
    1710             :     // and thus aren't visible through Xray wrappers unless we handle them
    1711             :     // explicitly. So we check if we're running in such a scope, and if so,
    1712             :     // whether the wrappee is a bound element. If it is, we do a lookup via
    1713             :     // specialized XBL machinery.
    1714             :     //
    1715             :     // While we have to do some sketchy walking through content land, we should
    1716             :     // be protected by read-only/non-configurable properties, and any functions
    1717             :     // we end up with should _always_ be living in our own scope (the XBL scope).
    1718             :     // Make sure to assert that.
    1719         153 :     JS::Rooted<JSObject*> maybeElement(cx, obj);
    1720             :     Element* element;
    1721         384 :     if (xpc::ObjectScope(wrapper)->IsContentXBLScope() &&
    1722         128 :         NS_SUCCEEDED(UNWRAP_OBJECT(Element, &maybeElement, element))) {
    1723           0 :       if (!nsContentUtils::LookupBindingMember(cx, element, id, desc)) {
    1724           0 :         return false;
    1725             :       }
    1726             : 
    1727           0 :       DEBUG_CheckXBLLookup(cx, desc.address());
    1728             : 
    1729           0 :       if (desc.object()) {
    1730             :         // XBL properties shouldn't be cached on the holder, as they might be
    1731             :         // shadowed by own properties returned from mResolveOwnProperty.
    1732           0 :         desc.object().set(wrapper);
    1733             : 
    1734           0 :         return true;
    1735             :       }
    1736             :     }
    1737             : 
    1738             :     // For non-global instance Xrays there are no other properties, so return
    1739             :     // here for them.
    1740         128 :     if (type != eGlobalInstance) {
    1741         103 :       return true;
    1742             :     }
    1743         189 :   } else if (type == eInterface) {
    1744           0 :     if (IdEquals(id, "prototype")) {
    1745           0 :       return nativePropertyHooks->mPrototypeID == prototypes::id::_ID_Count ||
    1746           0 :              ResolvePrototypeOrConstructor(cx, wrapper, obj,
    1747           0 :                                            nativePropertyHooks->mPrototypeID,
    1748             :                                            JSPROP_PERMANENT | JSPROP_READONLY,
    1749           0 :                                            desc, cacheOnHolder);
    1750             :     }
    1751             : 
    1752           0 :     if (id == SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::hasInstance)) &&
    1753           0 :         DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj))->
    1754           0 :           wantsInterfaceHasInstance) {
    1755           0 :       cacheOnHolder = true;
    1756             :       JSNativeWrapper interfaceHasInstanceWrapper = { InterfaceHasInstance,
    1757           0 :                                                       nullptr };
    1758           0 :       JSObject* funObj = XrayCreateFunction(cx, wrapper,
    1759           0 :                                             interfaceHasInstanceWrapper, 1, id);
    1760           0 :       if (!funObj) {
    1761           0 :         return false;
    1762             :       }
    1763             : 
    1764           0 :       desc.value().setObject(*funObj);
    1765           0 :       desc.setAttributes(JSPROP_READONLY | JSPROP_PERMANENT);
    1766           0 :       desc.object().set(wrapper);
    1767           0 :       desc.setSetter(nullptr);
    1768           0 :       desc.setGetter(nullptr);
    1769           0 :       return true;
    1770             :     }
    1771             :   } else {
    1772         189 :     MOZ_ASSERT(IsInterfacePrototype(type));
    1773             : 
    1774         189 :     if (IdEquals(id, "constructor")) {
    1775           0 :       return nativePropertyHooks->mConstructorID == constructors::id::_ID_Count ||
    1776           0 :              ResolvePrototypeOrConstructor(cx, wrapper, obj,
    1777           0 :                                            nativePropertyHooks->mConstructorID,
    1778           0 :                                            0, desc, cacheOnHolder);
    1779             :     }
    1780             : 
    1781             :     // The properties for globals live on the instance, so return here as there
    1782             :     // are no properties on their interface prototype object.
    1783         189 :     if (type == eGlobalInterfacePrototype) {
    1784           1 :       return true;
    1785             :     }
    1786             :   }
    1787             : 
    1788         290 :   if (found &&
    1789          77 :       !XrayResolveProperty(cx, wrapper, obj, id, desc, cacheOnHolder, type,
    1790             :                            nativeProperties, *found)) {
    1791           0 :     return false;
    1792             :   }
    1793             : 
    1794         213 :   return true;
    1795             : }
    1796             : 
    1797             : bool
    1798           0 : XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
    1799             :                    JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
    1800             :                    JS::Handle<JS::PropertyDescriptor> desc,
    1801             :                    JS::ObjectOpResult &result, bool *defined)
    1802             : {
    1803           0 :   if (!js::IsProxy(obj))
    1804           0 :     return true;
    1805             : 
    1806           0 :   const DOMProxyHandler* handler = GetDOMProxyHandler(obj);
    1807           0 :   return handler->defineProperty(cx, wrapper, id, desc, result, defined);
    1808             : }
    1809             : 
    1810             : template<typename SpecType>
    1811             : bool
    1812           0 : XrayAppendPropertyKeys(JSContext* cx, JS::Handle<JSObject*> obj,
    1813             :                        const Prefable<const SpecType>* pref,
    1814             :                        const PropertyInfo* infos, unsigned flags,
    1815             :                        JS::AutoIdVector& props)
    1816             : {
    1817             :   do {
    1818           0 :     bool prefIsEnabled = pref->isEnabled(cx, obj);
    1819           0 :     if (prefIsEnabled) {
    1820           0 :       const SpecType* spec = pref->specs;
    1821           0 :       do {
    1822           0 :         const jsid& id = infos++->id;
    1823           0 :         if (((flags & JSITER_HIDDEN) ||
    1824           0 :              (spec->flags & JSPROP_ENUMERATE)) &&
    1825           0 :             ((flags & JSITER_SYMBOLS) || !JSID_IS_SYMBOL(id)) &&
    1826           0 :             !props.append(id)) {
    1827           0 :           return false;
    1828             :         }
    1829           0 :       } while ((++spec)->name);
    1830             :     }
    1831             :     // Break if we have reached the end of pref.
    1832           0 :     if (!(++pref)->specs) {
    1833           0 :       break;
    1834             :     }
    1835             :     // Advance infos if the previous pref is disabled. The -1 is required
    1836             :     // because there is an end-of-list terminator between pref->specs and
    1837             :     // (pref - 1)->specs.
    1838           0 :     if (!prefIsEnabled) {
    1839           0 :       infos += pref->specs - (pref - 1)->specs - 1;
    1840           0 :     }
    1841             :   } while (1);
    1842             : 
    1843           0 :   return true;
    1844             : }
    1845             : 
    1846             : template<>
    1847             : bool
    1848           0 : XrayAppendPropertyKeys<ConstantSpec>(JSContext* cx, JS::Handle<JSObject*> obj,
    1849             :                                      const Prefable<const ConstantSpec>* pref,
    1850             :                                      const PropertyInfo* infos, unsigned flags,
    1851             :                                      JS::AutoIdVector& props)
    1852             : {
    1853             :   do {
    1854           0 :     bool prefIsEnabled = pref->isEnabled(cx, obj);
    1855           0 :     if (prefIsEnabled) {
    1856           0 :       const ConstantSpec* spec = pref->specs;
    1857           0 :       do {
    1858           0 :         if (!props.append(infos++->id)) {
    1859           0 :           return false;
    1860             :         }
    1861           0 :       } while ((++spec)->name);
    1862             :     }
    1863             :     // Break if we have reached the end of pref.
    1864           0 :     if (!(++pref)->specs) {
    1865           0 :       break;
    1866             :     }
    1867             :     // Advance infos if the previous pref is disabled. The -1 is required
    1868             :     // because there is an end-of-list terminator between pref->specs and
    1869             :     // (pref - 1)->specs.
    1870           0 :     if (!prefIsEnabled) {
    1871           0 :       infos += pref->specs - (pref - 1)->specs - 1;
    1872           0 :     }
    1873             :   } while (1);
    1874             : 
    1875           0 :   return true;
    1876             : }
    1877             : 
    1878             : #define ADD_KEYS_IF_DEFINED(FieldName) {                                        \
    1879             :   if (nativeProperties->Has##FieldName##s() &&                                  \
    1880             :       !XrayAppendPropertyKeys(cx, obj,                                          \
    1881             :                               nativeProperties->FieldName##s(),                 \
    1882             :                               nativeProperties->FieldName##PropertyInfos(),     \
    1883             :                               flags, props)) {                                  \
    1884             :     return false;                                                               \
    1885             :   }                                                                             \
    1886             : }
    1887             : 
    1888             : bool
    1889           0 : XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
    1890             :                     JS::Handle<JSObject*> obj,
    1891             :                     unsigned flags, JS::AutoIdVector& props,
    1892             :                     DOMObjectType type,
    1893             :                     const NativeProperties* nativeProperties)
    1894             : {
    1895           0 :   MOZ_ASSERT(type != eNamedPropertiesObject);
    1896             : 
    1897           0 :   if (IsInstance(type)) {
    1898           0 :     ADD_KEYS_IF_DEFINED(UnforgeableMethod);
    1899           0 :     ADD_KEYS_IF_DEFINED(UnforgeableAttribute);
    1900           0 :     if (type == eGlobalInstance) {
    1901           0 :       ADD_KEYS_IF_DEFINED(Method);
    1902           0 :       ADD_KEYS_IF_DEFINED(Attribute);
    1903             :     }
    1904             :   } else {
    1905           0 :     MOZ_ASSERT(type != eGlobalInterfacePrototype);
    1906           0 :     if (type == eInterface) {
    1907           0 :       ADD_KEYS_IF_DEFINED(StaticMethod);
    1908           0 :       ADD_KEYS_IF_DEFINED(StaticAttribute);
    1909             :     } else {
    1910           0 :       MOZ_ASSERT(type == eInterfacePrototype);
    1911           0 :       ADD_KEYS_IF_DEFINED(Method);
    1912           0 :       ADD_KEYS_IF_DEFINED(Attribute);
    1913             :     }
    1914           0 :     ADD_KEYS_IF_DEFINED(Constant);
    1915             :   }
    1916             : 
    1917           0 :   return true;
    1918             : }
    1919             : 
    1920             : #undef ADD_KEYS_IF_DEFINED
    1921             : 
    1922             : bool
    1923           0 : XrayOwnNativePropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
    1924             :                           const NativePropertyHooks* nativePropertyHooks,
    1925             :                           DOMObjectType type, JS::Handle<JSObject*> obj,
    1926             :                           unsigned flags, JS::AutoIdVector& props)
    1927             : {
    1928           0 :   MOZ_ASSERT(type != eNamedPropertiesObject);
    1929             : 
    1930           0 :   if (type == eInterface &&
    1931           0 :       nativePropertyHooks->mPrototypeID != prototypes::id::_ID_Count &&
    1932           0 :       !AddStringToIDVector(cx, props, "prototype")) {
    1933           0 :     return false;
    1934             :   }
    1935             : 
    1936           0 :   if (IsInterfacePrototype(type) &&
    1937           0 :       nativePropertyHooks->mConstructorID != constructors::id::_ID_Count &&
    1938           0 :       (flags & JSITER_HIDDEN) &&
    1939           0 :       !AddStringToIDVector(cx, props, "constructor")) {
    1940           0 :     return false;
    1941             :   }
    1942             : 
    1943             :   const NativePropertiesHolder& nativeProperties =
    1944           0 :     nativePropertyHooks->mNativeProperties;
    1945             : 
    1946           0 :   if (nativeProperties.regular &&
    1947           0 :       !XrayOwnPropertyKeys(cx, wrapper, obj, flags, props, type,
    1948           0 :                            nativeProperties.regular)) {
    1949           0 :     return false;
    1950             :   }
    1951             : 
    1952           0 :   if (nativeProperties.chromeOnly &&
    1953           0 :       xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
    1954           0 :       !XrayOwnPropertyKeys(cx, wrapper, obj, flags, props, type,
    1955           0 :                            nativeProperties.chromeOnly)) {
    1956           0 :     return false;
    1957             :   }
    1958             : 
    1959           0 :   return true;
    1960             : }
    1961             : 
    1962             : bool
    1963           0 : XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
    1964             :                     JS::Handle<JSObject*> obj,
    1965             :                     unsigned flags, JS::AutoIdVector& props)
    1966             : {
    1967             :   DOMObjectType type;
    1968             :   const NativePropertyHooks* nativePropertyHooks =
    1969           0 :     GetNativePropertyHooks(cx, obj, type);
    1970             :   EnumerateOwnProperties enumerateOwnProperties =
    1971           0 :     nativePropertyHooks->mEnumerateOwnProperties;
    1972             : 
    1973           0 :   if (type == eNamedPropertiesObject) {
    1974           0 :     return enumerateOwnProperties(cx, wrapper, obj, props);
    1975             :   }
    1976             : 
    1977           0 :   if (IsInstance(type)) {
    1978             :     // FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=1071189
    1979             :     //       Should do something about XBL properties too.
    1980           0 :     if (enumerateOwnProperties &&
    1981           0 :         !enumerateOwnProperties(cx, wrapper, obj, props)) {
    1982           0 :       return false;
    1983             :     }
    1984             :   }
    1985             : 
    1986           0 :   return type == eGlobalInterfacePrototype ||
    1987           0 :          XrayOwnNativePropertyKeys(cx, wrapper, nativePropertyHooks, type,
    1988           0 :                                    obj, flags, props);
    1989             : }
    1990             : 
    1991             : const JSClass*
    1992           0 : XrayGetExpandoClass(JSContext* cx, JS::Handle<JSObject*> obj)
    1993             : {
    1994             :   DOMObjectType type;
    1995             :   const NativePropertyHooks* nativePropertyHooks =
    1996           0 :     GetNativePropertyHooks(cx, obj, type);
    1997           0 :   if (!IsInstance(type)) {
    1998             :     // Non-instances don't need any special expando classes.
    1999           0 :     return &DefaultXrayExpandoObjectClass;
    2000             :   }
    2001             : 
    2002           0 :   return nativePropertyHooks->mXrayExpandoClass;
    2003             : }
    2004             : 
    2005             : bool
    2006           0 : XrayDeleteNamedProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
    2007             :                         JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
    2008             :                         JS::ObjectOpResult& opresult)
    2009             : {
    2010             :   DOMObjectType type;
    2011             :   const NativePropertyHooks* nativePropertyHooks =
    2012           0 :     GetNativePropertyHooks(cx, obj, type);
    2013           0 :   if (!IsInstance(type) || !nativePropertyHooks->mDeleteNamedProperty) {
    2014           0 :     return opresult.succeed();
    2015             :   }
    2016           0 :   return nativePropertyHooks->mDeleteNamedProperty(cx, wrapper, obj, id,
    2017           0 :                                                    opresult);
    2018             : }
    2019             : 
    2020             : JSObject*
    2021           0 : GetCachedSlotStorageObjectSlow(JSContext* cx, JS::Handle<JSObject*> obj,
    2022             :                                bool* isXray)
    2023             : {
    2024           0 :   if (!xpc::WrapperFactory::IsXrayWrapper(obj)) {
    2025           0 :     JSObject* retval = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
    2026           0 :     MOZ_ASSERT(IsDOMObject(retval));
    2027           0 :     *isXray = false;
    2028           0 :     return retval;
    2029             :   }
    2030             : 
    2031           0 :   *isXray = true;
    2032           0 :   return xpc::EnsureXrayExpandoObject(cx, obj);;
    2033             : }
    2034             : 
    2035             : DEFINE_XRAY_EXPANDO_CLASS(, DefaultXrayExpandoObjectClass, 0);
    2036             : 
    2037             : NativePropertyHooks sEmptyNativePropertyHooks = {
    2038             :   nullptr,
    2039             :   nullptr,
    2040             :   nullptr,
    2041             :   {
    2042             :     nullptr,
    2043             :     nullptr
    2044             :   },
    2045             :   prototypes::id::_ID_Count,
    2046             :   constructors::id::_ID_Count,
    2047             :   nullptr
    2048             : };
    2049             : 
    2050             : const js::ClassOps sBoringInterfaceObjectClassClassOps = {
    2051             :     nullptr,               /* addProperty */
    2052             :     nullptr,               /* delProperty */
    2053             :     nullptr,               /* getProperty */
    2054             :     nullptr,               /* setProperty */
    2055             :     nullptr,               /* enumerate */
    2056             :     nullptr,               /* newEnumerate */
    2057             :     nullptr,               /* resolve */
    2058             :     nullptr,               /* mayResolve */
    2059             :     nullptr,               /* finalize */
    2060             :     ThrowingConstructor,   /* call */
    2061             :     nullptr,               /* hasInstance */
    2062             :     ThrowingConstructor,   /* construct */
    2063             :     nullptr,               /* trace */
    2064             : };
    2065             : 
    2066             : const js::ObjectOps sInterfaceObjectClassObjectOps = {
    2067             :   nullptr, /* lookupProperty */
    2068             :   nullptr, /* defineProperty */
    2069             :   nullptr, /* hasProperty */
    2070             :   nullptr, /* getProperty */
    2071             :   nullptr, /* setProperty */
    2072             :   nullptr, /* getOwnPropertyDescriptor */
    2073             :   nullptr, /* deleteProperty */
    2074             :   nullptr, /* watch */
    2075             :   nullptr, /* unwatch */
    2076             :   nullptr, /* getElements */
    2077             :   InterfaceObjectToString, /* funToString */
    2078             : };
    2079             : 
    2080             : bool
    2081          65 : GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
    2082             :                        JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
    2083             :                        bool* found, JS::MutableHandle<JS::Value> vp)
    2084             : {
    2085         130 :   JS::Rooted<JSObject*> proto(cx);
    2086          65 :   if (!js::GetObjectProto(cx, proxy, &proto)) {
    2087           0 :     return false;
    2088             :   }
    2089          65 :   if (!proto) {
    2090           0 :     *found = false;
    2091           0 :     return true;
    2092             :   }
    2093             : 
    2094          65 :   if (!JS_HasPropertyById(cx, proto, id, found)) {
    2095           0 :     return false;
    2096             :   }
    2097             : 
    2098          65 :   if (!*found) {
    2099           1 :     return true;
    2100             :   }
    2101             : 
    2102          64 :   return JS_ForwardGetPropertyTo(cx, proto, id, receiver, vp);
    2103             : }
    2104             : 
    2105             : bool
    2106         476 : HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
    2107             :                        JS::Handle<jsid> id, bool* has)
    2108             : {
    2109         952 :   JS::Rooted<JSObject*> proto(cx);
    2110         476 :   if (!js::GetObjectProto(cx, proxy, &proto)) {
    2111           0 :     return false;
    2112             :   }
    2113         476 :   if (!proto) {
    2114           0 :     *has = false;
    2115           0 :     return true;
    2116             :   }
    2117             : 
    2118         476 :   return JS_HasPropertyById(cx, proto, id, has);
    2119             : }
    2120             : 
    2121             : bool
    2122           0 : AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
    2123             :                        nsTArray<nsString>& names,
    2124             :                        bool shadowPrototypeProperties,
    2125             :                        JS::AutoIdVector& props)
    2126             : {
    2127           0 :   for (uint32_t i = 0; i < names.Length(); ++i) {
    2128           0 :     JS::Rooted<JS::Value> v(cx);
    2129           0 :     if (!xpc::NonVoidStringToJsval(cx, names[i], &v)) {
    2130           0 :       return false;
    2131             :     }
    2132             : 
    2133           0 :     JS::Rooted<jsid> id(cx);
    2134           0 :     if (!JS_ValueToId(cx, v, &id)) {
    2135           0 :       return false;
    2136             :     }
    2137             : 
    2138           0 :     bool shouldAppend = shadowPrototypeProperties;
    2139           0 :     if (!shouldAppend) {
    2140             :       bool has;
    2141           0 :       if (!HasPropertyOnPrototype(cx, proxy, id, &has)) {
    2142           0 :         return false;
    2143             :       }
    2144           0 :       shouldAppend = !has;
    2145             :     }
    2146             : 
    2147           0 :     if (shouldAppend) {
    2148           0 :       if (!props.append(id)) {
    2149           0 :         return false;
    2150             :       }
    2151             :     }
    2152             :   }
    2153             : 
    2154           0 :   return true;
    2155             : }
    2156             : 
    2157             : bool
    2158           1 : DictionaryBase::ParseJSON(JSContext* aCx,
    2159             :                           const nsAString& aJSON,
    2160             :                           JS::MutableHandle<JS::Value> aVal)
    2161             : {
    2162           1 :   if (aJSON.IsEmpty()) {
    2163           0 :     return true;
    2164             :   }
    2165           1 :   return JS_ParseJSON(aCx, PromiseFlatString(aJSON).get(), aJSON.Length(), aVal);
    2166             : }
    2167             : 
    2168             : bool
    2169           0 : DictionaryBase::StringifyToJSON(JSContext* aCx,
    2170             :                                 JS::Handle<JSObject*> aObj,
    2171             :                                 nsAString& aJSON) const
    2172             : {
    2173           0 :   return JS::ToJSONMaybeSafely(aCx, aObj, AppendJSONToString, &aJSON);
    2174             : }
    2175             : 
    2176             : /* static */
    2177             : bool
    2178           0 : DictionaryBase::AppendJSONToString(const char16_t* aJSONData,
    2179             :                                    uint32_t aDataLength,
    2180             :                                    void* aString)
    2181             : {
    2182           0 :   nsAString* string = static_cast<nsAString*>(aString);
    2183           0 :   string->Append(aJSONData, aDataLength);
    2184           0 :   return true;
    2185             : }
    2186             : 
    2187             : nsresult
    2188           0 : ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg)
    2189             : {
    2190           0 :   js::AssertSameCompartment(aCx, aObjArg);
    2191             : 
    2192             :   // Check if we're anywhere near the stack limit before we reach the
    2193             :   // transplanting code, since it has no good way to handle errors. This uses
    2194             :   // the untrusted script limit, which is not strictly necessary since no
    2195             :   // actual script should run.
    2196           0 :   if (!js::CheckRecursionLimitConservative(aCx)) {
    2197           0 :     return NS_ERROR_FAILURE;
    2198             :   }
    2199             : 
    2200           0 :   JS::Rooted<JSObject*> aObj(aCx, aObjArg);
    2201           0 :   const DOMJSClass* domClass = GetDOMClass(aObj);
    2202             : 
    2203             :   // DOM things are always parented to globals.
    2204             :   JS::Rooted<JSObject*> oldParent(aCx,
    2205           0 :                                   js::GetGlobalForObjectCrossCompartment(aObj));
    2206           0 :   MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(oldParent) == oldParent);
    2207             : 
    2208             :   JS::Rooted<JSObject*> newParent(aCx,
    2209           0 :                                   domClass->mGetAssociatedGlobal(aCx, aObj));
    2210           0 :   MOZ_ASSERT(JS_IsGlobalObject(newParent));
    2211             : 
    2212           0 :   JSAutoCompartment oldAc(aCx, oldParent);
    2213             : 
    2214           0 :   JSCompartment* oldCompartment = js::GetObjectCompartment(oldParent);
    2215           0 :   JSCompartment* newCompartment = js::GetObjectCompartment(newParent);
    2216           0 :   if (oldCompartment == newCompartment) {
    2217           0 :     MOZ_ASSERT(oldParent == newParent);
    2218           0 :     return NS_OK;
    2219             :   }
    2220             : 
    2221           0 :   nsISupports* native = UnwrapDOMObjectToISupports(aObj);
    2222           0 :   if (!native) {
    2223           0 :     return NS_OK;
    2224             :   }
    2225             : 
    2226           0 :   bool isProxy = js::IsProxy(aObj);
    2227           0 :   JS::Rooted<JSObject*> expandoObject(aCx);
    2228           0 :   if (isProxy) {
    2229           0 :     expandoObject = DOMProxyHandler::GetAndClearExpandoObject(aObj);
    2230             :   }
    2231             : 
    2232           0 :   JSAutoCompartment newAc(aCx, newParent);
    2233             : 
    2234             :   // First we clone the reflector. We get a copy of its properties and clone its
    2235             :   // expando chain.
    2236             : 
    2237           0 :   JS::Handle<JSObject*> proto = (domClass->mGetProto)(aCx);
    2238           0 :   if (!proto) {
    2239           0 :     return NS_ERROR_FAILURE;
    2240             :   }
    2241             : 
    2242           0 :   JS::Rooted<JSObject*> newobj(aCx, JS_CloneObject(aCx, aObj, proto));
    2243           0 :   if (!newobj) {
    2244           0 :     return NS_ERROR_FAILURE;
    2245             :   }
    2246             : 
    2247           0 :   JS::Rooted<JSObject*> propertyHolder(aCx);
    2248           0 :   JS::Rooted<JSObject*> copyFrom(aCx, isProxy ? expandoObject : aObj);
    2249           0 :   if (copyFrom) {
    2250           0 :     propertyHolder = JS_NewObjectWithGivenProto(aCx, nullptr, nullptr);
    2251           0 :     if (!propertyHolder) {
    2252           0 :       return NS_ERROR_OUT_OF_MEMORY;
    2253             :     }
    2254             : 
    2255           0 :     if (!JS_CopyPropertiesFrom(aCx, propertyHolder, copyFrom)) {
    2256           0 :       return NS_ERROR_FAILURE;
    2257             :     }
    2258             :   } else {
    2259           0 :     propertyHolder = nullptr;
    2260             :   }
    2261             : 
    2262             :   // Expandos from other compartments are attached to the target JS object.
    2263             :   // Copy them over, and let the old ones die a natural death.
    2264             : 
    2265             :   // Note that at this point the DOM_OBJECT_SLOT for |newobj| has not been set.
    2266             :   // CloneExpandoChain() will use this property of |newobj| when it calls
    2267             :   // preserveWrapper() via attachExpandoObject() if |aObj| has expandos set, and
    2268             :   // preserveWrapper() will not do anything in this case.  This is safe because
    2269             :   // if expandos are present then the wrapper will already have been preserved
    2270             :   // for this native.
    2271           0 :   if (!xpc::XrayUtils::CloneExpandoChain(aCx, newobj, aObj)) {
    2272           0 :     return NS_ERROR_FAILURE;
    2273             :   }
    2274             : 
    2275             :   // We've set up |newobj|, so we make it own the native by setting its reserved
    2276             :   // slot and nulling out the reserved slot of |obj|.
    2277             :   //
    2278             :   // NB: It's important to do this _after_ copying the properties to
    2279             :   // propertyHolder. Otherwise, an object with |foo.x === foo| will
    2280             :   // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
    2281           0 :   js::SetReservedSlot(newobj, DOM_OBJECT_SLOT,
    2282           0 :                       js::GetReservedSlot(aObj, DOM_OBJECT_SLOT));
    2283           0 :   js::SetReservedSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
    2284             : 
    2285           0 :   aObj = xpc::TransplantObject(aCx, aObj, newobj);
    2286           0 :   if (!aObj) {
    2287           0 :     MOZ_CRASH();
    2288             :   }
    2289             : 
    2290           0 :   nsWrapperCache* cache = nullptr;
    2291           0 :   CallQueryInterface(native, &cache);
    2292           0 :   bool preserving = cache->PreservingWrapper();
    2293           0 :   cache->SetPreservingWrapper(false);
    2294           0 :   cache->SetWrapper(aObj);
    2295           0 :   cache->SetPreservingWrapper(preserving);
    2296             : 
    2297           0 :   if (propertyHolder) {
    2298           0 :     JS::Rooted<JSObject*> copyTo(aCx);
    2299           0 :     if (isProxy) {
    2300           0 :       copyTo = DOMProxyHandler::EnsureExpandoObject(aCx, aObj);
    2301             :     } else {
    2302           0 :       copyTo = aObj;
    2303             :     }
    2304             : 
    2305           0 :     if (!copyTo || !JS_CopyPropertiesFrom(aCx, copyTo, propertyHolder)) {
    2306           0 :       MOZ_CRASH();
    2307             :     }
    2308             :   }
    2309             : 
    2310           0 :   JS::Rooted<JSObject*> maybeObjLC(aCx, aObj);
    2311             :   nsObjectLoadingContent* htmlobject;
    2312           0 :   nsresult rv = UNWRAP_OBJECT(HTMLObjectElement, &maybeObjLC, htmlobject);
    2313           0 :   if (NS_FAILED(rv)) {
    2314             :     rv = UnwrapObject<prototypes::id::HTMLEmbedElement,
    2315           0 :                       HTMLSharedObjectElement>(&maybeObjLC, htmlobject);
    2316           0 :     if (NS_FAILED(rv)) {
    2317             :       rv = UnwrapObject<prototypes::id::HTMLAppletElement,
    2318           0 :                         HTMLSharedObjectElement>(&maybeObjLC, htmlobject);
    2319           0 :       if (NS_FAILED(rv)) {
    2320           0 :         htmlobject = nullptr;
    2321             :       }
    2322             :     }
    2323             :   }
    2324           0 :   if (htmlobject) {
    2325           0 :     htmlobject->SetupProtoChain(aCx, aObj);
    2326             :   }
    2327             : 
    2328             :   // Now we can just return the wrapper
    2329           0 :   return NS_OK;
    2330             : }
    2331             : 
    2332          19 : GlobalObject::GlobalObject(JSContext* aCx, JSObject* aObject)
    2333             :   : mGlobalJSObject(aCx),
    2334             :     mCx(aCx),
    2335          19 :     mGlobalObject(nullptr)
    2336             : {
    2337          19 :   MOZ_ASSERT(mCx);
    2338          38 :   JS::Rooted<JSObject*> obj(aCx, aObject);
    2339          19 :   if (js::IsWrapper(obj)) {
    2340           1 :     obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
    2341           1 :     if (!obj) {
    2342             :       // We should never end up here on a worker thread, since there shouldn't
    2343             :       // be any security wrappers to worry about.
    2344           0 :       if (!MOZ_LIKELY(NS_IsMainThread())) {
    2345           0 :         MOZ_CRASH();
    2346             :       }
    2347             : 
    2348           0 :       Throw(aCx, NS_ERROR_XPC_SECURITY_MANAGER_VETO);
    2349           0 :       return;
    2350             :     }
    2351             :   }
    2352             : 
    2353          19 :   mGlobalJSObject = js::GetGlobalForObjectCrossCompartment(obj);
    2354             : }
    2355             : 
    2356             : nsISupports*
    2357          16 : GlobalObject::GetAsSupports() const
    2358             : {
    2359          16 :   if (mGlobalObject) {
    2360           1 :     return mGlobalObject;
    2361             :   }
    2362             : 
    2363          15 :   MOZ_ASSERT(!js::IsWrapper(mGlobalJSObject));
    2364             : 
    2365             :   // Most of our globals are DOM objects.  Try that first.  Note that this
    2366             :   // assumes that either the first nsISupports in the object is the canonical
    2367             :   // one or that we don't care about the canonical nsISupports here.
    2368          15 :   mGlobalObject = UnwrapDOMObjectToISupports(mGlobalJSObject);
    2369          15 :   if (mGlobalObject) {
    2370          11 :     return mGlobalObject;
    2371             :   }
    2372             : 
    2373           4 :   MOZ_ASSERT(NS_IsMainThread(), "All our worker globals are DOM objects");
    2374             : 
    2375             :   // Remove everything below here once all our global objects are using new
    2376             :   // bindings.  If that ever happens; it would need to include Sandbox and
    2377             :   // BackstagePass.
    2378             : 
    2379             :   // See whether mGlobalJSObject is an XPCWrappedNative.  This will redo the
    2380             :   // IsWrapper bit above and the UnwrapDOMObjectToISupports in the case when
    2381             :   // we're not actually an XPCWrappedNative, but this should be a rare-ish case
    2382             :   // anyway.
    2383           8 :   nsCOMPtr<nsISupports> supp = xpc::UnwrapReflectorToISupports(mGlobalJSObject);
    2384           4 :   if (supp) {
    2385             :     // See documentation for mGlobalJSObject for why this assignment is OK.
    2386           4 :     mGlobalObject = supp;
    2387           4 :     return mGlobalObject;
    2388             :   }
    2389             : 
    2390             :   // And now a final hack.  Sandbox is not a reflector, but it does have an
    2391             :   // nsIGlobalObject hanging out in its private slot.  Handle that case here,
    2392             :   // (though again, this will do the useless UnwrapDOMObjectToISupports if we
    2393             :   // got here for something that is somehow not a DOM object, not an
    2394             :   // XPCWrappedNative _and_ not a Sandbox).
    2395           0 :   if (XPCConvert::GetISupportsFromJSObject(mGlobalJSObject, &mGlobalObject)) {
    2396           0 :     return mGlobalObject;
    2397             :   }
    2398             : 
    2399           0 :   MOZ_ASSERT(!mGlobalObject);
    2400             : 
    2401           0 :   Throw(mCx, NS_ERROR_XPC_BAD_CONVERT_JS);
    2402           0 :   return nullptr;
    2403             : }
    2404             : 
    2405             : nsIPrincipal*
    2406           0 : GlobalObject::GetSubjectPrincipal() const
    2407             : {
    2408           0 :   if (!NS_IsMainThread()) {
    2409           0 :     return nullptr;
    2410             :   }
    2411             : 
    2412           0 :   JSCompartment* compartment = js::GetContextCompartment(mCx);
    2413           0 :   MOZ_ASSERT(compartment);
    2414           0 :   JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment);
    2415           0 :   return nsJSPrincipals::get(principals);
    2416             : }
    2417             : 
    2418             : CallerType
    2419           0 : GlobalObject::CallerType() const
    2420             : {
    2421           0 :   return nsContentUtils::ThreadsafeIsSystemCaller(mCx) ?
    2422           0 :     dom::CallerType::System : dom::CallerType::NonSystem;
    2423             : }
    2424             : 
    2425             : static bool
    2426           2 : CallOrdinaryHasInstance(JSContext* cx, JS::CallArgs& args)
    2427             : {
    2428           4 :     JS::Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
    2429             :     bool isInstance;
    2430           2 :     if (!JS::OrdinaryHasInstance(cx, thisObj, args.get(0), &isInstance)) {
    2431           0 :       return false;
    2432             :     }
    2433           2 :     args.rval().setBoolean(isInstance);
    2434           2 :     return true;
    2435             : }
    2436             : 
    2437             : bool
    2438           5 : InterfaceHasInstance(JSContext* cx, unsigned argc, JS::Value* vp)
    2439             : {
    2440           5 :   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    2441             :   // If the thing we were passed is not an object, return false like
    2442             :   // OrdinaryHasInstance does.
    2443           5 :   if (!args.get(0).isObject()) {
    2444           0 :     args.rval().setBoolean(false);
    2445           0 :     return true;
    2446             :   }
    2447             : 
    2448             :   // If "this" is not an object, likewise return false (again, like
    2449             :   // OrdinaryHasInstance).
    2450           5 :   if (!args.thisv().isObject()) {
    2451           0 :     args.rval().setBoolean(false);
    2452           0 :     return true;
    2453             :   }
    2454             : 
    2455             :   // If "this" doesn't have a DOMIfaceAndProtoJSClass, it's not a DOM
    2456             :   // constructor, so just fall back to OrdinaryHasInstance.  But note that we
    2457             :   // should CheckedUnwrap here, because otherwise we won't get the right
    2458             :   // answers.
    2459          10 :   JS::Rooted<JSObject*> thisObj(cx, js::CheckedUnwrap(&args.thisv().toObject()));
    2460           5 :   if (!thisObj) {
    2461             :     // Just fall back on the normal thing, in case it still happens to work.
    2462           0 :     return CallOrdinaryHasInstance(cx, args);
    2463             :   }
    2464             : 
    2465           5 :   const js::Class* thisClass = js::GetObjectClass(thisObj);
    2466             : 
    2467           5 :   if (!IsDOMIfaceAndProtoClass(thisClass)) {
    2468           0 :     return CallOrdinaryHasInstance(cx, args);
    2469             :   }
    2470             : 
    2471             :   const DOMIfaceAndProtoJSClass* clasp =
    2472           5 :     DOMIfaceAndProtoJSClass::FromJSClass(thisClass);
    2473             : 
    2474             :   // If "this" isn't a DOM constructor or is a constructor for an interface
    2475             :   // without a prototype, just fall back to OrdinaryHasInstance.
    2476          10 :   if (clasp->mType != eInterface ||
    2477           5 :       clasp->mPrototypeID == prototypes::id::_ID_Count) {
    2478           0 :     return CallOrdinaryHasInstance(cx, args);
    2479             :   }
    2480             : 
    2481          10 :   JS::Rooted<JSObject*> instance(cx, &args[0].toObject());
    2482             :   const DOMJSClass* domClass =
    2483           5 :     GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
    2484             : 
    2485           9 :   if (domClass &&
    2486           4 :       domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
    2487           3 :     args.rval().setBoolean(true);
    2488           3 :     return true;
    2489             :   }
    2490             : 
    2491           2 :   if (jsipc::IsWrappedCPOW(instance)) {
    2492           0 :     bool boolp = false;
    2493           0 :     if (!jsipc::DOMInstanceOf(cx, js::UncheckedUnwrap(instance), clasp->mPrototypeID,
    2494           0 :                               clasp->mDepth, &boolp)) {
    2495           0 :       return false;
    2496             :     }
    2497           0 :     args.rval().setBoolean(boolp);
    2498           0 :     return true;
    2499             :   }
    2500             : 
    2501           2 :   return CallOrdinaryHasInstance(cx, args);
    2502             : }
    2503             : 
    2504             : bool
    2505           0 : InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
    2506             :                      JS::Handle<JSObject*> instance,
    2507             :                      bool* bp)
    2508             : {
    2509           0 :   const DOMJSClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
    2510             : 
    2511           0 :   MOZ_ASSERT(!domClass || prototypeID != prototypes::id::_ID_Count,
    2512             :              "Why do we have a hasInstance hook if we don't have a prototype "
    2513             :              "ID?");
    2514             : 
    2515           0 :   *bp = (domClass && domClass->mInterfaceChain[depth] == prototypeID);
    2516           0 :   return true;
    2517             : }
    2518             : 
    2519             : bool
    2520           0 : ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj)
    2521             : {
    2522           0 :   JS::Rooted<JSObject*> rootedObj(cx, obj);
    2523           0 :   GlobalObject global(cx, rootedObj);
    2524           0 :   if (global.Failed()) {
    2525           0 :     return false;
    2526             :   }
    2527           0 :   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());
    2528           0 :   if (window && window->GetDoc()) {
    2529           0 :     window->GetDoc()->WarnOnceAbout(nsIDocument::eLenientThis);
    2530             :   }
    2531           0 :   return true;
    2532             : }
    2533             : 
    2534             : bool
    2535           0 : GetContentGlobalForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
    2536             :                                        nsIGlobalObject** globalObj)
    2537             : {
    2538             :   // Be very careful to not get tricked here.
    2539           0 :   MOZ_ASSERT(NS_IsMainThread());
    2540           0 :   if (!xpc::AccessCheck::isChrome(js::GetObjectCompartment(obj))) {
    2541           0 :     MOZ_CRASH("Should have a chrome object here");
    2542             :   }
    2543             : 
    2544             :   // Look up the content-side object.
    2545           0 :   JS::Rooted<JS::Value> domImplVal(cx);
    2546           0 :   if (!JS_GetProperty(cx, obj, "__DOM_IMPL__", &domImplVal)) {
    2547           0 :     return false;
    2548             :   }
    2549             : 
    2550           0 :   if (!domImplVal.isObject()) {
    2551           0 :     ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Value");
    2552           0 :     return false;
    2553             :   }
    2554             : 
    2555             :   // Go ahead and get the global from it.  GlobalObject will handle
    2556             :   // doing unwrapping as needed.
    2557           0 :   GlobalObject global(cx, &domImplVal.toObject());
    2558           0 :   if (global.Failed()) {
    2559           0 :     return false;
    2560             :   }
    2561             : 
    2562           0 :   DebugOnly<nsresult> rv = CallQueryInterface(global.GetAsSupports(), globalObj);
    2563           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
    2564           0 :   MOZ_ASSERT(*globalObj);
    2565           0 :   return true;
    2566             : }
    2567             : 
    2568             : already_AddRefed<nsIGlobalObject>
    2569           0 : ConstructJSImplementation(const char* aContractId,
    2570             :                           const GlobalObject& aGlobal,
    2571             :                           JS::MutableHandle<JSObject*> aObject,
    2572             :                           ErrorResult& aRv)
    2573             : {
    2574             :   // Get the global object to use as a parent and for initialization.
    2575           0 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
    2576           0 :   if (!global) {
    2577           0 :     aRv.Throw(NS_ERROR_FAILURE);
    2578           0 :     return nullptr;
    2579             :   }
    2580             : 
    2581           0 :   ConstructJSImplementation(aContractId, global, aObject, aRv);
    2582             : 
    2583           0 :   if (aRv.Failed()) {
    2584           0 :     return nullptr;
    2585             :   }
    2586           0 :   return global.forget();
    2587             : }
    2588             : 
    2589             : void
    2590           0 : ConstructJSImplementation(const char* aContractId,
    2591             :                           nsIGlobalObject* aGlobal,
    2592             :                           JS::MutableHandle<JSObject*> aObject,
    2593             :                           ErrorResult& aRv)
    2594             : {
    2595           0 :   MOZ_ASSERT(NS_IsMainThread());
    2596             : 
    2597             :   // Make sure to divorce ourselves from the calling JS while creating and
    2598             :   // initializing the object, so exceptions from that will get reported
    2599             :   // properly, since those are never exceptions that a spec wants to be thrown.
    2600             :   {
    2601           0 :     AutoNoJSAPI nojsapi;
    2602             : 
    2603             :     // Get the XPCOM component containing the JS implementation.
    2604             :     nsresult rv;
    2605           0 :     nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId, &rv);
    2606           0 :     if (!implISupports) {
    2607             :       nsPrintfCString msg("Failed to get JS implementation for contract \"%s\"",
    2608           0 :                           aContractId);
    2609           0 :       NS_WARNING(msg.get());
    2610           0 :       aRv.Throw(rv);
    2611           0 :       return;
    2612             :     }
    2613             :     // Initialize the object, if it implements nsIDOMGlobalPropertyInitializer
    2614             :     // and our global is a window.
    2615             :     nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
    2616           0 :       do_QueryInterface(implISupports);
    2617           0 :     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
    2618           0 :     if (gpi) {
    2619           0 :       JS::Rooted<JS::Value> initReturn(RootingCx());
    2620           0 :       rv = gpi->Init(window, &initReturn);
    2621           0 :       if (NS_FAILED(rv)) {
    2622           0 :         aRv.Throw(rv);
    2623           0 :         return;
    2624             :       }
    2625             :       // With JS-implemented WebIDL, the return value of init() is not used to determine
    2626             :       // if init() failed, so init() should only return undefined. Any kind of permission
    2627             :       // or pref checking must happen by adding an attribute to the WebIDL interface.
    2628           0 :       if (!initReturn.isUndefined()) {
    2629           0 :         MOZ_ASSERT(false, "The init() method for JS-implemented WebIDL should not return anything");
    2630             :         MOZ_CRASH();
    2631             :       }
    2632             :     }
    2633             :     // Extract the JS implementation from the XPCOM object.
    2634             :     nsCOMPtr<nsIXPConnectWrappedJS> implWrapped =
    2635           0 :       do_QueryInterface(implISupports, &rv);
    2636           0 :     MOZ_ASSERT(implWrapped, "Failed to get wrapped JS from XPCOM component.");
    2637           0 :     if (!implWrapped) {
    2638           0 :       aRv.Throw(rv);
    2639           0 :       return;
    2640             :     }
    2641           0 :     aObject.set(implWrapped->GetJSObject());
    2642           0 :     if (!aObject) {
    2643           0 :       aRv.Throw(NS_ERROR_FAILURE);
    2644             :     }
    2645             :   }
    2646             : }
    2647             : 
    2648             : bool
    2649           0 : NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
    2650             :                          JS::MutableHandle<JS::Value> rval)
    2651             : {
    2652             :     // ByteStrings are not UTF-8 encoded.
    2653           0 :     JSString* jsStr = JS_NewStringCopyN(cx, str.Data(), str.Length());
    2654             : 
    2655           0 :     if (!jsStr)
    2656           0 :         return false;
    2657             : 
    2658           0 :     rval.setString(jsStr);
    2659           0 :     return true;
    2660             : }
    2661             : 
    2662             : 
    2663             : template<typename T> static void
    2664           8 : NormalizeUSVStringInternal(T& aString)
    2665             : {
    2666           8 :   char16_t* start = aString.BeginWriting();
    2667             :   // Must use const here because we can't pass char** to UTF16CharEnumerator as
    2668             :   // it expects const char**.  Unclear why this is illegal...
    2669           8 :   const char16_t* nextChar = start;
    2670           8 :   const char16_t* end = aString.Data() + aString.Length();
    2671         764 :   while (nextChar < end) {
    2672         378 :     uint32_t enumerated = UTF16CharEnumerator::NextChar(&nextChar, end);
    2673         378 :     if (enumerated == UCS2_REPLACEMENT_CHAR) {
    2674           0 :       int32_t lastCharIndex = (nextChar - start) - 1;
    2675           0 :       start[lastCharIndex] = static_cast<char16_t>(enumerated);
    2676             :     }
    2677             :   }
    2678           8 : }
    2679             : 
    2680             : void
    2681           0 : NormalizeUSVString(nsAString& aString)
    2682             : {
    2683           0 :   NormalizeUSVStringInternal(aString);
    2684           0 : }
    2685             : 
    2686             : void
    2687           8 : NormalizeUSVString(binding_detail::FakeString& aString)
    2688             : {
    2689           8 :   NormalizeUSVStringInternal(aString);
    2690           8 : }
    2691             : 
    2692             : bool
    2693           3 : ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
    2694             :                            bool nullable, nsACString& result)
    2695             : {
    2696           6 :   JS::Rooted<JSString*> s(cx);
    2697           3 :   if (v.isString()) {
    2698           3 :     s = v.toString();
    2699             :   } else {
    2700             : 
    2701           0 :     if (nullable && v.isNullOrUndefined()) {
    2702           0 :       result.SetIsVoid(true);
    2703           0 :       return true;
    2704             :     }
    2705             : 
    2706           0 :     s = JS::ToString(cx, v);
    2707           0 :     if (!s) {
    2708           0 :       return false;
    2709             :     }
    2710             :   }
    2711             : 
    2712             :   // Conversion from Javascript string to ByteString is only valid if all
    2713             :   // characters < 256. This is always the case for Latin1 strings.
    2714             :   size_t length;
    2715           3 :   if (!js::StringHasLatin1Chars(s)) {
    2716             :     // ThrowErrorMessage can GC, so we first scan the string for bad chars
    2717             :     // and report the error outside the AutoCheckCannotGC scope.
    2718           0 :     bool foundBadChar = false;
    2719             :     size_t badCharIndex;
    2720             :     char16_t badChar;
    2721             :     {
    2722           0 :       JS::AutoCheckCannotGC nogc;
    2723           0 :       const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, s, &length);
    2724           0 :       if (!chars) {
    2725           0 :         return false;
    2726             :       }
    2727             : 
    2728           0 :       for (size_t i = 0; i < length; i++) {
    2729           0 :         if (chars[i] > 255) {
    2730           0 :           badCharIndex = i;
    2731           0 :           badChar = chars[i];
    2732           0 :           foundBadChar = true;
    2733           0 :           break;
    2734             :         }
    2735             :       }
    2736             :     }
    2737             : 
    2738           0 :     if (foundBadChar) {
    2739           0 :       MOZ_ASSERT(badCharIndex < length);
    2740           0 :       MOZ_ASSERT(badChar > 255);
    2741             :       // The largest unsigned 64 bit number (18,446,744,073,709,551,615) has
    2742             :       // 20 digits, plus one more for the null terminator.
    2743             :       char index[21];
    2744             :       static_assert(sizeof(size_t) <= 8, "index array too small");
    2745           0 :       SprintfLiteral(index, "%" PRIuSIZE, badCharIndex);
    2746             :       // A char16_t is 16 bits long.  The biggest unsigned 16 bit
    2747             :       // number (65,535) has 5 digits, plus one more for the null
    2748             :       // terminator.
    2749             :       char badCharArray[6];
    2750             :       static_assert(sizeof(char16_t) <= 2, "badCharArray too small");
    2751           0 :       SprintfLiteral(badCharArray, "%d", badChar);
    2752           0 :       ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badCharArray);
    2753           0 :       return false;
    2754             :     }
    2755             :   } else {
    2756           3 :     length = js::GetStringLength(s);
    2757             :   }
    2758             : 
    2759             :   static_assert(js::MaxStringLength < UINT32_MAX,
    2760             :                 "length+1 shouldn't overflow");
    2761             : 
    2762           3 :   if (!result.SetLength(length, fallible)) {
    2763           0 :     return false;
    2764             :   }
    2765             : 
    2766           3 :   JS_EncodeStringToBuffer(cx, s, result.BeginWriting(), length);
    2767             : 
    2768           3 :   return true;
    2769             : }
    2770             : 
    2771             : void
    2772           0 : FinalizeGlobal(JSFreeOp* aFreeOp, JSObject* aObj)
    2773             : {
    2774           0 :   MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL);
    2775           0 :   mozilla::dom::DestroyProtoAndIfaceCache(aObj);
    2776           0 : }
    2777             : 
    2778             : bool
    2779       17299 : ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
    2780             :               JS::Handle<jsid> aId, bool* aResolvedp)
    2781             : {
    2782       17299 :   MOZ_ASSERT(JS_IsGlobalObject(aObj),
    2783             :              "Should have a global here, since we plan to resolve standard "
    2784             :              "classes!");
    2785             : 
    2786       17299 :   return JS_ResolveStandardClass(aCx, aObj, aId, aResolvedp);
    2787             : }
    2788             : 
    2789             : bool
    2790          19 : MayResolveGlobal(const JSAtomState& aNames, jsid aId, JSObject* aMaybeObj)
    2791             : {
    2792          19 :   return JS_MayResolveStandardClass(aNames, aId, aMaybeObj);
    2793             : }
    2794             : 
    2795             : bool
    2796           0 : EnumerateGlobal(JSContext* aCx, JS::HandleObject aObj,
    2797             :                 JS::AutoIdVector& aProperties, bool aEnumerableOnly)
    2798             : {
    2799           0 :   MOZ_ASSERT(JS_IsGlobalObject(aObj),
    2800             :              "Should have a global here, since we plan to enumerate standard "
    2801             :              "classes!");
    2802             : 
    2803           0 :   return JS_NewEnumerateStandardClasses(aCx, aObj, aProperties,
    2804           0 :                                         aEnumerableOnly);
    2805             : }
    2806             : 
    2807             : bool
    2808         170 : IsNonExposedGlobal(JSContext* aCx, JSObject* aGlobal,
    2809             :                    uint32_t aNonExposedGlobals)
    2810             : {
    2811         170 :   MOZ_ASSERT(aNonExposedGlobals, "Why did we get called?");
    2812         170 :   MOZ_ASSERT((aNonExposedGlobals &
    2813             :               ~(GlobalNames::Window |
    2814             :                 GlobalNames::BackstagePass |
    2815             :                 GlobalNames::DedicatedWorkerGlobalScope |
    2816             :                 GlobalNames::SharedWorkerGlobalScope |
    2817             :                 GlobalNames::ServiceWorkerGlobalScope |
    2818             :                 GlobalNames::WorkerDebuggerGlobalScope |
    2819             :                 GlobalNames::WorkletGlobalScope)) == 0,
    2820             :              "Unknown non-exposed global type");
    2821             : 
    2822         170 :   const char* name = js::GetObjectClass(aGlobal)->name;
    2823             : 
    2824         170 :   if ((aNonExposedGlobals & GlobalNames::Window) &&
    2825           0 :       !strcmp(name, "Window")) {
    2826           0 :     return true;
    2827             :   }
    2828             : 
    2829         216 :   if ((aNonExposedGlobals & GlobalNames::BackstagePass) &&
    2830          46 :       !strcmp(name, "BackstagePass")) {
    2831           0 :     return true;
    2832             :   }
    2833             : 
    2834         309 :   if ((aNonExposedGlobals & GlobalNames::DedicatedWorkerGlobalScope) &&
    2835         139 :       !strcmp(name, "DedicatedWorkerGlobalScope")) {
    2836          14 :     return true;
    2837             :   }
    2838             : 
    2839         281 :   if ((aNonExposedGlobals & GlobalNames::SharedWorkerGlobalScope) &&
    2840         125 :       !strcmp(name, "SharedWorkerGlobalScope")) {
    2841           0 :     return true;
    2842             :   }
    2843             : 
    2844         268 :   if ((aNonExposedGlobals & GlobalNames::ServiceWorkerGlobalScope) &&
    2845         112 :       !strcmp(name, "ServiceWorkerGlobalScope")) {
    2846           0 :     return true;
    2847             :   }
    2848             : 
    2849         184 :   if ((aNonExposedGlobals & GlobalNames::WorkerDebuggerGlobalScope) &&
    2850          28 :       !strcmp(name, "WorkerDebuggerGlobalScopex")) {
    2851           0 :     return true;
    2852             :   }
    2853             : 
    2854         156 :   if ((aNonExposedGlobals & GlobalNames::WorkletGlobalScope) &&
    2855           0 :       !strcmp(name, "WorkletGlobalScope")) {
    2856           0 :     return true;
    2857             :   }
    2858             : 
    2859         156 :   return false;
    2860             : }
    2861             : 
    2862             : void
    2863           0 : HandlePrerenderingViolation(nsPIDOMWindowInner* aWindow)
    2864             : {
    2865             :   // Freeze the window and its workers, and its children too.
    2866           0 :   aWindow->Freeze();
    2867             : 
    2868             :   // Suspend event handling on the document
    2869           0 :   nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
    2870           0 :   if (doc) {
    2871           0 :     doc->SuppressEventHandling();
    2872             :   }
    2873           0 : }
    2874             : 
    2875             : bool
    2876           1 : EnforceNotInPrerendering(JSContext* aCx, JSObject* aObj)
    2877             : {
    2878           2 :   JS::Rooted<JSObject*> thisObj(aCx, js::CheckedUnwrap(aObj));
    2879           1 :   if (!thisObj) {
    2880             :     // Without a this object, we cannot check the safety.
    2881           0 :     return true;
    2882             :   }
    2883           1 :   nsGlobalWindow* window = xpc::WindowGlobalOrNull(thisObj);
    2884           1 :   if (!window) {
    2885             :     // Without a window, we cannot check the safety.
    2886           0 :     return true;
    2887             :   }
    2888             : 
    2889           1 :   if (window->GetIsPrerendered()) {
    2890           0 :     HandlePrerenderingViolation(window->AsInner());
    2891             :     // When the bindings layer sees a false return value, it returns false form
    2892             :     // the JSNative in order to trigger an uncatchable exception.
    2893           0 :     return false;
    2894             :   }
    2895             : 
    2896           1 :   return true;
    2897             : }
    2898             : 
    2899             : bool
    2900         774 : GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp)
    2901             : {
    2902         774 :   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    2903         774 :   const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
    2904         774 :   prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
    2905         774 :   if (!args.thisv().isObject()) {
    2906           0 :     return ThrowInvalidThis(cx, args, false, protoID);
    2907             :   }
    2908        1548 :   JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
    2909             : 
    2910             :   // NOTE: we want to leave obj in its initial compartment, so don't want to
    2911             :   // pass it to UnwrapObject.
    2912        1548 :   JS::Rooted<JSObject*> rootSelf(cx, obj);
    2913             :   void* self;
    2914             :   {
    2915         774 :     binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
    2916         774 :     nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
    2917             :                                                                    self,
    2918             :                                                                    protoID,
    2919        1548 :                                                                    info->depth);
    2920         774 :     if (NS_FAILED(rv)) {
    2921           0 :       return ThrowInvalidThis(cx, args,
    2922             :                               rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
    2923           0 :                               protoID);
    2924             :     }
    2925             :   }
    2926             : 
    2927         774 :   MOZ_ASSERT(info->type() == JSJitInfo::Getter);
    2928         774 :   JSJitGetterOp getter = info->getter;
    2929         774 :   bool ok = getter(cx, obj, self, JSJitGetterCallArgs(args));
    2930             : #ifdef DEBUG
    2931         774 :   if (ok) {
    2932         774 :     AssertReturnTypeMatchesJitinfo(info, args.rval());
    2933             :   }
    2934             : #endif
    2935         774 :   return ok;
    2936             : }
    2937             : 
    2938             : bool
    2939           0 : GenericPromiseReturningBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp)
    2940             : {
    2941             :   // Make sure to save the callee before someone maybe messes with rval().
    2942           0 :   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    2943           0 :   JS::Rooted<JSObject*> callee(cx, &args.callee());
    2944             : 
    2945             :   // We could invoke GenericBindingGetter here, but that involves an
    2946             :   // extra call.  Manually inline it instead.
    2947           0 :   const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
    2948           0 :   prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
    2949           0 :   if (!args.thisv().isObject()) {
    2950           0 :     ThrowInvalidThis(cx, args, false, protoID);
    2951           0 :     return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
    2952           0 :                                      args.rval());
    2953             :   }
    2954           0 :   JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
    2955             : 
    2956             :   // NOTE: we want to leave obj in its initial compartment, so don't want to
    2957             :   // pass it to UnwrapObject.
    2958           0 :   JS::Rooted<JSObject*> rootSelf(cx, obj);
    2959             :   void* self;
    2960             :   {
    2961           0 :     binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
    2962           0 :     nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
    2963             :                                                                    self,
    2964             :                                                                    protoID,
    2965           0 :                                                                    info->depth);
    2966           0 :     if (NS_FAILED(rv)) {
    2967           0 :       ThrowInvalidThis(cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
    2968           0 :                        protoID);
    2969           0 :       return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
    2970           0 :                                        args.rval());
    2971             :     }
    2972             :   }
    2973           0 :   MOZ_ASSERT(info->type() == JSJitInfo::Getter);
    2974           0 :   JSJitGetterOp getter = info->getter;
    2975           0 :   bool ok = getter(cx, obj, self, JSJitGetterCallArgs(args));
    2976           0 :   if (ok) {
    2977             : #ifdef DEBUG
    2978           0 :     AssertReturnTypeMatchesJitinfo(info, args.rval());
    2979             : #endif
    2980           0 :     return true;
    2981             :   }
    2982             : 
    2983             :   // Promise-returning getters always return objects
    2984           0 :   MOZ_ASSERT(info->returnType() == JSVAL_TYPE_OBJECT);
    2985           0 :   return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
    2986           0 :                                    args.rval());
    2987             : }
    2988             : 
    2989             : bool
    2990         106 : GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp)
    2991             : {
    2992         106 :   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    2993         106 :   const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
    2994         106 :   prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
    2995         106 :   if (!args.thisv().isObject()) {
    2996           0 :     return ThrowInvalidThis(cx, args, false, protoID);
    2997             :   }
    2998         211 :   JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
    2999             : 
    3000             :   // NOTE: we want to leave obj in its initial compartment, so don't want to
    3001             :   // pass it to UnwrapObject.
    3002         211 :   JS::Rooted<JSObject*> rootSelf(cx, obj);
    3003             :   void* self;
    3004             :   {
    3005         106 :     binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
    3006         106 :     nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
    3007             :                                                                    self,
    3008             :                                                                    protoID,
    3009         212 :                                                                    info->depth);
    3010         106 :     if (NS_FAILED(rv)) {
    3011           0 :       return ThrowInvalidThis(cx, args,
    3012             :                               rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
    3013           0 :                               protoID);
    3014             :     }
    3015             :   }
    3016         106 :   if (args.length() == 0) {
    3017           0 :     return ThrowNoSetterArg(cx, protoID);
    3018             :   }
    3019         106 :   MOZ_ASSERT(info->type() == JSJitInfo::Setter);
    3020         106 :   JSJitSetterOp setter = info->setter;
    3021         106 :   if (!setter(cx, obj, self, JSJitSetterCallArgs(args))) {
    3022           0 :     return false;
    3023             :   }
    3024         105 :   args.rval().setUndefined();
    3025             : #ifdef DEBUG
    3026         105 :   AssertReturnTypeMatchesJitinfo(info, args.rval());
    3027             : #endif
    3028         105 :   return true;
    3029             : }
    3030             : 
    3031             : bool
    3032        1160 : GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp)
    3033             : {
    3034        1160 :   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    3035        1160 :   const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
    3036        1160 :   prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
    3037        1160 :   if (!args.thisv().isObject()) {
    3038           0 :     return ThrowInvalidThis(cx, args, false, protoID);
    3039             :   }
    3040        2320 :   JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
    3041             : 
    3042             :   // NOTE: we want to leave obj in its initial compartment, so don't want to
    3043             :   // pass it to UnwrapObject.
    3044        2320 :   JS::Rooted<JSObject*> rootSelf(cx, obj);
    3045             :   void* self;
    3046             :   {
    3047        1160 :     binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
    3048        1160 :     nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
    3049             :                                                                    self,
    3050             :                                                                    protoID,
    3051        2320 :                                                                    info->depth);
    3052        1160 :     if (NS_FAILED(rv)) {
    3053           0 :       return ThrowInvalidThis(cx, args,
    3054             :                               rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
    3055           0 :                               protoID);
    3056             :     }
    3057             :   }
    3058        1160 :   MOZ_ASSERT(info->type() == JSJitInfo::Method);
    3059        1160 :   JSJitMethodOp method = info->method;
    3060        1160 :   bool ok = method(cx, obj, self, JSJitMethodCallArgs(args));
    3061             : #ifdef DEBUG
    3062        1160 :   if (ok) {
    3063        1160 :     AssertReturnTypeMatchesJitinfo(info, args.rval());
    3064             :   }
    3065             : #endif
    3066        1160 :   return ok;
    3067             : }
    3068             : 
    3069             : bool
    3070           1 : GenericPromiseReturningBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp)
    3071             : {
    3072             :   // Make sure to save the callee before someone maybe messes with rval().
    3073           1 :   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    3074           2 :   JS::Rooted<JSObject*> callee(cx, &args.callee());
    3075             : 
    3076             :   // We could invoke GenericBindingMethod here, but that involves an
    3077             :   // extra call.  Manually inline it instead.
    3078           1 :   const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
    3079           1 :   prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
    3080           1 :   if (!args.thisv().isObject()) {
    3081           0 :     ThrowInvalidThis(cx, args, false, protoID);
    3082           0 :     return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
    3083           0 :                                      args.rval());
    3084             :   }
    3085           2 :   JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
    3086             : 
    3087             :   // NOTE: we want to leave obj in its initial compartment, so don't want to
    3088             :   // pass it to UnwrapObject.
    3089           2 :   JS::Rooted<JSObject*> rootSelf(cx, obj);
    3090             :   void* self;
    3091             :   {
    3092           1 :     binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
    3093           1 :     nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
    3094             :                                                                    self,
    3095             :                                                                    protoID,
    3096           2 :                                                                    info->depth);
    3097           1 :     if (NS_FAILED(rv)) {
    3098           0 :       ThrowInvalidThis(cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
    3099           0 :                        protoID);
    3100           0 :       return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
    3101           0 :                                        args.rval());
    3102             :     }
    3103             :   }
    3104           1 :   MOZ_ASSERT(info->type() == JSJitInfo::Method);
    3105           1 :   JSJitMethodOp method = info->method;
    3106           1 :   bool ok = method(cx, obj, self, JSJitMethodCallArgs(args));
    3107           1 :   if (ok) {
    3108             : #ifdef DEBUG
    3109           1 :     AssertReturnTypeMatchesJitinfo(info, args.rval());
    3110             : #endif
    3111           1 :     return true;
    3112             :   }
    3113             : 
    3114             :   // Promise-returning methods always return objects
    3115           0 :   MOZ_ASSERT(info->returnType() == JSVAL_TYPE_OBJECT);
    3116           0 :   return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
    3117           0 :                                    args.rval());
    3118             : }
    3119             : 
    3120             : bool
    3121           0 : StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp)
    3122             : {
    3123             :   // Make sure to save the callee before someone maybe messes with rval().
    3124           0 :   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    3125           0 :   JS::Rooted<JSObject*> callee(cx, &args.callee());
    3126             : 
    3127           0 :   const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
    3128           0 :   MOZ_ASSERT(info);
    3129           0 :   MOZ_ASSERT(info->type() == JSJitInfo::StaticMethod);
    3130             : 
    3131           0 :   bool ok = info->staticMethod(cx, argc, vp);
    3132           0 :   if (ok) {
    3133           0 :     return true;
    3134             :   }
    3135             : 
    3136           0 :   return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
    3137           0 :                                    args.rval());
    3138             : }
    3139             : 
    3140             : bool
    3141           0 : ConvertExceptionToPromise(JSContext* cx,
    3142             :                           JSObject* promiseScope,
    3143             :                           JS::MutableHandle<JS::Value> rval)
    3144             : {
    3145             :   {
    3146           0 :     JSAutoCompartment ac(cx, promiseScope);
    3147             : 
    3148           0 :     JS::Rooted<JS::Value> exn(cx);
    3149           0 :     if (!JS_GetPendingException(cx, &exn)) {
    3150             :       // This is very important: if there is no pending exception here but we're
    3151             :       // ending up in this code, that means the callee threw an uncatchable
    3152             :       // exception.  Just propagate that out as-is.
    3153           0 :       return false;
    3154             :     }
    3155             : 
    3156           0 :     JS_ClearPendingException(cx);
    3157             : 
    3158           0 :     JSObject* promise = JS::CallOriginalPromiseReject(cx, exn);
    3159           0 :     if (!promise) {
    3160             :       // We just give up.  Put the exception back.
    3161           0 :       JS_SetPendingException(cx, exn);
    3162           0 :       return false;
    3163             :     }
    3164             : 
    3165           0 :     rval.setObject(*promise);
    3166             :   }
    3167             : 
    3168             :   // Now make sure we rewrap promise back into the compartment we want
    3169           0 :   return JS_WrapValue(cx, rval);
    3170             : }
    3171             : 
    3172             : /* static */
    3173             : void
    3174           0 : CreateGlobalOptions<nsGlobalWindow>::TraceGlobal(JSTracer* aTrc, JSObject* aObj)
    3175             : {
    3176           0 :   xpc::TraceXPCGlobal(aTrc, aObj);
    3177           0 : }
    3178             : 
    3179             : static bool sRegisteredDOMNames = false;
    3180             : 
    3181             : nsresult
    3182          64 : RegisterDOMNames()
    3183             : {
    3184          64 :   if (sRegisteredDOMNames) {
    3185          61 :     return NS_OK;
    3186             :   }
    3187             : 
    3188             :   // Register new DOM bindings
    3189           3 :   WebIDLGlobalNameHash::Init();
    3190             : 
    3191           3 :   nsresult rv = nsDOMClassInfo::Init();
    3192           3 :   if (NS_FAILED(rv)) {
    3193           0 :     NS_ERROR("Could not initialize nsDOMClassInfo");
    3194           0 :     return rv;
    3195             :   }
    3196             : 
    3197           3 :   sRegisteredDOMNames = true;
    3198             : 
    3199           3 :   return NS_OK;
    3200             : }
    3201             : 
    3202             : /* static */
    3203             : bool
    3204           7 : CreateGlobalOptions<nsGlobalWindow>::PostCreateGlobal(JSContext* aCx,
    3205             :                                                       JS::Handle<JSObject*> aGlobal)
    3206             : {
    3207           7 :   nsresult rv = RegisterDOMNames();
    3208           7 :   if (NS_FAILED(rv)) {
    3209           0 :     return Throw(aCx, rv);
    3210             :   }
    3211             : 
    3212             :   // Invoking the XPCWrappedNativeScope constructor automatically hooks it
    3213             :   // up to the compartment of aGlobal.
    3214          14 :   (void) new XPCWrappedNativeScope(aCx, aGlobal);
    3215           7 :   return true;
    3216             : }
    3217             : 
    3218             : #ifdef DEBUG
    3219             : void
    3220        2928 : AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitInfo,
    3221             :                                JS::Handle<JS::Value> aValue)
    3222             : {
    3223        2928 :   switch (aJitInfo->returnType()) {
    3224             :   case JSVAL_TYPE_UNKNOWN:
    3225             :     // Any value is good.
    3226        1230 :     break;
    3227             :   case JSVAL_TYPE_DOUBLE:
    3228             :     // The value could actually be an int32 value as well.
    3229         123 :     MOZ_ASSERT(aValue.isNumber());
    3230         123 :     break;
    3231             :   case JSVAL_TYPE_INT32:
    3232          46 :     MOZ_ASSERT(aValue.isInt32());
    3233          46 :     break;
    3234             :   case JSVAL_TYPE_UNDEFINED:
    3235         801 :     MOZ_ASSERT(aValue.isUndefined());
    3236         801 :     break;
    3237             :   case JSVAL_TYPE_BOOLEAN:
    3238          82 :     MOZ_ASSERT(aValue.isBoolean());
    3239          82 :     break;
    3240             :   case JSVAL_TYPE_STRING:
    3241         214 :     MOZ_ASSERT(aValue.isString());
    3242         214 :     break;
    3243             :   case JSVAL_TYPE_NULL:
    3244           0 :     MOZ_ASSERT(aValue.isNull());
    3245           0 :     break;
    3246             :   case JSVAL_TYPE_OBJECT:
    3247         432 :     MOZ_ASSERT(aValue.isObject());
    3248         432 :     break;
    3249             :   default:
    3250             :     // Someone messed up their jitinfo type.
    3251           0 :     MOZ_ASSERT(false, "Unexpected JSValueType stored in jitinfo");
    3252             :     break;
    3253             :   }
    3254        2928 : }
    3255             : #endif
    3256             : 
    3257             : bool
    3258           0 : CallerSubsumes(JSObject *aObject)
    3259             : {
    3260           0 :   nsIPrincipal* objPrin = nsContentUtils::ObjectPrincipal(js::UncheckedUnwrap(aObject));
    3261           0 :   return nsContentUtils::SubjectPrincipal()->Subsumes(objPrin);
    3262             : }
    3263             : 
    3264             : nsresult
    3265         266 : UnwrapArgImpl(JSContext* cx,
    3266             :               JS::Handle<JSObject*> src,
    3267             :               const nsIID &iid,
    3268             :               void **ppArg)
    3269             : {
    3270         266 :   if (!NS_IsMainThread()) {
    3271           0 :     return NS_ERROR_NOT_AVAILABLE;
    3272             :   }
    3273             : 
    3274         532 :   nsCOMPtr<nsISupports> iface = xpc::UnwrapReflectorToISupports(src);
    3275         266 :   if (iface) {
    3276         265 :     if (NS_FAILED(iface->QueryInterface(iid, ppArg))) {
    3277           0 :       return NS_ERROR_XPC_BAD_CONVERT_JS;
    3278             :     }
    3279             : 
    3280         265 :     return NS_OK;
    3281             :   }
    3282             : 
    3283             :   // Only allow XPCWrappedJS stuff in system code.  Ideally we would remove this
    3284             :   // even there, but that involves converting some things to WebIDL callback
    3285             :   // interfaces and making some other things builtinclass...
    3286           1 :   if (!nsContentUtils::IsSystemCaller(cx)) {
    3287           0 :     return NS_ERROR_XPC_BAD_CONVERT_JS;
    3288             :   }
    3289             : 
    3290           2 :   RefPtr<nsXPCWrappedJS> wrappedJS;
    3291           1 :   nsresult rv = nsXPCWrappedJS::GetNewOrUsed(src, iid, getter_AddRefs(wrappedJS));
    3292           1 :   if (NS_FAILED(rv) || !wrappedJS) {
    3293           0 :     return rv;
    3294             :   }
    3295             : 
    3296             :   // We need to go through the QueryInterface logic to make this return
    3297             :   // the right thing for the various 'special' interfaces; e.g.
    3298             :   // nsIPropertyBag. We must use AggregatedQueryInterface in cases where
    3299             :   // there is an outer to avoid nasty recursion.
    3300           1 :   return wrappedJS->QueryInterface(iid, ppArg);
    3301             : }
    3302             : 
    3303             : nsresult
    3304           0 : UnwrapXPConnectImpl(JSContext* cx,
    3305             :                     JS::MutableHandle<JS::Value> src,
    3306             :                     const nsIID &iid,
    3307             :                     void **ppArg)
    3308             : {
    3309           0 :   if (!NS_IsMainThread()) {
    3310           0 :     return NS_ERROR_NOT_AVAILABLE;
    3311             :   }
    3312             : 
    3313           0 :   MOZ_ASSERT(src.isObject());
    3314             :   // Unwrap ourselves, because we're going to want access to the unwrapped
    3315             :   // object.
    3316             :   JS::Rooted<JSObject*> obj(cx,
    3317           0 :                             js::CheckedUnwrap(&src.toObject(),
    3318           0 :                                               /* stopAtWindowProxy = */ false));
    3319           0 :   if (!obj) {
    3320           0 :     return NS_ERROR_NOT_AVAILABLE;
    3321             :   }
    3322             : 
    3323           0 :   nsCOMPtr<nsISupports> iface = xpc::UnwrapReflectorToISupports(obj);
    3324           0 :   if (!iface) {
    3325           0 :     return NS_ERROR_XPC_BAD_CONVERT_JS;
    3326             :   }
    3327             : 
    3328           0 :   if (NS_FAILED(iface->QueryInterface(iid, ppArg))) {
    3329           0 :     return NS_ERROR_XPC_BAD_CONVERT_JS;
    3330             :   }
    3331             : 
    3332             :   // Now update our source to keep rooting our object.
    3333           0 :   src.setObject(*obj);
    3334           0 :   return NS_OK;
    3335             : }
    3336             : 
    3337             : nsresult
    3338           0 : UnwrapWindowProxyImpl(JSContext* cx,
    3339             :                       JS::Handle<JSObject*> src,
    3340             :                       nsPIDOMWindowOuter** ppArg)
    3341             : {
    3342           0 :   nsCOMPtr<nsPIDOMWindowInner> inner;
    3343           0 :   nsresult rv = UnwrapArg<nsPIDOMWindowInner>(cx, src, getter_AddRefs(inner));
    3344           0 :   NS_ENSURE_SUCCESS(rv, rv);
    3345             : 
    3346           0 :   nsCOMPtr<nsPIDOMWindowOuter> outer = inner->GetOuterWindow();
    3347           0 :   outer.forget(ppArg);
    3348           0 :   return NS_OK;
    3349             : }
    3350             : 
    3351             : bool
    3352       14169 : SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
    3353             :                     JS::Handle<jsid> id, bool* resolvedp)
    3354             : {
    3355       14169 :   if (!ResolveGlobal(cx, obj, id, resolvedp)) {
    3356           0 :     return false;
    3357             :   }
    3358             : 
    3359       14170 :   if (*resolvedp) {
    3360         249 :     return true;
    3361             :   }
    3362             : 
    3363       13921 :   return ResolveSystemBinding(cx, obj, id, resolvedp);
    3364             : }
    3365             : 
    3366             : bool
    3367           0 : SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj)
    3368             : {
    3369           0 :   bool ignored = false;
    3370           0 :   return JS_EnumerateStandardClasses(cx, obj) &&
    3371           0 :          ResolveSystemBinding(cx, obj, JSID_VOIDHANDLE, &ignored);
    3372             : }
    3373             : 
    3374             : template<decltype(JS::NewMapObject) Method>
    3375             : bool
    3376           0 : GetMaplikeSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
    3377             :                                size_t aSlotIndex,
    3378             :                                JS::MutableHandle<JSObject*> aBackingObj,
    3379             :                                bool* aBackingObjCreated)
    3380             : {
    3381           0 :   JS::Rooted<JSObject*> reflector(aCx);
    3382           0 :   reflector = IsDOMObject(aObj) ? aObj : js::UncheckedUnwrap(aObj,
    3383             :                                                              /* stopAtWindowProxy = */ false);
    3384             : 
    3385             :   // Retrieve the backing object from the reserved slot on the maplike/setlike
    3386             :   // object. If it doesn't exist yet, create it.
    3387           0 :   JS::Rooted<JS::Value> slotValue(aCx);
    3388           0 :   slotValue = js::GetReservedSlot(reflector, aSlotIndex);
    3389           0 :   if (slotValue.isUndefined()) {
    3390             :     // Since backing object access can happen in non-originating compartments,
    3391             :     // make sure to create the backing object in reflector compartment.
    3392             :     {
    3393           0 :       JSAutoCompartment ac(aCx, reflector);
    3394           0 :       JS::Rooted<JSObject*> newBackingObj(aCx);
    3395           0 :       newBackingObj.set(Method(aCx));
    3396           0 :       if (NS_WARN_IF(!newBackingObj)) {
    3397           0 :         return false;
    3398             :       }
    3399           0 :       js::SetReservedSlot(reflector, aSlotIndex, JS::ObjectValue(*newBackingObj));
    3400             :     }
    3401           0 :     slotValue = js::GetReservedSlot(reflector, aSlotIndex);
    3402           0 :     *aBackingObjCreated = true;
    3403             :   } else {
    3404           0 :     *aBackingObjCreated = false;
    3405             :   }
    3406           0 :   if (!MaybeWrapNonDOMObjectValue(aCx, &slotValue)) {
    3407           0 :     return false;
    3408             :   }
    3409           0 :   aBackingObj.set(&slotValue.toObject());
    3410           0 :   return true;
    3411             : }
    3412             : 
    3413             : bool
    3414           0 : GetMaplikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
    3415             :                         size_t aSlotIndex,
    3416             :                         JS::MutableHandle<JSObject*> aBackingObj,
    3417             :                         bool* aBackingObjCreated)
    3418             : {
    3419             :   return GetMaplikeSetlikeBackingObject<JS::NewMapObject>(aCx, aObj, aSlotIndex,
    3420             :                                                           aBackingObj,
    3421           0 :                                                           aBackingObjCreated);
    3422             : }
    3423             : 
    3424             : bool
    3425           0 : GetSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
    3426             :                         size_t aSlotIndex,
    3427             :                         JS::MutableHandle<JSObject*> aBackingObj,
    3428             :                         bool* aBackingObjCreated)
    3429             : {
    3430             :   return GetMaplikeSetlikeBackingObject<JS::NewSetObject>(aCx, aObj, aSlotIndex,
    3431             :                                                           aBackingObj,
    3432           0 :                                                           aBackingObjCreated);
    3433             : }
    3434             : 
    3435             : bool
    3436           0 : ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
    3437             : {
    3438           0 :   JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
    3439             :   // Unpack callback and object from slots
    3440             :   JS::Rooted<JS::Value>
    3441           0 :     callbackFn(aCx, js::GetFunctionNativeReserved(&args.callee(),
    3442           0 :                                                   FOREACH_CALLBACK_SLOT));
    3443             :   JS::Rooted<JS::Value>
    3444             :     maplikeOrSetlikeObj(aCx,
    3445           0 :                         js::GetFunctionNativeReserved(&args.callee(),
    3446           0 :                                                       FOREACH_MAPLIKEORSETLIKEOBJ_SLOT));
    3447           0 :   MOZ_ASSERT(aArgc == 3);
    3448           0 :   JS::AutoValueVector newArgs(aCx);
    3449             :   // Arguments are passed in as value, key, object. Keep value and key, replace
    3450             :   // object with the maplike/setlike object.
    3451           0 :   if (!newArgs.append(args.get(0))) {
    3452           0 :     return false;
    3453             :   }
    3454           0 :   if (!newArgs.append(args.get(1))) {
    3455           0 :     return false;
    3456             :   }
    3457           0 :   if (!newArgs.append(maplikeOrSetlikeObj)) {
    3458           0 :     return false;
    3459             :   }
    3460           0 :   JS::Rooted<JS::Value> rval(aCx, JS::UndefinedValue());
    3461             :   // Now actually call the user specified callback
    3462           0 :   return JS::Call(aCx, args.thisv(), callbackFn, newArgs, &rval);
    3463             : }
    3464             : 
    3465             : static inline prototypes::ID
    3466          18 : GetProtoIdForNewtarget(JS::Handle<JSObject*> aNewTarget)
    3467             : {
    3468          18 :   const js::Class* newTargetClass = js::GetObjectClass(aNewTarget);
    3469          18 :   if (IsDOMIfaceAndProtoClass(newTargetClass)) {
    3470             :     const DOMIfaceAndProtoJSClass* newTargetIfaceClass =
    3471          17 :       DOMIfaceAndProtoJSClass::FromJSClass(newTargetClass);
    3472          17 :     if (newTargetIfaceClass->mType == eInterface) {
    3473          17 :       return newTargetIfaceClass->mPrototypeID;
    3474             :     }
    3475           1 :   } else if (JS_IsNativeFunction(aNewTarget, Constructor)) {
    3476           0 :     return GetNativePropertyHooksFromConstructorFunction(aNewTarget)->mPrototypeID;
    3477             :   }
    3478             : 
    3479           1 :   return prototypes::id::_ID_Count;
    3480             : }
    3481             : 
    3482             : bool
    3483          17 : GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
    3484             :                 JS::MutableHandle<JSObject*> aDesiredProto)
    3485             : {
    3486          17 :   if (!aCallArgs.isConstructing()) {
    3487           0 :     aDesiredProto.set(nullptr);
    3488           0 :     return true;
    3489             :   }
    3490             : 
    3491             :   // The desired prototype depends on the actual constructor that was invoked,
    3492             :   // which is passed to us as the newTarget in the callargs.  We want to do
    3493             :   // something akin to the ES6 specification's GetProtototypeFromConstructor (so
    3494             :   // get .prototype on the newTarget, with a fallback to some sort of default).
    3495             : 
    3496             :   // First, a fast path for the case when the the constructor is in fact one of
    3497             :   // our DOM constructors.  This is safe because on those the "constructor"
    3498             :   // property is non-configurable and non-writable, so we don't have to do the
    3499             :   // slow JS_GetProperty call.
    3500          34 :   JS::Rooted<JSObject*> newTarget(aCx, &aCallArgs.newTarget().toObject());
    3501          34 :   JS::Rooted<JSObject*> originalNewTarget(aCx, newTarget);
    3502             :   // See whether we have a known DOM constructor here, such that we can take a
    3503             :   // fast path.
    3504          17 :   prototypes::ID protoID = GetProtoIdForNewtarget(newTarget);
    3505          17 :   if (protoID == prototypes::id::_ID_Count) {
    3506             :     // We might still have a cross-compartment wrapper for a known DOM
    3507             :     // constructor.
    3508           1 :     newTarget = js::CheckedUnwrap(newTarget);
    3509           1 :     if (newTarget && newTarget != originalNewTarget) {
    3510           1 :       protoID = GetProtoIdForNewtarget(newTarget);
    3511             :     }
    3512             :   }
    3513             : 
    3514          17 :   if (protoID != prototypes::id::_ID_Count) {
    3515             :     ProtoAndIfaceCache& protoAndIfaceCache =
    3516          17 :       *GetProtoAndIfaceCache(js::GetGlobalForObjectCrossCompartment(newTarget));
    3517          17 :     aDesiredProto.set(protoAndIfaceCache.EntrySlotMustExist(protoID));
    3518          17 :     if (newTarget != originalNewTarget) {
    3519           1 :       return JS_WrapObject(aCx, aDesiredProto);
    3520             :     }
    3521          16 :     return true;
    3522             :   }
    3523             : 
    3524             :   // Slow path.  This basically duplicates the ES6 spec's
    3525             :   // GetPrototypeFromConstructor except that instead of taking a string naming
    3526             :   // the fallback prototype we just fall back to using null and assume that our
    3527             :   // caller will then pick the right default.  The actual defaulting behavior
    3528             :   // here still needs to be defined in the Web IDL specification.
    3529             :   //
    3530             :   // Note that it's very important to do this property get on originalNewTarget,
    3531             :   // not our unwrapped newTarget, since we want to get Xray behavior here as
    3532             :   // needed.
    3533             :   // XXXbz for speed purposes, using a preinterned id here sure would be nice.
    3534           0 :   JS::Rooted<JS::Value> protoVal(aCx);
    3535           0 :   if (!JS_GetProperty(aCx, originalNewTarget, "prototype", &protoVal)) {
    3536           0 :     return false;
    3537             :   }
    3538             : 
    3539           0 :   if (!protoVal.isObject()) {
    3540           0 :     aDesiredProto.set(nullptr);
    3541           0 :     return true;
    3542             :   }
    3543             : 
    3544           0 :   aDesiredProto.set(&protoVal.toObject());
    3545           0 :   return true;
    3546             : }
    3547             : 
    3548             : CustomElementReactionsStack*
    3549         602 : GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj)
    3550             : {
    3551             :   // This might not be the right object, if there are wrappers. Unwrap if we can.
    3552         602 :   JSObject* obj = js::CheckedUnwrap(aObj);
    3553         602 :   if (!obj) {
    3554           0 :     return nullptr;
    3555             :   }
    3556             : 
    3557         602 :   nsGlobalWindow* window = xpc::WindowGlobalOrNull(obj);
    3558         602 :   if (!window) {
    3559           0 :     return nullptr;
    3560             :   }
    3561             : 
    3562         602 :   DocGroup* docGroup = window->AsInner()->GetDocGroup();
    3563         602 :   if (!docGroup) {
    3564           0 :     return nullptr;
    3565             :   }
    3566             : 
    3567         602 :   return docGroup->CustomElementReactionsStack();
    3568             : }
    3569             : 
    3570             : // https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
    3571             : already_AddRefed<nsGenericHTMLElement>
    3572           0 : CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
    3573             :                   ErrorResult& aRv)
    3574             : {
    3575             :   // Step 1.
    3576           0 :   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
    3577           0 :   if (!window) {
    3578           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    3579           0 :     return nullptr;
    3580             :   }
    3581             : 
    3582           0 :   nsIDocument* doc = window->GetExtantDoc();
    3583           0 :   if (!doc) {
    3584           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    3585           0 :     return nullptr;
    3586             :   }
    3587             : 
    3588           0 :   RefPtr<mozilla::dom::CustomElementRegistry> registry(window->CustomElements());
    3589           0 :   if (!registry) {
    3590           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    3591           0 :     return nullptr;
    3592             :   }
    3593             : 
    3594             :   // Step 2 is in the code output by CGClassConstructor.
    3595             :   // Step 3.
    3596           0 :   JSContext* cx = aGlobal.Context();
    3597           0 :   JS::Rooted<JSObject*> newTarget(cx, &aCallArgs.newTarget().toObject());
    3598             :   CustomElementDefinition* definition =
    3599           0 :     registry->LookupCustomElementDefinition(cx, newTarget);
    3600           0 :   if (!definition) {
    3601           0 :     aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
    3602           0 :     return nullptr;
    3603             :   }
    3604             : 
    3605             :   // The callee might be an Xray. Unwrap it to get actual callee.
    3606           0 :   JS::Rooted<JSObject*> callee(cx, js::CheckedUnwrap(&aCallArgs.callee()));
    3607           0 :   if (!callee) {
    3608           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    3609           0 :     return nullptr;
    3610             :   }
    3611             : 
    3612             :   // And the actual callee might be in different compartment, so enter its
    3613             :   // compartment before getting the standard constructor object to compare to,
    3614             :   // so we get it from the same global as callee itself.
    3615           0 :   JSAutoCompartment ac(cx, callee);
    3616           0 :   int32_t tag = eHTMLTag_userdefined;
    3617           0 :   if (!definition->IsCustomBuiltIn()) {
    3618             :     // Step 4.
    3619             :     // If the definition is for an autonomous custom element, the active
    3620             :     // function should be HTMLElement.
    3621           0 :     JS::Rooted<JSObject*> constructor(cx, HTMLElementBinding::GetConstructorObject(cx));
    3622           0 :     if (!constructor) {
    3623           0 :       aRv.NoteJSContextException(cx);
    3624           0 :       return nullptr;
    3625             :     }
    3626             : 
    3627           0 :     if (callee != constructor) {
    3628           0 :       aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
    3629           0 :       return nullptr;
    3630             :     }
    3631             :   } else {
    3632             :     // Step 5.
    3633             :     // If the definition is for a customized built-in element, the localName
    3634             :     // should be defined in the specification.
    3635           0 :     nsIParserService* parserService = nsContentUtils::GetParserService();
    3636           0 :     if (!parserService) {
    3637           0 :       aRv.Throw(NS_ERROR_UNEXPECTED);
    3638           0 :       return nullptr;
    3639             :     }
    3640             : 
    3641           0 :     tag = parserService->HTMLCaseSensitiveAtomTagToId(definition->mLocalName);
    3642           0 :     if (tag == eHTMLTag_userdefined) {
    3643           0 :       aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
    3644           0 :       return nullptr;
    3645             :     }
    3646             : 
    3647           0 :     MOZ_ASSERT(tag <= NS_HTML_TAG_MAX, "tag is out of bounds");
    3648             : 
    3649             :     // If the definition is for a customized built-in element, the active
    3650             :     // function should be the localname's element interface.
    3651           0 :     constructorGetterCallback cb = sConstructorGetterCallback[tag];
    3652           0 :     if (!cb) {
    3653           0 :       aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
    3654           0 :       return nullptr;
    3655             :     }
    3656             : 
    3657           0 :     JS::Rooted<JSObject*> constructor(cx, cb(cx));
    3658           0 :     if (!constructor) {
    3659           0 :       aRv.NoteJSContextException(cx);
    3660           0 :       return nullptr;
    3661             :     }
    3662             : 
    3663           0 :     if (callee != constructor) {
    3664           0 :       aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
    3665           0 :       return nullptr;
    3666             :     }
    3667             :   }
    3668             : 
    3669             :   RefPtr<mozilla::dom::NodeInfo> nodeInfo =
    3670           0 :     doc->NodeInfoManager()->GetNodeInfo(definition->mLocalName,
    3671             :                                         nullptr,
    3672             :                                         kNameSpaceID_XHTML,
    3673           0 :                                         nsIDOMNode::ELEMENT_NODE);
    3674           0 :   if (!nodeInfo) {
    3675           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    3676           0 :     return nullptr;
    3677             :   }
    3678             : 
    3679             :   // Step 6 and Step 7 are in the code output by CGClassConstructor.
    3680             :   // Step 8.
    3681             :   // Construction stack will be implemented in bug 1287348. So we always run
    3682             :   // "construction stack is empty" case for now.
    3683           0 :   RefPtr<nsGenericHTMLElement> element;
    3684           0 :   if (tag == eHTMLTag_userdefined) {
    3685             :     // Autonomous custom element.
    3686           0 :     element = NS_NewHTMLElement(nodeInfo.forget());
    3687             :   } else {
    3688             :     // Customized built-in element.
    3689           0 :     element = CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
    3690             :   }
    3691             : 
    3692           0 :   element->SetCustomElementData(
    3693           0 :     new CustomElementData(definition->mType, CustomElementData::State::eCustom));
    3694             : 
    3695           0 :   return element.forget();
    3696             : }
    3697             : 
    3698             : #ifdef DEBUG
    3699             : namespace binding_detail {
    3700             : void
    3701        2103 : AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector,
    3702             :                              JS::Handle<JSObject*> aGivenProto)
    3703             : {
    3704        2103 :   if (!aGivenProto) {
    3705             :     // Nothing to assert here
    3706        2103 :     return;
    3707             :   }
    3708             : 
    3709           0 :   JS::Rooted<JSObject*> reflector(aCx, aReflector);
    3710           0 :   JSAutoCompartment ac(aCx, reflector);
    3711           0 :   JS::Rooted<JSObject*> reflectorProto(aCx);
    3712           0 :   bool ok = JS_GetPrototype(aCx, reflector, &reflectorProto);
    3713           0 :   MOZ_ASSERT(ok);
    3714             :   // aGivenProto may not be in the right compartment here, so we
    3715             :   // have to wrap it to compare.
    3716           0 :   JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
    3717           0 :   ok = JS_WrapObject(aCx, &givenProto);
    3718           0 :   MOZ_ASSERT(ok);
    3719           0 :   MOZ_ASSERT(givenProto == reflectorProto,
    3720             :              "How are we supposed to change the proto now?");
    3721             : }
    3722             : } // namespace binding_detail
    3723             : #endif // DEBUG
    3724             : 
    3725             : void
    3726           0 : SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject,
    3727             :                              UseCounter aUseCounter)
    3728             : {
    3729           0 :   nsGlobalWindow* win = xpc::WindowGlobalOrNull(js::UncheckedUnwrap(aObject));
    3730           0 :   if (win && win->GetDocument()) {
    3731           0 :     win->GetDocument()->SetDocumentAndPageUseCounter(aUseCounter);
    3732             :   }
    3733           0 : }
    3734             : 
    3735             : namespace {
    3736             : 
    3737             : // This runnable is used to write a deprecation message from a worker to the
    3738             : // console running on the main-thread.
    3739           0 : class DeprecationWarningRunnable final : public WorkerProxyToMainThreadRunnable
    3740             : {
    3741             :   nsIDocument::DeprecatedOperations mOperation;
    3742             : 
    3743             : public:
    3744           0 :   DeprecationWarningRunnable(WorkerPrivate* aWorkerPrivate,
    3745             :                              nsIDocument::DeprecatedOperations aOperation)
    3746           0 :     : WorkerProxyToMainThreadRunnable(aWorkerPrivate)
    3747           0 :     , mOperation(aOperation)
    3748             :   {
    3749           0 :     MOZ_ASSERT(aWorkerPrivate);
    3750           0 :     aWorkerPrivate->AssertIsOnWorkerThread();
    3751           0 :   }
    3752             : 
    3753             : private:
    3754             :   void
    3755           0 :   RunOnMainThread() override
    3756             :   {
    3757           0 :     MOZ_ASSERT(NS_IsMainThread());
    3758             : 
    3759             :     // Walk up to our containing page
    3760           0 :     WorkerPrivate* wp = mWorkerPrivate;
    3761           0 :     while (wp->GetParent()) {
    3762           0 :       wp = wp->GetParent();
    3763             :     }
    3764             : 
    3765           0 :     nsPIDOMWindowInner* window = wp->GetWindow();
    3766           0 :     if (window && window->GetExtantDoc()) {
    3767           0 :       window->GetExtantDoc()->WarnOnceAbout(mOperation);
    3768             :     }
    3769           0 :   }
    3770             : 
    3771             :   void
    3772           0 :   RunBackOnWorkerThreadForCleanup() override
    3773           0 :   {}
    3774             : };
    3775             : 
    3776             : } // anonymous namespace
    3777             : 
    3778             : void
    3779           0 : DeprecationWarning(JSContext* aCx, JSObject* aObject,
    3780             :                    nsIDocument::DeprecatedOperations aOperation)
    3781             : {
    3782           0 :   GlobalObject global(aCx, aObject);
    3783           0 :   if (global.Failed()) {
    3784           0 :     NS_ERROR("Could not create global for DeprecationWarning");
    3785           0 :     return;
    3786             :   }
    3787             : 
    3788           0 :   DeprecationWarning(global, aOperation);
    3789             : }
    3790             : 
    3791             : void
    3792           0 : DeprecationWarning(const GlobalObject& aGlobal,
    3793             :                    nsIDocument::DeprecatedOperations aOperation)
    3794             : {
    3795           0 :   if (NS_IsMainThread()) {
    3796           0 :     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
    3797           0 :     if (window && window->GetExtantDoc()) {
    3798           0 :       window->GetExtantDoc()->WarnOnceAbout(aOperation);
    3799             :     }
    3800             : 
    3801           0 :     return;
    3802             :   }
    3803             : 
    3804           0 :   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aGlobal.Context());
    3805           0 :   if (!workerPrivate) {
    3806           0 :     return;
    3807             :   }
    3808             : 
    3809             :   RefPtr<DeprecationWarningRunnable> runnable =
    3810           0 :     new DeprecationWarningRunnable(workerPrivate, aOperation);
    3811           0 :   runnable->Dispatch();
    3812             : }
    3813             : 
    3814             : namespace binding_detail {
    3815             : JSObject*
    3816           0 : UnprivilegedJunkScopeOrWorkerGlobal()
    3817             : {
    3818           0 :   if (NS_IsMainThread()) {
    3819           0 :     return xpc::UnprivilegedJunkScope();
    3820             :   }
    3821             : 
    3822           0 :   return GetCurrentThreadWorkerGlobal();
    3823             : }
    3824             : } // namespace binding_detail
    3825             : 
    3826             : } // namespace dom
    3827             : } // namespace mozilla

Generated by: LCOV version 1.13