tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsJSEnvironment.cpp (71773B)


      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
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "nsJSEnvironment.h"
      8 
      9 #include "mozilla/EventDispatcher.h"
     10 #include "mozilla/HoldDropJSObjects.h"
     11 #include "nsAtom.h"
     12 #include "nsCOMPtr.h"
     13 #include "nsContentUtils.h"
     14 #include "nsCycleCollector.h"
     15 #include "nsDOMCID.h"
     16 #include "nsDOMJSUtils.h"
     17 #include "nsError.h"
     18 #include "nsIConsoleService.h"
     19 #include "nsIContent.h"
     20 #include "nsIDocShell.h"
     21 #include "nsIDocShellTreeItem.h"
     22 #include "nsIInterfaceRequestor.h"
     23 #include "nsIInterfaceRequestorUtils.h"
     24 #include "nsIObserverService.h"
     25 #include "nsIScriptGlobalObject.h"
     26 #include "nsIScriptObjectPrincipal.h"
     27 #include "nsISupportsPrimitives.h"
     28 #include "nsITimer.h"
     29 #include "nsIXPConnect.h"
     30 #include "nsJSUtils.h"
     31 #include "nsPIDOMWindow.h"
     32 #include "nsPresContext.h"
     33 #include "nsReadableUtils.h"
     34 #include "nsServiceManagerUtils.h"
     35 #include "nsTextFormatter.h"
     36 #include "nsXPCOMCIDInternal.h"
     37 #ifdef XP_WIN
     38 #  include <process.h>
     39 #  define getpid _getpid
     40 #else
     41 #  include <unistd.h>  // for getpid()
     42 #endif
     43 #include "AccessCheck.h"
     44 #include "CCGCScheduler.h"
     45 #include "WrapperFactory.h"
     46 #include "js/Array.h"               // JS::NewArrayObject
     47 #include "js/PropertyAndElement.h"  // JS_DefineProperty
     48 #include "js/PropertySpec.h"
     49 #include "js/SliceBudget.h"
     50 #include "js/Wrapper.h"
     51 #include "jsapi.h"
     52 #include "mozilla/Attributes.h"
     53 #include "mozilla/AutoRestore.h"
     54 #include "mozilla/BasePrincipal.h"
     55 #include "mozilla/ContentEvents.h"
     56 #include "mozilla/CycleCollectedJSContext.h"
     57 #include "mozilla/CycleCollectedJSRuntime.h"
     58 #include "mozilla/CycleCollectorStats.h"
     59 #include "mozilla/EventStateManager.h"
     60 #include "mozilla/Logging.h"
     61 #include "mozilla/MainThreadIdlePeriod.h"
     62 #include "mozilla/Preferences.h"
     63 #include "mozilla/PresShell.h"
     64 #include "mozilla/ProfilerLabels.h"
     65 #include "mozilla/ProfilerMarkers.h"
     66 #include "mozilla/SchedulerGroup.h"
     67 #include "mozilla/StaticPrefs_dom.h"
     68 #include "mozilla/StaticPrefs_javascript.h"
     69 #include "mozilla/StaticPtr.h"
     70 #include "mozilla/dom/BindingUtils.h"
     71 #include "mozilla/dom/BrowsingContext.h"
     72 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
     73 #include "mozilla/dom/DOMException.h"
     74 #include "mozilla/dom/DOMExceptionBinding.h"
     75 #include "mozilla/dom/Element.h"
     76 #include "mozilla/dom/ErrorEvent.h"
     77 #include "mozilla/dom/FetchUtil.h"
     78 #include "mozilla/dom/RootedDictionary.h"
     79 #include "mozilla/dom/ScriptSettings.h"
     80 #include "mozilla/dom/SerializedStackHolder.h"
     81 #include "mozilla/dom/TimeoutHandler.h"
     82 #include "mozilla/dom/TimeoutManager.h"
     83 #include "mozilla/glean/DomMetrics.h"
     84 #include "nsCycleCollectionNoteRootCallback.h"
     85 #include "nsGlobalWindowInner.h"
     86 #include "nsGlobalWindowOuter.h"
     87 #include "nsIArray.h"
     88 #include "nsJSPrincipals.h"
     89 #include "nsRefreshDriver.h"
     90 #include "prthread.h"
     91 #include "xpcpublic.h"
     92 #if defined(MOZ_MEMORY)
     93 #  include "mozmemory.h"
     94 #endif
     95 
     96 using namespace mozilla;
     97 using namespace mozilla::dom;
     98 
     99 // Thank you Microsoft!
    100 #ifdef CompareString
    101 #  undef CompareString
    102 #endif
    103 
    104 static JS::GCSliceCallback sPrevGCSliceCallback;
    105 
    106 static bool sIncrementalCC = false;
    107 
    108 static bool sIsInitialized;
    109 static bool sShuttingDown;
    110 
    111 static CCGCScheduler* sScheduler = nullptr;
    112 static std::aligned_storage_t<sizeof(*sScheduler)> sSchedulerStorage;
    113 
    114 // Cache a pointer to the main thread's statistics struct.
    115 static CycleCollectorStats* sCCStats = nullptr;
    116 
    117 static const char* ProcessNameForCollectorLog() {
    118  return XRE_GetProcessType() == GeckoProcessType_Default ? "default"
    119                                                          : "content";
    120 }
    121 
    122 namespace xpc {
    123 
    124 // This handles JS Exceptions (via ExceptionStackOrNull), DOM and XPC
    125 // Exceptions, and arbitrary values that were associated with a stack by the
    126 // JS engine when they were thrown, as specified by exceptionStack.
    127 //
    128 // Note that the returned stackObj and stackGlobal are _not_ wrapped into the
    129 // compartment of exceptionValue.
    130 void FindExceptionStackForConsoleReport(
    131    nsPIDOMWindowInner* win, JS::Handle<JS::Value> exceptionValue,
    132    JS::Handle<JSObject*> exceptionStack, JS::MutableHandle<JSObject*> stackObj,
    133    JS::MutableHandle<JSObject*> stackGlobal) {
    134  stackObj.set(nullptr);
    135  stackGlobal.set(nullptr);
    136 
    137  if (!exceptionValue.isObject()) {
    138    // Use the stack provided by the JS engine, if available. This will not be
    139    // a wrapper.
    140    if (exceptionStack) {
    141      stackObj.set(exceptionStack);
    142      stackGlobal.set(JS::GetNonCCWObjectGlobal(exceptionStack));
    143    }
    144    return;
    145  }
    146 
    147  if (win && win->AsGlobal()->IsDying()) {
    148    // Pretend like we have no stack, so we don't end up keeping the global
    149    // alive via the stack.
    150    return;
    151  }
    152 
    153  JS::RootingContext* rcx = RootingCx();
    154  JS::Rooted<JSObject*> exceptionObject(rcx, &exceptionValue.toObject());
    155  if (JSObject* excStack = JS::ExceptionStackOrNull(exceptionObject)) {
    156    // At this point we know exceptionObject is a possibly-wrapped
    157    // js::ErrorObject that has excStack as stack. excStack might also be a CCW,
    158    // but excStack must be same-compartment with the unwrapped ErrorObject.
    159    // Return the ErrorObject's global as stackGlobal. This matches what we do
    160    // in the ErrorObject's |.stack| getter and ensures stackObj and stackGlobal
    161    // are same-compartment.
    162    JSObject* unwrappedException = js::UncheckedUnwrap(exceptionObject);
    163    stackObj.set(excStack);
    164    stackGlobal.set(JS::GetNonCCWObjectGlobal(unwrappedException));
    165    return;
    166  }
    167 
    168  // It is not a JS Exception, try DOM Exception.
    169  RefPtr<Exception> exception;
    170  UNWRAP_OBJECT(DOMException, exceptionObject, exception);
    171  if (!exception) {
    172    // Not a DOM Exception, try XPC Exception.
    173    UNWRAP_OBJECT(Exception, exceptionObject, exception);
    174    if (!exception) {
    175      // As above, use the stack provided by the JS engine, if available.
    176      if (exceptionStack) {
    177        stackObj.set(exceptionStack);
    178        stackGlobal.set(JS::GetNonCCWObjectGlobal(exceptionStack));
    179      }
    180      return;
    181    }
    182  }
    183 
    184  nsCOMPtr<nsIStackFrame> stack = exception->GetLocation();
    185  if (!stack) {
    186    return;
    187  }
    188  JS::Rooted<JS::Value> value(rcx);
    189  stack->GetNativeSavedFrame(&value);
    190  if (value.isObject()) {
    191    stackObj.set(&value.toObject());
    192    MOZ_ASSERT(JS::IsUnwrappedSavedFrame(stackObj));
    193    stackGlobal.set(JS::GetNonCCWObjectGlobal(stackObj));
    194    return;
    195  }
    196 }
    197 
    198 } /* namespace xpc */
    199 
    200 static TimeDuration GetCollectionTimeDelta() {
    201  static TimeStamp sFirstCollectionTime;
    202  TimeStamp now = TimeStamp::Now();
    203  if (sFirstCollectionTime) {
    204    return now - sFirstCollectionTime;
    205  }
    206  sFirstCollectionTime = now;
    207  return TimeDuration();
    208 }
    209 
    210 class nsJSEnvironmentObserver final : public nsIObserver {
    211  ~nsJSEnvironmentObserver() = default;
    212 
    213 public:
    214  NS_DECL_ISUPPORTS
    215  NS_DECL_NSIOBSERVER
    216 };
    217 
    218 NS_IMPL_ISUPPORTS(nsJSEnvironmentObserver, nsIObserver)
    219 
    220 NS_IMETHODIMP
    221 nsJSEnvironmentObserver::Observe(nsISupports* aSubject, const char* aTopic,
    222                                 const char16_t* aData) {
    223  if (!nsCRT::strcmp(aTopic, "memory-pressure")) {
    224    if (StaticPrefs::javascript_options_gc_on_memory_pressure()) {
    225      if (sShuttingDown) {
    226        // Don't GC/CC if we're already shutting down.
    227        return NS_OK;
    228      }
    229      nsDependentString data(aData);
    230      if (data.EqualsLiteral("low-memory-ongoing")) {
    231        // Don't GC/CC if we are in an ongoing low-memory state since its very
    232        // slow and it likely won't help us anyway.
    233        return NS_OK;
    234      }
    235      if (data.EqualsLiteral("heap-minimize")) {
    236        // heap-minimize notifiers expect this to run synchronously
    237        nsJSContext::DoLowMemoryGC();
    238        return NS_OK;
    239      }
    240      if (data.EqualsLiteral("low-memory")) {
    241        nsJSContext::SetLowMemoryState(true);
    242      }
    243      // Asynchronously GC.
    244      nsJSContext::LowMemoryGC();
    245    }
    246  } else if (!nsCRT::strcmp(aTopic, "memory-pressure-stop")) {
    247    nsJSContext::SetLowMemoryState(false);
    248  } else if (!nsCRT::strcmp(aTopic, "user-interaction-inactive")) {
    249    sScheduler->UserIsInactive();
    250  } else if (!nsCRT::strcmp(aTopic, "user-interaction-active")) {
    251    sScheduler->UserIsActive();
    252  } else if (!nsCRT::strcmp(aTopic, "quit-application") ||
    253             !nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) ||
    254             !nsCRT::strcmp(aTopic, "content-child-will-shutdown")) {
    255    sShuttingDown = true;
    256    sScheduler->Shutdown();
    257  }
    258 
    259  return NS_OK;
    260 }
    261 
    262 /****************************************************************
    263 ************************** AutoFree ****************************
    264 ****************************************************************/
    265 
    266 class AutoFree {
    267 public:
    268  explicit AutoFree(void* aPtr) : mPtr(aPtr) {}
    269  ~AutoFree() {
    270    if (mPtr) free(mPtr);
    271  }
    272  void Invalidate() { mPtr = nullptr; }
    273 
    274 private:
    275  void* mPtr;
    276 };
    277 
    278 // A utility function for script languages to call.  Although it looks small,
    279 // the use of nsIDocShell and nsPresContext triggers a huge number of
    280 // dependencies that most languages would not otherwise need.
    281 // XXXmarkh - This function is mis-placed!
    282 bool NS_HandleScriptError(nsIScriptGlobalObject* aScriptGlobal,
    283                          const ErrorEventInit& aErrorEventInit,
    284                          nsEventStatus* aStatus) {
    285  bool called = false;
    286  nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aScriptGlobal));
    287  nsIDocShell* docShell = win ? win->GetDocShell() : nullptr;
    288  if (docShell) {
    289    RefPtr<nsPresContext> presContext = docShell->GetPresContext();
    290 
    291    static int32_t errorDepth;  // Recursion prevention
    292    ++errorDepth;
    293 
    294    if (errorDepth < 2) {
    295      // Dispatch() must be synchronous for the recursion block
    296      // (errorDepth) to work.
    297      RefPtr<ErrorEvent> event = ErrorEvent::Constructor(
    298          nsGlobalWindowInner::Cast(win), u"error"_ns, aErrorEventInit);
    299      event->SetTrusted(true);
    300 
    301      // MOZ_KnownLive due to bug 1506441
    302      EventDispatcher::DispatchDOMEvent(
    303          MOZ_KnownLive(nsGlobalWindowInner::Cast(win)), nullptr, event,
    304          presContext, aStatus);
    305      called = true;
    306    }
    307    --errorDepth;
    308  }
    309  return called;
    310 }
    311 
    312 class ScriptErrorEvent : public Runnable {
    313 public:
    314  ScriptErrorEvent(nsPIDOMWindowInner* aWindow, JS::RootingContext* aRootingCx,
    315                   xpc::ErrorReport* aReport, JS::Handle<JS::Value> aError,
    316                   JS::Handle<JSObject*> aErrorStack)
    317      : mozilla::Runnable("ScriptErrorEvent"),
    318        mWindow(aWindow),
    319        mReport(aReport),
    320        mError(aRootingCx, aError),
    321        mErrorStack(aRootingCx, aErrorStack) {}
    322 
    323  // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230, bug 1535398)
    324  MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
    325    nsEventStatus status = nsEventStatus_eIgnore;
    326    nsCOMPtr<nsPIDOMWindowInner> win = mWindow;
    327    MOZ_ASSERT(win);
    328    MOZ_ASSERT(NS_IsMainThread());
    329    // First, notify the DOM that we have a script error, but only if
    330    // our window is still the current inner.
    331    JS::RootingContext* rootingCx = RootingCx();
    332    if (win->IsCurrentInnerWindow() && win->GetDocShell() &&
    333        !sHandlingScriptError) {
    334      AutoRestore<bool> recursionGuard(sHandlingScriptError);
    335      sHandlingScriptError = true;
    336 
    337      RefPtr<nsPresContext> presContext = win->GetDocShell()->GetPresContext();
    338 
    339      RootedDictionary<ErrorEventInit> init(rootingCx);
    340      init.mCancelable = true;
    341      init.mFilename = mReport->mFileName;
    342      init.mBubbles = true;
    343 
    344      constexpr auto xoriginMsg = u"Script error."_ns;
    345      if (!mReport->mIsMuted) {
    346        init.mMessage = mReport->mErrorMsg;
    347        init.mLineno = mReport->mLineNumber;
    348        init.mColno = mReport->mColumn;
    349        init.mError = mError;
    350      } else {
    351        NS_WARNING("Not same origin error!");
    352        init.mMessage = xoriginMsg;
    353        init.mLineno = 0;
    354      }
    355 
    356      RefPtr<ErrorEvent> event = ErrorEvent::Constructor(
    357          nsGlobalWindowInner::Cast(win), u"error"_ns, init);
    358      event->SetTrusted(true);
    359 
    360      // MOZ_KnownLive due to bug 1506441
    361      EventDispatcher::DispatchDOMEvent(
    362          MOZ_KnownLive(nsGlobalWindowInner::Cast(win)), nullptr, event,
    363          presContext, &status);
    364    }
    365 
    366    if (status != nsEventStatus_eConsumeNoDefault) {
    367      JS::Rooted<JSObject*> stack(rootingCx);
    368      JS::Rooted<JSObject*> stackGlobal(rootingCx);
    369      xpc::FindExceptionStackForConsoleReport(win, mError, mErrorStack, &stack,
    370                                              &stackGlobal);
    371      JS::Rooted<Maybe<JS::Value>> exception(rootingCx, Some(mError));
    372      nsGlobalWindowInner* inner = nsGlobalWindowInner::Cast(win);
    373      mReport->LogToConsoleWithStack(inner, exception, stack, stackGlobal);
    374    }
    375 
    376    return NS_OK;
    377  }
    378 
    379 private:
    380  nsCOMPtr<nsPIDOMWindowInner> mWindow;
    381  RefPtr<xpc::ErrorReport> mReport;
    382  JS::PersistentRooted<JS::Value> mError;
    383  JS::PersistentRooted<JSObject*> mErrorStack;
    384 
    385  static bool sHandlingScriptError;
    386 };
    387 
    388 bool ScriptErrorEvent::sHandlingScriptError = false;
    389 
    390 // This temporarily lives here to avoid code churn. It will go away entirely
    391 // soon.
    392 namespace xpc {
    393 
    394 void DispatchScriptErrorEvent(nsPIDOMWindowInner* win,
    395                              JS::RootingContext* rootingCx,
    396                              xpc::ErrorReport* xpcReport,
    397                              JS::Handle<JS::Value> exception,
    398                              JS::Handle<JSObject*> exceptionStack) {
    399  nsContentUtils::AddScriptRunner(new ScriptErrorEvent(
    400      win, rootingCx, xpcReport, exception, exceptionStack));
    401 }
    402 
    403 } /* namespace xpc */
    404 
    405 #ifdef DEBUG
    406 // A couple of useful functions to call when you're debugging.
    407 nsGlobalWindowInner* JSObject2Win(JSObject* obj) {
    408  return xpc::WindowOrNull(obj);
    409 }
    410 
    411 template <typename T>
    412 void PrintWinURI(T* win) {
    413  if (!win) {
    414    printf("No window passed in.\n");
    415    return;
    416  }
    417 
    418  nsCOMPtr<Document> doc = win->GetExtantDoc();
    419  if (!doc) {
    420    printf("No document in the window.\n");
    421    return;
    422  }
    423 
    424  nsIURI* uri = doc->GetDocumentURI();
    425  if (!uri) {
    426    printf("Document doesn't have a URI.\n");
    427    return;
    428  }
    429 
    430  printf("%s\n", uri->GetSpecOrDefault().get());
    431 }
    432 
    433 void PrintWinURIInner(nsGlobalWindowInner* aWin) { return PrintWinURI(aWin); }
    434 
    435 void PrintWinURIOuter(nsGlobalWindowOuter* aWin) { return PrintWinURI(aWin); }
    436 
    437 template <typename T>
    438 void PrintWinCodebase(T* win) {
    439  if (!win) {
    440    printf("No window passed in.\n");
    441    return;
    442  }
    443 
    444  nsIPrincipal* prin = win->GetPrincipal();
    445  if (!prin) {
    446    printf("Window doesn't have principals.\n");
    447    return;
    448  }
    449  if (prin->IsSystemPrincipal()) {
    450    printf("No URI, it's the system principal.\n");
    451    return;
    452  }
    453  nsCString spec;
    454  prin->GetAsciiSpec(spec);
    455  printf("%s\n", spec.get());
    456 }
    457 
    458 void PrintWinCodebaseInner(nsGlobalWindowInner* aWin) {
    459  return PrintWinCodebase(aWin);
    460 }
    461 
    462 void PrintWinCodebaseOuter(nsGlobalWindowOuter* aWin) {
    463  return PrintWinCodebase(aWin);
    464 }
    465 
    466 void DumpString(const nsAString& str) {
    467  printf("%s\n", NS_ConvertUTF16toUTF8(str).get());
    468 }
    469 #endif
    470 
    471 nsJSContext::nsJSContext(bool aGCOnDestruction,
    472                         nsIScriptGlobalObject* aGlobalObject)
    473    : mWindowProxy(nullptr),
    474      mGCOnDestruction(aGCOnDestruction),
    475      mGlobalObjectRef(aGlobalObject) {
    476  EnsureStatics();
    477 
    478  mProcessingScriptTag = false;
    479  HoldJSObjects(this);
    480 }
    481 
    482 nsJSContext::~nsJSContext() {
    483  mGlobalObjectRef = nullptr;
    484 
    485  Destroy();
    486 }
    487 
    488 void nsJSContext::Destroy() {
    489  if (mGCOnDestruction) {
    490    sScheduler->PokeGC(JS::GCReason::NSJSCONTEXT_DESTROY, mWindowProxy);
    491  }
    492 
    493  DropJSObjects(this);
    494 }
    495 
    496 // QueryInterface implementation for nsJSContext
    497 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSContext)
    498 
    499 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSContext)
    500  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mWindowProxy)
    501 NS_IMPL_CYCLE_COLLECTION_TRACE_END
    502 
    503 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSContext)
    504  tmp->mGCOnDestruction = false;
    505  tmp->mWindowProxy = nullptr;
    506  tmp->Destroy();
    507  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobalObjectRef)
    508 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    509 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSContext)
    510  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobalObjectRef)
    511 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    512 
    513 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext)
    514  NS_INTERFACE_MAP_ENTRY(nsIScriptContext)
    515  NS_INTERFACE_MAP_ENTRY(nsISupports)
    516 NS_INTERFACE_MAP_END
    517 
    518 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSContext)
    519 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSContext)
    520 
    521 #ifdef DEBUG
    522 bool AtomIsEventHandlerName(nsAtom* aName) {
    523  const char16_t* name = aName->GetUTF16String();
    524 
    525  const char16_t* cp;
    526  char16_t c;
    527  for (cp = name; *cp != '\0'; ++cp) {
    528    c = *cp;
    529    if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) return false;
    530  }
    531 
    532  return true;
    533 }
    534 #endif
    535 
    536 nsIScriptGlobalObject* nsJSContext::GetGlobalObject() {
    537  // Note: this could probably be simplified somewhat more; see bug 974327
    538  // comments 1 and 3.
    539  if (!mWindowProxy) {
    540    return nullptr;
    541  }
    542 
    543  MOZ_ASSERT(mGlobalObjectRef);
    544  return mGlobalObjectRef;
    545 }
    546 
    547 nsresult nsJSContext::SetProperty(JS::Handle<JSObject*> aTarget,
    548                                  const char* aPropName, nsISupports* aArgs) {
    549  AutoJSAPI jsapi;
    550  if (NS_WARN_IF(!jsapi.Init(GetGlobalObject()))) {
    551    return NS_ERROR_FAILURE;
    552  }
    553  JSContext* cx = jsapi.cx();
    554 
    555  JS::RootedVector<JS::Value> args(cx);
    556 
    557  JS::Rooted<JSObject*> global(cx, GetWindowProxy());
    558  nsresult rv = ConvertSupportsTojsvals(cx, aArgs, global, &args);
    559  NS_ENSURE_SUCCESS(rv, rv);
    560 
    561  // got the arguments, now attach them.
    562 
    563  for (uint32_t i = 0; i < args.length(); ++i) {
    564    if (!JS_WrapValue(cx, args[i])) {
    565      return NS_ERROR_FAILURE;
    566    }
    567  }
    568 
    569  JS::Rooted<JSObject*> array(cx, JS::NewArrayObject(cx, args));
    570  if (!array) {
    571    return NS_ERROR_FAILURE;
    572  }
    573 
    574  return JS_DefineProperty(cx, aTarget, aPropName, array, 0) ? NS_OK
    575                                                             : NS_ERROR_FAILURE;
    576 }
    577 
    578 nsresult nsJSContext::ConvertSupportsTojsvals(
    579    JSContext* aCx, nsISupports* aArgs, JS::Handle<JSObject*> aScope,
    580    JS::MutableHandleVector<JS::Value> aArgsOut) {
    581  nsresult rv = NS_OK;
    582 
    583  // If the array implements nsIJSArgArray, copy the contents and return.
    584  nsCOMPtr<nsIJSArgArray> fastArray = do_QueryInterface(aArgs);
    585  if (fastArray) {
    586    uint32_t argc;
    587    JS::Value* argv;
    588    rv = fastArray->GetArgs(&argc, reinterpret_cast<void**>(&argv));
    589    if (NS_SUCCEEDED(rv) && !aArgsOut.append(argv, argc)) {
    590      rv = NS_ERROR_OUT_OF_MEMORY;
    591    }
    592    return rv;
    593  }
    594 
    595  // Take the slower path converting each item.
    596  // Handle only nsIArray and nsIVariant.  nsIArray is only needed for
    597  // SetProperty('arguments', ...);
    598 
    599  nsIXPConnect* xpc = nsContentUtils::XPConnect();
    600  NS_ENSURE_TRUE(xpc, NS_ERROR_UNEXPECTED);
    601 
    602  if (!aArgs) return NS_OK;
    603  uint32_t argCount;
    604  // This general purpose function may need to convert an arg array
    605  // (window.arguments, event-handler args) and a generic property.
    606  nsCOMPtr<nsIArray> argsArray(do_QueryInterface(aArgs));
    607 
    608  if (argsArray) {
    609    rv = argsArray->GetLength(&argCount);
    610    NS_ENSURE_SUCCESS(rv, rv);
    611    if (argCount == 0) return NS_OK;
    612  } else {
    613    argCount = 1;  // the nsISupports which is not an array
    614  }
    615 
    616  // Use the caller's auto guards to release and unroot.
    617  if (!aArgsOut.resize(argCount)) {
    618    return NS_ERROR_OUT_OF_MEMORY;
    619  }
    620 
    621  if (argsArray) {
    622    for (uint32_t argCtr = 0; argCtr < argCount && NS_SUCCEEDED(rv); argCtr++) {
    623      nsCOMPtr<nsISupports> arg;
    624      JS::MutableHandle<JS::Value> thisVal = aArgsOut[argCtr];
    625      argsArray->QueryElementAt(argCtr, NS_GET_IID(nsISupports),
    626                                getter_AddRefs(arg));
    627      if (!arg) {
    628        thisVal.setNull();
    629        continue;
    630      }
    631      nsCOMPtr<nsIVariant> variant(do_QueryInterface(arg));
    632      if (variant != nullptr) {
    633        rv = xpc->VariantToJS(aCx, aScope, variant, thisVal);
    634      } else {
    635        // And finally, support the nsISupportsPrimitives supplied
    636        // by the AppShell.  It generally will pass only strings, but
    637        // as we have code for handling all, we may as well use it.
    638        rv = AddSupportsPrimitiveTojsvals(aCx, arg, thisVal.address());
    639        if (rv == NS_ERROR_NO_INTERFACE) {
    640          // something else - probably an event object or similar -
    641          // just wrap it.
    642 #ifdef DEBUG
    643          // but first, check its not another nsISupportsPrimitive, as
    644          // these are now deprecated for use with script contexts.
    645          nsCOMPtr<nsISupportsPrimitive> prim(do_QueryInterface(arg));
    646          NS_ASSERTION(prim == nullptr,
    647                       "Don't pass nsISupportsPrimitives - use nsIVariant!");
    648 #endif
    649          JSAutoRealm ar(aCx, aScope);
    650          rv = nsContentUtils::WrapNative(aCx, arg, thisVal);
    651        }
    652      }
    653    }
    654  } else {
    655    nsCOMPtr<nsIVariant> variant = do_QueryInterface(aArgs);
    656    if (variant) {
    657      rv = xpc->VariantToJS(aCx, aScope, variant, aArgsOut[0]);
    658    } else {
    659      NS_ERROR("Not an array, not an interface?");
    660      rv = NS_ERROR_UNEXPECTED;
    661    }
    662  }
    663  return rv;
    664 }
    665 
    666 // This really should go into xpconnect somewhere...
    667 nsresult nsJSContext::AddSupportsPrimitiveTojsvals(JSContext* aCx,
    668                                                   nsISupports* aArg,
    669                                                   JS::Value* aArgv) {
    670  MOZ_ASSERT(aArg, "Empty arg");
    671 
    672  nsCOMPtr<nsISupportsPrimitive> argPrimitive(do_QueryInterface(aArg));
    673  if (!argPrimitive) return NS_ERROR_NO_INTERFACE;
    674 
    675  uint16_t type;
    676  argPrimitive->GetType(&type);
    677 
    678  switch (type) {
    679    case nsISupportsPrimitive::TYPE_CSTRING: {
    680      nsCOMPtr<nsISupportsCString> p(do_QueryInterface(argPrimitive));
    681      NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    682 
    683      nsAutoCString data;
    684 
    685      p->GetData(data);
    686 
    687      JSString* str = ::JS_NewStringCopyN(aCx, data.get(), data.Length());
    688      NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
    689 
    690      aArgv->setString(str);
    691 
    692      break;
    693    }
    694    case nsISupportsPrimitive::TYPE_STRING: {
    695      nsCOMPtr<nsISupportsString> p(do_QueryInterface(argPrimitive));
    696      NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    697 
    698      nsAutoString data;
    699 
    700      p->GetData(data);
    701 
    702      // cast is probably safe since wchar_t and char16_t are expected
    703      // to be equivalent; both unsigned 16-bit entities
    704      JSString* str = ::JS_NewUCStringCopyN(aCx, data.get(), data.Length());
    705      NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
    706 
    707      aArgv->setString(str);
    708      break;
    709    }
    710    case nsISupportsPrimitive::TYPE_PRBOOL: {
    711      nsCOMPtr<nsISupportsPRBool> p(do_QueryInterface(argPrimitive));
    712      NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    713 
    714      bool data;
    715 
    716      p->GetData(&data);
    717 
    718      aArgv->setBoolean(data);
    719 
    720      break;
    721    }
    722    case nsISupportsPrimitive::TYPE_PRUINT8: {
    723      nsCOMPtr<nsISupportsPRUint8> p(do_QueryInterface(argPrimitive));
    724      NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    725 
    726      uint8_t data;
    727 
    728      p->GetData(&data);
    729 
    730      aArgv->setInt32(data);
    731 
    732      break;
    733    }
    734    case nsISupportsPrimitive::TYPE_PRUINT16: {
    735      nsCOMPtr<nsISupportsPRUint16> p(do_QueryInterface(argPrimitive));
    736      NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    737 
    738      uint16_t data;
    739 
    740      p->GetData(&data);
    741 
    742      aArgv->setInt32(data);
    743 
    744      break;
    745    }
    746    case nsISupportsPrimitive::TYPE_PRUINT32: {
    747      nsCOMPtr<nsISupportsPRUint32> p(do_QueryInterface(argPrimitive));
    748      NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    749 
    750      uint32_t data;
    751 
    752      p->GetData(&data);
    753 
    754      aArgv->setInt32(data);
    755 
    756      break;
    757    }
    758    case nsISupportsPrimitive::TYPE_CHAR: {
    759      nsCOMPtr<nsISupportsChar> p(do_QueryInterface(argPrimitive));
    760      NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    761 
    762      char data;
    763 
    764      p->GetData(&data);
    765 
    766      JSString* str = ::JS_NewStringCopyN(aCx, &data, 1);
    767      NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
    768 
    769      aArgv->setString(str);
    770 
    771      break;
    772    }
    773    case nsISupportsPrimitive::TYPE_PRINT16: {
    774      nsCOMPtr<nsISupportsPRInt16> p(do_QueryInterface(argPrimitive));
    775      NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    776 
    777      int16_t data;
    778 
    779      p->GetData(&data);
    780 
    781      aArgv->setInt32(data);
    782 
    783      break;
    784    }
    785    case nsISupportsPrimitive::TYPE_PRINT32: {
    786      nsCOMPtr<nsISupportsPRInt32> p(do_QueryInterface(argPrimitive));
    787      NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    788 
    789      int32_t data;
    790 
    791      p->GetData(&data);
    792 
    793      aArgv->setInt32(data);
    794 
    795      break;
    796    }
    797    case nsISupportsPrimitive::TYPE_FLOAT: {
    798      nsCOMPtr<nsISupportsFloat> p(do_QueryInterface(argPrimitive));
    799      NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    800 
    801      float data;
    802 
    803      p->GetData(&data);
    804 
    805      *aArgv = ::JS_NumberValue(data);
    806 
    807      break;
    808    }
    809    case nsISupportsPrimitive::TYPE_DOUBLE: {
    810      nsCOMPtr<nsISupportsDouble> p(do_QueryInterface(argPrimitive));
    811      NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    812 
    813      double data;
    814 
    815      p->GetData(&data);
    816 
    817      *aArgv = ::JS_NumberValue(data);
    818 
    819      break;
    820    }
    821    case nsISupportsPrimitive::TYPE_INTERFACE_POINTER: {
    822      nsCOMPtr<nsISupportsInterfacePointer> p(do_QueryInterface(argPrimitive));
    823      NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    824 
    825      nsCOMPtr<nsISupports> data;
    826      nsIID* iid = nullptr;
    827 
    828      p->GetData(getter_AddRefs(data));
    829      p->GetDataIID(&iid);
    830      NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
    831 
    832      AutoFree iidGuard(iid);  // Free iid upon destruction.
    833 
    834      JS::Rooted<JSObject*> scope(aCx, GetWindowProxy());
    835      JS::Rooted<JS::Value> v(aCx);
    836      JSAutoRealm ar(aCx, scope);
    837      nsresult rv = nsContentUtils::WrapNative(aCx, data, iid, &v);
    838      NS_ENSURE_SUCCESS(rv, rv);
    839 
    840      *aArgv = v;
    841 
    842      break;
    843    }
    844    case nsISupportsPrimitive::TYPE_ID:
    845    case nsISupportsPrimitive::TYPE_PRUINT64:
    846    case nsISupportsPrimitive::TYPE_PRINT64:
    847    case nsISupportsPrimitive::TYPE_PRTIME: {
    848      NS_WARNING("Unsupported primitive type used");
    849      aArgv->setNull();
    850      break;
    851    }
    852    default: {
    853      NS_WARNING("Unknown primitive type used");
    854      aArgv->setNull();
    855      break;
    856    }
    857  }
    858  return NS_OK;
    859 }
    860 
    861 nsresult nsJSContext::InitClasses(JS::Handle<JSObject*> aGlobalObj) {
    862  AutoJSAPI jsapi;
    863  jsapi.Init();
    864  JSContext* cx = jsapi.cx();
    865  JSAutoRealm ar(cx, aGlobalObj);
    866 
    867  return NS_OK;
    868 }
    869 
    870 bool nsJSContext::GetProcessingScriptTag() { return mProcessingScriptTag; }
    871 
    872 void nsJSContext::SetProcessingScriptTag(bool aFlag) {
    873  mProcessingScriptTag = aFlag;
    874 }
    875 
    876 // static
    877 void nsJSContext::SetLowMemoryState(bool aState) {
    878  JSContext* cx = danger::GetJSContext();
    879  JS::SetLowMemoryState(cx, aState);
    880 }
    881 
    882 static void GarbageCollectImpl(JS::GCReason aReason,
    883                               nsJSContext::IsShrinking aShrinking,
    884                               const JS::SliceBudget& aBudget) {
    885  AUTO_PROFILER_LABEL_DYNAMIC_CSTR_NONSENSITIVE(
    886      "nsJSContext::GarbageCollectNow", GCCC, JS::ExplainGCReason(aReason));
    887 
    888  bool wantIncremental = !aBudget.isUnlimited();
    889 
    890  // We use danger::GetJSContext() since AutoJSAPI will assert if the current
    891  // thread's context is null (such as during shutdown).
    892  JSContext* cx = danger::GetJSContext();
    893 
    894  if (!nsContentUtils::XPConnect() || !cx) {
    895    return;
    896  }
    897 
    898  if (sScheduler->InIncrementalGC() && wantIncremental) {
    899    // We're in the middle of incremental GC. Do another slice.
    900    JS::PrepareForIncrementalGC(cx);
    901    JS::IncrementalGCSlice(cx, aReason, aBudget);
    902    return;
    903  }
    904 
    905  JS::GCOptions options = aShrinking == nsJSContext::ShrinkingGC
    906                              ? JS::GCOptions::Shrink
    907                              : JS::GCOptions::Normal;
    908 
    909  if (!wantIncremental || aReason == JS::GCReason::FULL_GC_TIMER) {
    910    sScheduler->SetNeedsFullGC();
    911  }
    912 
    913  if (sScheduler->NeedsFullGC()) {
    914    JS::PrepareForFullGC(cx);
    915  }
    916 
    917  if (wantIncremental) {
    918    // Incremental GC slices will be triggered by the GC Runner. If one doesn't
    919    // already exist, create it in the GC_SLICE_END callback for the first
    920    // slice being executed here.
    921    JS::StartIncrementalGC(cx, options, aReason, aBudget);
    922  } else {
    923    JS::NonIncrementalGC(cx, options, aReason);
    924  }
    925 }
    926 
    927 // static
    928 void nsJSContext::GarbageCollectNow(JS::GCReason aReason,
    929                                    IsShrinking aShrinking) {
    930  GarbageCollectImpl(aReason, aShrinking, JS::SliceBudget::unlimited());
    931 }
    932 
    933 // static
    934 void nsJSContext::RunIncrementalGCSlice(JS::GCReason aReason,
    935                                        IsShrinking aShrinking,
    936                                        JS::SliceBudget& aBudget) {
    937  AUTO_PROFILER_LABEL_RELEVANT_FOR_JS("Incremental GC", GCCC);
    938  GarbageCollectImpl(aReason, aShrinking, aBudget);
    939 }
    940 
    941 static void FinishAnyIncrementalGC() {
    942  AUTO_PROFILER_LABEL("FinishAnyIncrementalGC", GCCC);
    943 
    944  if (sScheduler->InIncrementalGC()) {
    945    AutoJSAPI jsapi;
    946    jsapi.Init();
    947 
    948    // We're in the middle of an incremental GC, so finish it.
    949    JS::PrepareForIncrementalGC(jsapi.cx());
    950    JS::FinishIncrementalGC(jsapi.cx(), JS::GCReason::CC_FORCED);
    951  }
    952 }
    953 
    954 static void FireForgetSkippable(bool aRemoveChildless, TimeStamp aDeadline) {
    955  TimeStamp startTimeStamp = TimeStamp::Now();
    956  FinishAnyIncrementalGC();
    957 
    958  JS::SliceBudget budget =
    959      sScheduler->ComputeForgetSkippableBudget(startTimeStamp, aDeadline);
    960  bool earlyForgetSkippable = sScheduler->IsEarlyForgetSkippable();
    961  nsCycleCollector_forgetSkippable(startTimeStamp, budget, !aDeadline.IsNull(),
    962                                   aRemoveChildless, earlyForgetSkippable);
    963  TimeStamp now = TimeStamp::Now();
    964  sScheduler->NoteForgetSkippableComplete(now,
    965                                          nsCycleCollector_suspectedCount());
    966 
    967  TimeDuration duration = now - startTimeStamp;
    968  if (duration.ToSeconds()) {
    969    TimeDuration idleDuration;
    970    if (!aDeadline.IsNull()) {
    971      if (aDeadline < now) {
    972        // This slice overflowed the idle period.
    973        if (aDeadline > startTimeStamp) {
    974          idleDuration = aDeadline - startTimeStamp;
    975        }
    976      } else {
    977        idleDuration = duration;
    978      }
    979    }
    980 
    981    uint32_t percent =
    982        uint32_t(idleDuration.ToSeconds() / duration.ToSeconds() * 100);
    983    glean::dom::forget_skippable_during_idle.AccumulateSingleSample(percent);
    984  }
    985 }
    986 
    987 static void MaybeLogStats(const CycleCollectorResults& aResults,
    988                          uint32_t aCleanups) {
    989  if (!StaticPrefs::javascript_options_mem_log() && !sCCStats->mFile) {
    990    return;
    991  }
    992 
    993  TimeDuration delta = GetCollectionTimeDelta();
    994 
    995  nsCString mergeMsg;
    996  if (aResults.mMergedZones) {
    997    mergeMsg.AssignLiteral(" merged");
    998  }
    999 
   1000  nsCString gcMsg;
   1001  if (aResults.mForcedGC) {
   1002    gcMsg.AssignLiteral(", forced a GC");
   1003  }
   1004 
   1005  const char16_t* kFmt =
   1006      u"CC(T+%.1f)[%s-%i] max pause: %.fms, total time: %.fms, slices: %lu, "
   1007      u"suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu "
   1008      u"RCed and %lu GCed (%lu|%lu|%lu waiting for GC)%s\n"
   1009      u"ForgetSkippable %lu times before CC, min: %.f ms, max: %.f ms, avg: "
   1010      u"%.f ms, total: %.f ms, max sync: %.f ms, removed: %lu";
   1011  nsString msg;
   1012  nsTextFormatter::ssprintf(
   1013      msg, kFmt, delta.ToMicroseconds() / PR_USEC_PER_SEC,
   1014      ProcessNameForCollectorLog(), getpid(),
   1015      sCCStats->mMaxSliceTime.ToMilliseconds(),
   1016      sCCStats->mTotalSliceTime.ToMilliseconds(), aResults.mNumSlices,
   1017      sCCStats->mSuspected, aResults.mVisitedRefCounted, aResults.mVisitedGCed,
   1018      mergeMsg.get(), aResults.mFreedRefCounted, aResults.mFreedGCed,
   1019      sScheduler->mCCollectedWaitingForGC,
   1020      sScheduler->mCCollectedZonesWaitingForGC,
   1021      sScheduler->mLikelyShortLivingObjectsNeedingGC, gcMsg.get(),
   1022      sCCStats->mForgetSkippableBeforeCC,
   1023      sCCStats->mMinForgetSkippableTime.ToMilliseconds(),
   1024      sCCStats->mMaxForgetSkippableTime.ToMilliseconds(),
   1025      sCCStats->mTotalForgetSkippableTime.ToMilliseconds() / aCleanups,
   1026      sCCStats->mTotalForgetSkippableTime.ToMilliseconds(),
   1027      sCCStats->mMaxSkippableDuration.ToMilliseconds(),
   1028      sCCStats->mRemovedPurples);
   1029  if (StaticPrefs::javascript_options_mem_log()) {
   1030    nsCOMPtr<nsIConsoleService> cs =
   1031        do_GetService(NS_CONSOLESERVICE_CONTRACTID);
   1032    if (cs) {
   1033      cs->LogStringMessage(msg.get());
   1034    }
   1035  }
   1036  if (sCCStats->mFile) {
   1037    fprintf(sCCStats->mFile, "%s\n", NS_ConvertUTF16toUTF8(msg).get());
   1038  }
   1039 }
   1040 
   1041 static void MaybeNotifyStats(const CycleCollectorResults& aResults,
   1042                             TimeDuration aCCNowDuration, uint32_t aCleanups) {
   1043  if (!StaticPrefs::javascript_options_mem_notify()) {
   1044    return;
   1045  }
   1046 
   1047  const char16_t* kJSONFmt =
   1048      u"{ \"timestamp\": %llu, "
   1049      u"\"duration\": %.f, "
   1050      u"\"max_slice_pause\": %.f, "
   1051      u"\"total_slice_pause\": %.f, "
   1052      u"\"max_finish_gc_duration\": %.f, "
   1053      u"\"max_sync_skippable_duration\": %.f, "
   1054      u"\"suspected\": %lu, "
   1055      u"\"visited\": { "
   1056      u"\"RCed\": %lu, "
   1057      u"\"GCed\": %lu }, "
   1058      u"\"collected\": { "
   1059      u"\"RCed\": %lu, "
   1060      u"\"GCed\": %lu }, "
   1061      u"\"waiting_for_gc\": %lu, "
   1062      u"\"zones_waiting_for_gc\": %lu, "
   1063      u"\"short_living_objects_waiting_for_gc\": %lu, "
   1064      u"\"forced_gc\": %d, "
   1065      u"\"forget_skippable\": { "
   1066      u"\"times_before_cc\": %lu, "
   1067      u"\"min\": %.f, "
   1068      u"\"max\": %.f, "
   1069      u"\"avg\": %.f, "
   1070      u"\"total\": %.f, "
   1071      u"\"removed\": %lu } "
   1072      u"}";
   1073 
   1074  nsString json;
   1075  nsTextFormatter::ssprintf(
   1076      json, kJSONFmt, PR_Now(), aCCNowDuration.ToMilliseconds(),
   1077      sCCStats->mMaxSliceTime.ToMilliseconds(),
   1078      sCCStats->mTotalSliceTime.ToMilliseconds(),
   1079      sCCStats->mMaxGCDuration.ToMilliseconds(),
   1080      sCCStats->mMaxSkippableDuration.ToMilliseconds(), sCCStats->mSuspected,
   1081      aResults.mVisitedRefCounted, aResults.mVisitedGCed,
   1082      aResults.mFreedRefCounted, aResults.mFreedGCed,
   1083      sScheduler->mCCollectedWaitingForGC,
   1084      sScheduler->mCCollectedZonesWaitingForGC,
   1085      sScheduler->mLikelyShortLivingObjectsNeedingGC, aResults.mForcedGC,
   1086      sCCStats->mForgetSkippableBeforeCC,
   1087      sCCStats->mMinForgetSkippableTime.ToMilliseconds(),
   1088      sCCStats->mMaxForgetSkippableTime.ToMilliseconds(),
   1089      sCCStats->mTotalForgetSkippableTime.ToMilliseconds() / aCleanups,
   1090      sCCStats->mTotalForgetSkippableTime.ToMilliseconds(),
   1091      sCCStats->mRemovedPurples);
   1092  nsCOMPtr<nsIObserverService> observerService =
   1093      mozilla::services::GetObserverService();
   1094  if (observerService) {
   1095    observerService->NotifyObservers(nullptr, "cycle-collection-statistics",
   1096                                     json.get());
   1097  }
   1098 }
   1099 
   1100 // static
   1101 void nsJSContext::CycleCollectNow(CCReason aReason,
   1102                                  nsICycleCollectorListener* aListener) {
   1103  if (!NS_IsMainThread()) {
   1104    return;
   1105  }
   1106 
   1107  AUTO_PROFILER_LABEL("nsJSContext::CycleCollectNow", GCCC);
   1108 
   1109  PrepareForCycleCollectionSlice(aReason, TimeStamp());
   1110  nsCycleCollector_collect(aReason, aListener);
   1111  sCCStats->AfterCycleCollectionSlice();
   1112 }
   1113 
   1114 // static
   1115 void nsJSContext::PrepareForCycleCollectionSlice(CCReason aReason,
   1116                                                 TimeStamp aDeadline) {
   1117  TimeStamp beginTime = TimeStamp::Now();
   1118 
   1119  // Before we begin the cycle collection, make sure there is no active GC.
   1120  TimeStamp afterGCTime;
   1121  if (sScheduler->InIncrementalGC()) {
   1122    FinishAnyIncrementalGC();
   1123    afterGCTime = TimeStamp::Now();
   1124  }
   1125 
   1126  if (!sScheduler->IsCollectingCycles()) {
   1127    sCCStats->PrepareForCycleCollection(beginTime);
   1128    sScheduler->NoteCCBegin();
   1129  }
   1130 
   1131  sCCStats->AfterPrepareForCycleCollectionSlice(aDeadline, beginTime,
   1132                                                afterGCTime);
   1133 }
   1134 
   1135 // static
   1136 void nsJSContext::RunCycleCollectorSlice(CCReason aReason,
   1137                                         TimeStamp aDeadline) {
   1138  if (!NS_IsMainThread()) {
   1139    return;
   1140  }
   1141 
   1142  PrepareForCycleCollectionSlice(aReason, aDeadline);
   1143 
   1144  // Decide how long we want to budget for this slice.
   1145  if (sIncrementalCC) {
   1146    bool preferShorterSlices;
   1147    JS::SliceBudget budget = sScheduler->ComputeCCSliceBudget(
   1148        aDeadline, sCCStats->mBeginTime, sCCStats->mEndSliceTime,
   1149        TimeStamp::Now(), &preferShorterSlices);
   1150    nsCycleCollector_collectSlice(budget, aReason, preferShorterSlices);
   1151  } else {
   1152    JS::SliceBudget budget = JS::SliceBudget::unlimited();
   1153    nsCycleCollector_collectSlice(budget, aReason, false);
   1154  }
   1155 
   1156  sCCStats->AfterCycleCollectionSlice();
   1157 }
   1158 
   1159 // static
   1160 void nsJSContext::RunCycleCollectorWorkSlice(int64_t aWorkBudget) {
   1161  if (!NS_IsMainThread()) {
   1162    return;
   1163  }
   1164 
   1165  AUTO_PROFILER_LABEL("nsJSContext::RunCycleCollectorWorkSlice", GCCC);
   1166 
   1167  PrepareForCycleCollectionSlice(CCReason::API, TimeStamp());
   1168 
   1169  JS::SliceBudget budget = JS::SliceBudget(JS::WorkBudget(aWorkBudget));
   1170  nsCycleCollector_collectSlice(budget, CCReason::API);
   1171 
   1172  sCCStats->AfterCycleCollectionSlice();
   1173 }
   1174 
   1175 void nsJSContext::ClearMaxCCSliceTime() {
   1176  sCCStats->mMaxSliceTimeSinceClear = TimeDuration();
   1177 }
   1178 
   1179 uint32_t nsJSContext::GetMaxCCSliceTimeSinceClear() {
   1180  return sCCStats->mMaxSliceTimeSinceClear.ToMilliseconds();
   1181 }
   1182 
   1183 // static
   1184 void nsJSContext::BeginCycleCollectionCallback(CCReason aReason) {
   1185  MOZ_ASSERT(NS_IsMainThread());
   1186 
   1187  TimeStamp startTime = TimeStamp::Now();
   1188  sCCStats->PrepareForCycleCollection(startTime);
   1189 
   1190  // Run forgetSkippable synchronously to reduce the size of the CC graph. This
   1191  // is particularly useful if we recently finished a GC.
   1192  if (sScheduler->IsEarlyForgetSkippable()) {
   1193    while (sScheduler->IsEarlyForgetSkippable()) {
   1194      FireForgetSkippable(false, TimeStamp());
   1195    }
   1196    sCCStats->AfterSyncForgetSkippable(startTime);
   1197  }
   1198 
   1199  if (sShuttingDown) {
   1200    return;
   1201  }
   1202 
   1203  sScheduler->InitCCRunnerStateMachine(
   1204      mozilla::CCGCScheduler::CCRunnerState::CycleCollecting, aReason);
   1205  sScheduler->EnsureCCRunner(kICCIntersliceDelay, kIdleICCSliceBudget);
   1206 }
   1207 
   1208 // static
   1209 void nsJSContext::EndCycleCollectionCallback(
   1210    const CycleCollectorResults& aResults) {
   1211  MOZ_ASSERT(NS_IsMainThread());
   1212 
   1213  sScheduler->KillCCRunner();
   1214 
   1215  // Update timing information for the current slice before we log it, if
   1216  // we previously called PrepareForCycleCollectionSlice(). During shutdown
   1217  // CCs, this won't happen.
   1218  sCCStats->AfterCycleCollectionSlice();
   1219 
   1220  TimeStamp endCCTimeStamp = TimeStamp::Now();
   1221  MOZ_ASSERT(endCCTimeStamp >= sCCStats->mBeginTime);
   1222  TimeDuration ccNowDuration = endCCTimeStamp - sCCStats->mBeginTime;
   1223  TimeStamp prevCCEnd = sScheduler->GetLastCCEndTime();
   1224 
   1225  sScheduler->NoteCCEnd(aResults, endCCTimeStamp);
   1226 
   1227  // Log information about the CC via telemetry, JSON and the console.
   1228 
   1229  sCCStats->SendTelemetry(ccNowDuration, prevCCEnd);
   1230 
   1231  uint32_t cleanups = std::max(sCCStats->mForgetSkippableBeforeCC, 1u);
   1232 
   1233  MaybeLogStats(aResults, cleanups);
   1234 
   1235  MaybeNotifyStats(aResults, ccNowDuration, cleanups);
   1236 
   1237  // Update global state to indicate we have just run a cycle collection.
   1238  sCCStats->Clear();
   1239 
   1240  // If we need a GC after this CC (typically because lots of GCed objects or
   1241  // zones have been collected in the CC), schedule it.
   1242 
   1243  if (sScheduler->NeedsGCAfterCC()) {
   1244    MOZ_ASSERT(
   1245        TimeDuration::FromMilliseconds(
   1246            StaticPrefs::javascript_options_gc_delay()) > kMaxICCDuration,
   1247        "A max duration ICC shouldn't reduce GC delay to 0");
   1248 
   1249    TimeDuration delay;
   1250    if (sScheduler->PreferFasterCollection()) {
   1251      // If we collected lots of objects, trigger the next GC sooner so that
   1252      // GC can cut JS-to-native edges and native objects can be then deleted.
   1253      delay = TimeDuration::FromMilliseconds(
   1254          StaticPrefs::javascript_options_gc_delay_interslice());
   1255    } else {
   1256      delay = TimeDuration::FromMilliseconds(
   1257                  StaticPrefs::javascript_options_gc_delay()) -
   1258              std::min(ccNowDuration, kMaxICCDuration);
   1259    }
   1260 
   1261    sScheduler->PokeGC(JS::GCReason::CC_FINISHED, nullptr, delay);
   1262  }
   1263 #if defined(MOZ_MEMORY)
   1264  else if (
   1265      StaticPrefs::
   1266          dom_memory_foreground_content_processes_have_larger_page_cache()) {
   1267    jemalloc_free_dirty_pages();
   1268  }
   1269 #endif
   1270 }
   1271 
   1272 bool CCGCScheduler::CCRunnerFired(TimeStamp aDeadline) {
   1273  AUTO_PROFILER_LABEL_RELEVANT_FOR_JS("Incremental CC", GCCC);
   1274 
   1275  if (!aDeadline) {
   1276    mCurrentCollectionHasSeenNonIdle = true;
   1277  } else if (mPreferFasterCollection) {
   1278    // We found some idle time, try to utilize that a bit more given that
   1279    // we're in a mode where idle time is rare.
   1280    aDeadline = aDeadline + TimeDuration::FromMilliseconds(5.0);
   1281  }
   1282 
   1283  bool didDoWork = false;
   1284 
   1285  // The CC/GC scheduler (sScheduler) decides what action(s) to take during
   1286  // this invocation of the CC runner.
   1287  //
   1288  // This may be zero, one, or multiple actions. (Zero is when CC is blocked by
   1289  // incremental GC, or when the scheduler determined that a CC is no longer
   1290  // needed.) Loop until the scheduler finishes this invocation by returning
   1291  // `Yield` in step.mYield.
   1292  CCRunnerStep step;
   1293  do {
   1294    step = sScheduler->AdvanceCCRunner(aDeadline, TimeStamp::Now(),
   1295                                       nsCycleCollector_suspectedCount());
   1296    switch (step.mAction) {
   1297      case CCRunnerAction::None:
   1298        break;
   1299 
   1300      case CCRunnerAction::MinorGC:
   1301        JS::MaybeRunNurseryCollection(CycleCollectedJSRuntime::Get()->Runtime(),
   1302                                      step.mParam.mReason);
   1303        sScheduler->NoteMinorGCEnd();
   1304        break;
   1305 
   1306      case CCRunnerAction::ForgetSkippable:
   1307        // 'Forget skippable' only, then end this invocation.
   1308        FireForgetSkippable(bool(step.mParam.mRemoveChildless), aDeadline);
   1309        break;
   1310 
   1311      case CCRunnerAction::CleanupContentUnbinder:
   1312        // Clear content unbinder before the first actual CC slice.
   1313        Element::ClearContentUnbinder();
   1314        break;
   1315 
   1316      case CCRunnerAction::CleanupDeferred:
   1317        // and if time still permits, perform deferred deletions.
   1318        nsCycleCollector_doDeferredDeletion();
   1319        break;
   1320 
   1321      case CCRunnerAction::CycleCollect:
   1322        // Cycle collection slice.
   1323        nsJSContext::RunCycleCollectorSlice(step.mParam.mCCReason, aDeadline);
   1324        break;
   1325 
   1326      case CCRunnerAction::StopRunning:
   1327        // End this CC, either because we have run a cycle collection slice, or
   1328        // because a CC is no longer needed.
   1329        sScheduler->KillCCRunner();
   1330        break;
   1331    }
   1332 
   1333    if (step.mAction != CCRunnerAction::None) {
   1334      didDoWork = true;
   1335    }
   1336  } while (step.mYield == CCRunnerYield::Continue);
   1337 
   1338  return didDoWork;
   1339 }
   1340 
   1341 // static
   1342 bool nsJSContext::HasHadCleanupSinceLastGC() {
   1343  return sScheduler->IsEarlyForgetSkippable(1);
   1344 }
   1345 
   1346 // static
   1347 void nsJSContext::RunNextCollectorTimer(JS::GCReason aReason,
   1348                                        mozilla::TimeStamp aDeadline) {
   1349  sScheduler->RunNextCollectorTimer(aReason, aDeadline);
   1350 }
   1351 
   1352 // static
   1353 void nsJSContext::MaybeRunNextCollectorSlice(nsIDocShell* aDocShell,
   1354                                             JS::GCReason aReason) {
   1355  if (!aDocShell || !XRE_IsContentProcess()) {
   1356    return;
   1357  }
   1358 
   1359  BrowsingContext* bc = aDocShell->GetBrowsingContext();
   1360  if (!bc) {
   1361    return;
   1362  }
   1363 
   1364  BrowsingContext* root = bc->Top();
   1365  if (bc == root) {
   1366    // We don't want to run collectors when loading the top level page.
   1367    return;
   1368  }
   1369 
   1370  nsIDocShell* rootDocShell = root->GetDocShell();
   1371  if (!rootDocShell) {
   1372    return;
   1373  }
   1374 
   1375  Document* rootDocument = rootDocShell->GetDocument();
   1376  if (!rootDocument ||
   1377      rootDocument->GetReadyStateEnum() != Document::READYSTATE_COMPLETE ||
   1378      rootDocument->IsInBackgroundWindow()) {
   1379    return;
   1380  }
   1381 
   1382  if (!sScheduler->IsUserActive() &&
   1383      (sScheduler->InIncrementalGC() || sScheduler->IsCollectingCycles())) {
   1384    Maybe<TimeStamp> next = nsRefreshDriver::GetNextTickHint();
   1385    if (next.isSome()) {
   1386      // Try to not delay the next RefreshDriver tick, so give a reasonable
   1387      // deadline for collectors.
   1388      sScheduler->RunNextCollectorTimer(aReason, next.value());
   1389    }
   1390  }
   1391 
   1392  nsCOMPtr<nsIDocShell> shell = aDocShell;
   1393  NS_DispatchToCurrentThreadQueue(
   1394      NS_NewRunnableFunction("nsJSContext::MaybeRunNextCollectorSlice",
   1395                             [shell] {
   1396                               nsIDocShell::BusyFlags busyFlags =
   1397                                   nsIDocShell::BUSY_FLAGS_NONE;
   1398                               shell->GetBusyFlags(&busyFlags);
   1399                               if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE) {
   1400                                 return;
   1401                               }
   1402 
   1403                               // In order to improve performance on the next
   1404                               // page, run a minor GC. The 16ms limit ensures
   1405                               // it isn't called all the time if there are for
   1406                               // example multiple iframes loading at the same
   1407                               // time.
   1408                               JS::RunNurseryCollection(
   1409                                   CycleCollectedJSRuntime::Get()->Runtime(),
   1410                                   JS::GCReason::PREPARE_FOR_PAGELOAD,
   1411                                   mozilla::TimeDuration::FromMilliseconds(16));
   1412                             }),
   1413      EventQueuePriority::Idle);
   1414 }
   1415 
   1416 // static
   1417 void nsJSContext::PokeGC(JS::GCReason aReason, JSObject* aObj,
   1418                         TimeDuration aDelay) {
   1419  sScheduler->PokeGC(aReason, aObj, aDelay);
   1420 }
   1421 
   1422 // static
   1423 void nsJSContext::MaybePokeGC() {
   1424  if (sShuttingDown) {
   1425    return;
   1426  }
   1427 
   1428  JSRuntime* rt = CycleCollectedJSRuntime::Get()->Runtime();
   1429  JS::GCReason reason = JS::WantEagerMinorGC(rt);
   1430  if (reason != JS::GCReason::NO_REASON) {
   1431    MOZ_ASSERT(reason == JS::GCReason::EAGER_NURSERY_COLLECTION);
   1432    sScheduler->PokeMinorGC(reason);
   1433  }
   1434 
   1435  // Bug 1772638: For now, only do eager minor GCs. Eager major GCs regress some
   1436  // benchmarks. Hopefully that will be worked out and this will check for
   1437  // whether an eager major GC is needed.
   1438 }
   1439 
   1440 void nsJSContext::DoLowMemoryGC() {
   1441  if (sShuttingDown) {
   1442    return;
   1443  }
   1444  nsJSContext::GarbageCollectNow(JS::GCReason::MEM_PRESSURE,
   1445                                 nsJSContext::ShrinkingGC);
   1446  nsJSContext::CycleCollectNow(CCReason::MEM_PRESSURE);
   1447  if (sScheduler->NeedsGCAfterCC()) {
   1448    nsJSContext::GarbageCollectNow(JS::GCReason::MEM_PRESSURE,
   1449                                   nsJSContext::ShrinkingGC);
   1450  }
   1451 }
   1452 
   1453 // static
   1454 void nsJSContext::LowMemoryGC() {
   1455  RefPtr<CCGCScheduler::MayGCPromise> mbPromise =
   1456      CCGCScheduler::MayGCNow(JS::GCReason::MEM_PRESSURE);
   1457  if (!mbPromise) {
   1458    // Normally when the promise is null it means that IPC failed, that probably
   1459    // means that something bad happened, don't bother with the GC.
   1460    return;
   1461  }
   1462  mbPromise->Then(
   1463      GetMainThreadSerialEventTarget(), __func__,
   1464      [](bool aIgnored) { DoLowMemoryGC(); },
   1465      [](mozilla::ipc::ResponseRejectReason r) {});
   1466 }
   1467 
   1468 // static
   1469 void nsJSContext::MaybePokeCC() {
   1470  sScheduler->MaybePokeCC(TimeStamp::NowLoRes(),
   1471                          nsCycleCollector_suspectedCount());
   1472 }
   1473 
   1474 static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress,
   1475                               const JS::GCDescription& aDesc) {
   1476  NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread");
   1477 
   1478  static TimeStamp sCurrentGCStartTime;
   1479 
   1480  switch (aProgress) {
   1481    case JS::GC_CYCLE_BEGIN: {
   1482      // Prevent cycle collections and shrinking during incremental GC.
   1483      sScheduler->NoteGCBegin(aDesc.reason_);
   1484      sCurrentGCStartTime = TimeStamp::Now();
   1485      break;
   1486    }
   1487 
   1488    case JS::GC_CYCLE_END: {
   1489      TimeDuration delta = GetCollectionTimeDelta();
   1490 
   1491      if (StaticPrefs::javascript_options_mem_log()) {
   1492        nsString gcstats;
   1493        gcstats.Adopt(aDesc.formatSummaryMessage(aCx));
   1494        nsAutoString prefix;
   1495        nsTextFormatter::ssprintf(prefix, u"GC(T+%.1f)[%s-%i] ",
   1496                                  delta.ToSeconds(),
   1497                                  ProcessNameForCollectorLog(), getpid());
   1498        nsString msg = prefix + gcstats;
   1499        nsCOMPtr<nsIConsoleService> cs =
   1500            do_GetService(NS_CONSOLESERVICE_CONTRACTID);
   1501        if (cs) {
   1502          cs->LogStringMessage(msg.get());
   1503        }
   1504      }
   1505 
   1506      sScheduler->NoteGCEnd();
   1507 
   1508      // May need to kill the GC runner
   1509      sScheduler->KillGCRunner();
   1510 
   1511      nsJSContext::MaybePokeCC();
   1512 
   1513 #if defined(MOZ_MEMORY)
   1514      bool freeDirty = false;
   1515 #endif
   1516      if (aDesc.isZone_) {
   1517        sScheduler->PokeFullGC();
   1518      } else {
   1519 #if defined(MOZ_MEMORY)
   1520        freeDirty = true;
   1521 #endif
   1522        sScheduler->SetNeedsFullGC(false);
   1523        sScheduler->KillFullGCTimer();
   1524      }
   1525 
   1526      if (sScheduler->IsCCNeeded(TimeStamp::Now(),
   1527                                 nsCycleCollector_suspectedCount()) !=
   1528          CCReason::NO_REASON) {
   1529 #if defined(MOZ_MEMORY)
   1530        // We're likely to free the dirty pages after CC.
   1531        freeDirty = false;
   1532 #endif
   1533        nsCycleCollector_dispatchDeferredDeletion();
   1534      }
   1535 
   1536      MOZ_ASSERT(sCurrentGCStartTime);
   1537      glean::dom::gc_in_progress.AccumulateRawDuration(TimeStamp::Now() -
   1538                                                       sCurrentGCStartTime);
   1539 
   1540 #if defined(MOZ_MEMORY)
   1541      if (freeDirty &&
   1542          StaticPrefs::
   1543              dom_memory_foreground_content_processes_have_larger_page_cache()) {
   1544        jemalloc_free_dirty_pages();
   1545      }
   1546 #endif
   1547      break;
   1548    }
   1549 
   1550    case JS::GC_SLICE_BEGIN:
   1551      break;
   1552 
   1553    case JS::GC_SLICE_END:
   1554      sScheduler->NoteGCSliceEnd(aDesc.lastSliceStart(aCx),
   1555                                 aDesc.lastSliceEnd(aCx));
   1556 
   1557      if (sShuttingDown) {
   1558        sScheduler->KillGCRunner();
   1559      } else {
   1560        // If incremental GC wasn't triggered by GCTimerFired, we may not have a
   1561        // runner to ensure all the slices are handled. So, create the runner
   1562        // here.
   1563        sScheduler->EnsureOrResetGCRunner();
   1564      }
   1565 
   1566      if (sScheduler->IsCCNeeded(TimeStamp::Now(),
   1567                                 nsCycleCollector_suspectedCount()) !=
   1568          CCReason::NO_REASON) {
   1569        nsCycleCollector_dispatchDeferredDeletion();
   1570      }
   1571 
   1572      if (StaticPrefs::javascript_options_mem_log()) {
   1573        nsString gcstats;
   1574        gcstats.Adopt(aDesc.formatSliceMessage(aCx));
   1575        nsAutoString prefix;
   1576        nsTextFormatter::ssprintf(prefix, u"[%s-%i] ",
   1577                                  ProcessNameForCollectorLog(), getpid());
   1578        nsString msg = prefix + gcstats;
   1579        nsCOMPtr<nsIConsoleService> cs =
   1580            do_GetService(NS_CONSOLESERVICE_CONTRACTID);
   1581        if (cs) {
   1582          cs->LogStringMessage(msg.get());
   1583        }
   1584      }
   1585 
   1586      break;
   1587 
   1588    default:
   1589      MOZ_CRASH("Unexpected GCProgress value");
   1590  }
   1591 
   1592  if (sPrevGCSliceCallback) {
   1593    (*sPrevGCSliceCallback)(aCx, aProgress, aDesc);
   1594  }
   1595 }
   1596 
   1597 void nsJSContext::SetWindowProxy(JS::Handle<JSObject*> aWindowProxy) {
   1598  mWindowProxy = aWindowProxy;
   1599 }
   1600 
   1601 JSObject* nsJSContext::GetWindowProxy() { return mWindowProxy; }
   1602 
   1603 void nsJSContext::LikelyShortLivingObjectCreated() {
   1604  ++sScheduler->mLikelyShortLivingObjectsNeedingGC;
   1605 }
   1606 
   1607 void mozilla::dom::StartupJSEnvironment() {
   1608  // initialize all our statics, so that we can restart XPCOM
   1609  sIsInitialized = false;
   1610  sShuttingDown = false;
   1611  sCCStats = CycleCollectorStats::Get();
   1612 }
   1613 
   1614 static void SetGCParameter(JSGCParamKey aParam, uint32_t aValue) {
   1615  AutoJSAPI jsapi;
   1616  jsapi.Init();
   1617  JS_SetGCParameter(jsapi.cx(), aParam, aValue);
   1618 }
   1619 
   1620 static void ResetGCParameter(JSGCParamKey aParam) {
   1621  AutoJSAPI jsapi;
   1622  jsapi.Init();
   1623  JS_ResetGCParameter(jsapi.cx(), aParam);
   1624 }
   1625 
   1626 static void SetMemoryPrefChangedCallbackMB(const char* aPrefName,
   1627                                           void* aClosure) {
   1628  int32_t prefMB = Preferences::GetInt(aPrefName, -1);
   1629  // handle overflow and negative pref values
   1630  CheckedInt<int32_t> prefB = CheckedInt<int32_t>(prefMB) * 1024 * 1024;
   1631  if (prefB.isValid() && prefB.value() >= 0) {
   1632    SetGCParameter((JSGCParamKey)(uintptr_t)aClosure, prefB.value());
   1633  } else {
   1634    ResetGCParameter((JSGCParamKey)(uintptr_t)aClosure);
   1635  }
   1636 }
   1637 
   1638 static void SetMemoryNurseryPrefChangedCallback(const char* aPrefName,
   1639                                                void* aClosure) {
   1640  int32_t prefKB = Preferences::GetInt(aPrefName, -1);
   1641  // handle overflow and negative pref values
   1642  CheckedInt<int32_t> prefB = CheckedInt<int32_t>(prefKB) * 1024;
   1643  if (prefB.isValid() && prefB.value() >= 0) {
   1644    SetGCParameter((JSGCParamKey)(uintptr_t)aClosure, prefB.value());
   1645  } else {
   1646    ResetGCParameter((JSGCParamKey)(uintptr_t)aClosure);
   1647  }
   1648 }
   1649 
   1650 static void SetMemoryPrefChangedCallbackInt(const char* aPrefName,
   1651                                            void* aClosure) {
   1652  int32_t pref = Preferences::GetInt(aPrefName, -1);
   1653  // handle overflow and negative pref values
   1654  if (pref >= 0 && pref < 10000) {
   1655    SetGCParameter((JSGCParamKey)(uintptr_t)aClosure, pref);
   1656  } else {
   1657    ResetGCParameter((JSGCParamKey)(uintptr_t)aClosure);
   1658  }
   1659 }
   1660 
   1661 static void SetMemoryPrefChangedCallbackBool(const char* aPrefName,
   1662                                             void* aClosure) {
   1663  bool pref = Preferences::GetBool(aPrefName);
   1664  SetGCParameter((JSGCParamKey)(uintptr_t)aClosure, pref);
   1665 }
   1666 
   1667 static void SetMemoryGCSliceTimePrefChangedCallback(const char* aPrefName,
   1668                                                    void* aClosure) {
   1669  int32_t pref = Preferences::GetInt(aPrefName, -1);
   1670  // handle overflow and negative pref values
   1671  if (pref > 0 && pref < 100000) {
   1672    sScheduler->SetActiveIntersliceGCBudget(
   1673        TimeDuration::FromMilliseconds(pref));
   1674    SetGCParameter(JSGC_SLICE_TIME_BUDGET_MS, pref);
   1675  } else {
   1676    ResetGCParameter(JSGC_SLICE_TIME_BUDGET_MS);
   1677  }
   1678 }
   1679 
   1680 static void SetIncrementalCCPrefChangedCallback(const char* aPrefName,
   1681                                                void* aClosure) {
   1682  bool pref = Preferences::GetBool(aPrefName);
   1683  sIncrementalCC = pref;
   1684 }
   1685 
   1686 class JSDispatchableRunnable final : public Runnable {
   1687  ~JSDispatchableRunnable() { MOZ_ASSERT(!mDispatchable); }
   1688 
   1689 public:
   1690  explicit JSDispatchableRunnable(
   1691      js::UniquePtr<JS::Dispatchable>&& aDispatchable)
   1692      : mozilla::Runnable("JSDispatchableRunnable"),
   1693        mDispatchable(std::move(aDispatchable)) {
   1694    MOZ_ASSERT(mDispatchable);
   1695  }
   1696 
   1697 protected:
   1698  NS_IMETHOD Run() override {
   1699    MOZ_ASSERT(NS_IsMainThread());
   1700 
   1701    AutoJSAPI jsapi;
   1702    jsapi.Init();
   1703 
   1704    JS::Dispatchable::MaybeShuttingDown maybeShuttingDown =
   1705        sShuttingDown ? JS::Dispatchable::ShuttingDown
   1706                      : JS::Dispatchable::NotShuttingDown;
   1707 
   1708    JS::Dispatchable::Run(jsapi.cx(), std::move(mDispatchable),
   1709                          maybeShuttingDown);
   1710    // mDispatchable is no longer valid after this point.
   1711 
   1712    return NS_OK;
   1713  }
   1714 
   1715 private:
   1716  js::UniquePtr<JS::Dispatchable> mDispatchable;
   1717 };
   1718 
   1719 static bool DelayedDispatchToEventLoop(
   1720    void* closure, js::UniquePtr<JS::Dispatchable>&& aDispatchable,
   1721    uint32_t aDelay) {
   1722  MOZ_ASSERT(!closure);
   1723 
   1724  // Unlike DispatchToEventLoop, this is used exclusively on the Main Thread.
   1725  MOZ_ASSERT(NS_IsMainThread());
   1726 
   1727  nsIGlobalObject* global = GetCurrentGlobal();
   1728 
   1729  TimeoutManager* timeoutManager = global->GetTimeoutManager();
   1730  if (timeoutManager) {
   1731    JSContext* cx = nsContentUtils::GetCurrentJSContext();
   1732    RefPtr<TimeoutHandler> handler =
   1733        new DelayedJSDispatchableHandler(cx, std::move(aDispatchable));
   1734 
   1735    int32_t handle;
   1736    timeoutManager->SetTimeout(handler, aDelay, /* aIsInterval */ false,
   1737                               Timeout::Reason::eJSTimeout, &handle);
   1738  } else {
   1739    // Currently only used for waitAsync timeout implementation.
   1740    // We end up in this branch if the global does not have a
   1741    // timeout manager (for example, no innerWindow global).
   1742    // In this case, we reuse the ReleaseFailedTask machinery to
   1743    // cancel the pending associated notify task.
   1744    JS::Dispatchable::ReleaseFailedTask(std::move(aDispatchable));
   1745    return false;
   1746  }
   1747 
   1748  return true;
   1749 }
   1750 
   1751 static bool DispatchToEventLoop(
   1752    void* closure, js::UniquePtr<JS::Dispatchable>&& aDispatchable) {
   1753  MOZ_ASSERT(!closure);
   1754 
   1755  // This callback may execute either on the main thread or a random JS-internal
   1756  // helper thread. This callback can be called during shutdown so we cannot
   1757  // simply NS_DispatchToMainThread. Failure during shutdown is expected and
   1758  // properly handled by the JS engine.
   1759 
   1760  nsCOMPtr<nsIEventTarget> mainTarget = GetMainThreadSerialEventTarget();
   1761  if (!mainTarget) {
   1762    // if we have not transfered ownership of the dispatchable to the
   1763    // dispatchable runnable, release it here, so that the JS engine will
   1764    // handle deleting it on JS context shutdown.
   1765    JS::Dispatchable::ReleaseFailedTask(std::move(aDispatchable));
   1766    return false;
   1767  }
   1768 
   1769  RefPtr<JSDispatchableRunnable> r =
   1770      new JSDispatchableRunnable(std::move(aDispatchable));
   1771  MOZ_ALWAYS_SUCCEEDS(mainTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL));
   1772  return true;
   1773 }
   1774 
   1775 static bool ConsumeStream(JSContext* aCx, JS::Handle<JSObject*> aObj,
   1776                          JS::MimeType aMimeType,
   1777                          JS::StreamConsumer* aConsumer) {
   1778  return FetchUtil::StreamResponseToJS(aCx, aObj, aMimeType, aConsumer,
   1779                                       nullptr);
   1780 }
   1781 
   1782 static JS::SliceBudget CreateGCSliceBudget(JS::GCReason aReason,
   1783                                           int64_t aMillis) {
   1784  return sScheduler->CreateGCSliceBudget(
   1785      mozilla::TimeDuration::FromMilliseconds(aMillis), false, false);
   1786 }
   1787 
   1788 void nsJSContext::EnsureStatics() {
   1789  if (sIsInitialized) {
   1790    if (!nsContentUtils::XPConnect()) {
   1791      MOZ_CRASH();
   1792    }
   1793    return;
   1794  }
   1795 
   1796  // Let's make sure that our main thread is the same as the xpcom main thread.
   1797  MOZ_ASSERT(NS_IsMainThread());
   1798 
   1799  sScheduler =
   1800      new (&sSchedulerStorage) CCGCScheduler();  // Reset the scheduler state.
   1801 
   1802  AutoJSAPI jsapi;
   1803  jsapi.Init();
   1804 
   1805  sPrevGCSliceCallback = JS::SetGCSliceCallback(jsapi.cx(), DOMGCSliceCallback);
   1806 
   1807  JS::SetCreateGCSliceBudgetCallback(jsapi.cx(), CreateGCSliceBudget);
   1808 
   1809  JS::InitAsyncTaskCallbacks(jsapi.cx(), DispatchToEventLoop,
   1810                             DelayedDispatchToEventLoop, nullptr, nullptr,
   1811                             nullptr);
   1812 
   1813  JS::InitConsumeStreamCallback(jsapi.cx(), ConsumeStream,
   1814                                FetchUtil::ReportJSStreamError);
   1815 
   1816  // Set these global xpconnect options...
   1817  Preferences::RegisterCallbackAndCall(SetMemoryPrefChangedCallbackMB,
   1818                                       "javascript.options.mem.max",
   1819                                       (void*)JSGC_MAX_BYTES);
   1820  Preferences::RegisterCallbackAndCall(SetMemoryNurseryPrefChangedCallback,
   1821                                       "javascript.options.mem.nursery.min_kb",
   1822                                       (void*)JSGC_MIN_NURSERY_BYTES);
   1823  Preferences::RegisterCallbackAndCall(SetMemoryNurseryPrefChangedCallback,
   1824                                       "javascript.options.mem.nursery.max_kb",
   1825                                       (void*)JSGC_MAX_NURSERY_BYTES);
   1826 
   1827  Preferences::RegisterCallbackAndCall(SetMemoryPrefChangedCallbackBool,
   1828                                       "javascript.options.mem.gc_per_zone",
   1829                                       (void*)JSGC_PER_ZONE_GC_ENABLED);
   1830 
   1831  Preferences::RegisterCallbackAndCall(SetMemoryPrefChangedCallbackBool,
   1832                                       "javascript.options.mem.gc_incremental",
   1833                                       (void*)JSGC_INCREMENTAL_GC_ENABLED);
   1834 
   1835  Preferences::RegisterCallbackAndCall(SetMemoryPrefChangedCallbackBool,
   1836                                       "javascript.options.mem.gc_generational",
   1837                                       (void*)JSGC_NURSERY_ENABLED);
   1838 
   1839  Preferences::RegisterCallbackAndCall(SetMemoryPrefChangedCallbackBool,
   1840                                       "javascript.options.mem.gc_compacting",
   1841                                       (void*)JSGC_COMPACTING_ENABLED);
   1842 
   1843 #ifdef NIGHTLY_BUILD
   1844  Preferences::RegisterCallbackAndCall(
   1845      SetMemoryPrefChangedCallbackBool,
   1846      "javascript.options.mem.gc_experimental_semispace_nursery",
   1847      (void*)JSGC_SEMISPACE_NURSERY_ENABLED);
   1848 #endif
   1849 
   1850  Preferences::RegisterCallbackAndCall(
   1851      SetMemoryPrefChangedCallbackBool,
   1852      "javascript.options.mem.gc_parallel_marking",
   1853      (void*)JSGC_PARALLEL_MARKING_ENABLED);
   1854 
   1855  Preferences::RegisterCallbackAndCall(
   1856      SetMemoryPrefChangedCallbackInt,
   1857      "javascript.options.mem.gc_parallel_marking_threshold_mb",
   1858      (void*)JSGC_PARALLEL_MARKING_THRESHOLD_MB);
   1859 
   1860  Preferences::RegisterCallbackAndCall(
   1861      SetMemoryPrefChangedCallbackInt,
   1862      "javascript.options.mem.gc_max_parallel_marking_threads",
   1863      (void*)JSGC_MAX_MARKING_THREADS);
   1864 
   1865  Preferences::RegisterCallbackAndCall(
   1866      SetMemoryGCSliceTimePrefChangedCallback,
   1867      "javascript.options.mem.gc_incremental_slice_ms");
   1868 
   1869  Preferences::RegisterCallbackAndCall(
   1870      SetMemoryPrefChangedCallbackBool,
   1871      "javascript.options.mem.incremental_weakmap",
   1872      (void*)JSGC_INCREMENTAL_WEAKMAP_ENABLED);
   1873 
   1874  Preferences::RegisterCallbackAndCall(
   1875      SetMemoryPrefChangedCallbackInt,
   1876      "javascript.options.mem.gc_high_frequency_time_limit_ms",
   1877      (void*)JSGC_HIGH_FREQUENCY_TIME_LIMIT);
   1878 
   1879  Preferences::RegisterCallbackAndCall(
   1880      SetMemoryPrefChangedCallbackInt,
   1881      "javascript.options.mem.gc_low_frequency_heap_growth",
   1882      (void*)JSGC_LOW_FREQUENCY_HEAP_GROWTH);
   1883 
   1884  Preferences::RegisterCallbackAndCall(
   1885      SetMemoryPrefChangedCallbackInt,
   1886      "javascript.options.mem.gc_high_frequency_large_heap_growth",
   1887      (void*)JSGC_HIGH_FREQUENCY_LARGE_HEAP_GROWTH);
   1888 
   1889  Preferences::RegisterCallbackAndCall(
   1890      SetMemoryPrefChangedCallbackInt,
   1891      "javascript.options.mem.gc_high_frequency_small_heap_growth",
   1892      (void*)JSGC_HIGH_FREQUENCY_SMALL_HEAP_GROWTH);
   1893 
   1894  Preferences::RegisterCallbackAndCall(
   1895      SetMemoryPrefChangedCallbackBool,
   1896      "javascript.options.mem.gc_balanced_heap_limits",
   1897      (void*)JSGC_BALANCED_HEAP_LIMITS_ENABLED);
   1898 
   1899  Preferences::RegisterCallbackAndCall(
   1900      SetMemoryPrefChangedCallbackInt,
   1901      "javascript.options.mem.gc_heap_growth_factor",
   1902      (void*)JSGC_HEAP_GROWTH_FACTOR);
   1903 
   1904  Preferences::RegisterCallbackAndCall(
   1905      SetMemoryPrefChangedCallbackInt,
   1906      "javascript.options.mem.gc_small_heap_size_max_mb",
   1907      (void*)JSGC_SMALL_HEAP_SIZE_MAX);
   1908 
   1909  Preferences::RegisterCallbackAndCall(
   1910      SetMemoryPrefChangedCallbackInt,
   1911      "javascript.options.mem.gc_large_heap_size_min_mb",
   1912      (void*)JSGC_LARGE_HEAP_SIZE_MIN);
   1913 
   1914  Preferences::RegisterCallbackAndCall(
   1915      SetMemoryPrefChangedCallbackInt,
   1916      "javascript.options.mem.gc_allocation_threshold_mb",
   1917      (void*)JSGC_ALLOCATION_THRESHOLD);
   1918 
   1919  Preferences::RegisterCallbackAndCall(
   1920      SetMemoryPrefChangedCallbackInt,
   1921      "javascript.options.mem.gc_malloc_threshold_base_mb",
   1922      (void*)JSGC_MALLOC_THRESHOLD_BASE);
   1923 
   1924  Preferences::RegisterCallbackAndCall(
   1925      SetMemoryPrefChangedCallbackInt,
   1926      "javascript.options.mem.gc_small_heap_incremental_limit",
   1927      (void*)JSGC_SMALL_HEAP_INCREMENTAL_LIMIT);
   1928  Preferences::RegisterCallbackAndCall(
   1929      SetMemoryPrefChangedCallbackInt,
   1930      "javascript.options.mem.gc_large_heap_incremental_limit",
   1931      (void*)JSGC_LARGE_HEAP_INCREMENTAL_LIMIT);
   1932 
   1933  Preferences::RegisterCallbackAndCall(
   1934      SetMemoryPrefChangedCallbackInt,
   1935      "javascript.options.mem.gc_urgent_threshold_mb",
   1936      (void*)JSGC_URGENT_THRESHOLD_MB);
   1937 
   1938  Preferences::RegisterCallbackAndCall(SetIncrementalCCPrefChangedCallback,
   1939                                       "dom.cycle_collector.incremental");
   1940 
   1941  Preferences::RegisterCallbackAndCall(
   1942      SetMemoryPrefChangedCallbackInt,
   1943      "javascript.options.mem.gc_min_empty_chunk_count",
   1944      (void*)JSGC_MIN_EMPTY_CHUNK_COUNT);
   1945 
   1946  Preferences::RegisterCallbackAndCall(
   1947      SetMemoryPrefChangedCallbackInt,
   1948      "javascript.options.mem.gc_helper_thread_ratio",
   1949      (void*)JSGC_HELPER_THREAD_RATIO);
   1950 
   1951  Preferences::RegisterCallbackAndCall(
   1952      SetMemoryPrefChangedCallbackInt,
   1953      "javascript.options.mem.gc_max_helper_threads",
   1954      (void*)JSGC_MAX_HELPER_THREADS);
   1955 
   1956  Preferences::RegisterCallbackAndCall(
   1957      SetMemoryPrefChangedCallbackInt,
   1958      "javascript.options.mem.nursery_eager_collection_threshold_kb",
   1959      (void*)JSGC_NURSERY_EAGER_COLLECTION_THRESHOLD_KB);
   1960 
   1961  Preferences::RegisterCallbackAndCall(
   1962      SetMemoryPrefChangedCallbackInt,
   1963      "javascript.options.mem.nursery_eager_collection_threshold_percent",
   1964      (void*)JSGC_NURSERY_EAGER_COLLECTION_THRESHOLD_PERCENT);
   1965 
   1966  Preferences::RegisterCallbackAndCall(
   1967      SetMemoryPrefChangedCallbackInt,
   1968      "javascript.options.mem.nursery_eager_collection_timeout_ms",
   1969      (void*)JSGC_NURSERY_EAGER_COLLECTION_TIMEOUT_MS);
   1970 
   1971  Preferences::RegisterCallbackAndCall(
   1972      SetMemoryPrefChangedCallbackInt,
   1973      "javascript.options.mem.nursery_max_time_goal_ms",
   1974      (void*)JSGC_NURSERY_MAX_TIME_GOAL_MS);
   1975 
   1976  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   1977  if (!obs) {
   1978    MOZ_CRASH();
   1979  }
   1980 
   1981  nsIObserver* observer = new nsJSEnvironmentObserver();
   1982  obs->AddObserver(observer, "memory-pressure", false);
   1983  obs->AddObserver(observer, "user-interaction-inactive", false);
   1984  obs->AddObserver(observer, "user-interaction-active", false);
   1985  obs->AddObserver(observer, "quit-application", false);
   1986  obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
   1987  obs->AddObserver(observer, "content-child-will-shutdown", false);
   1988 
   1989  sIsInitialized = true;
   1990 }
   1991 
   1992 void mozilla::dom::ShutdownJSEnvironment() {
   1993  sShuttingDown = true;
   1994  sScheduler->Shutdown();
   1995  sCCStats = nullptr;
   1996 }
   1997 
   1998 AsyncErrorReporter::AsyncErrorReporter(xpc::ErrorReport* aReport)
   1999    : Runnable("dom::AsyncErrorReporter"), mReport(aReport) {}
   2000 
   2001 void AsyncErrorReporter::SerializeStack(JSContext* aCx,
   2002                                        JS::Handle<JSObject*> aStack) {
   2003  mStackHolder = MakeUnique<SerializedStackHolder>();
   2004  mStackHolder->SerializeMainThreadOrWorkletStack(aCx, aStack);
   2005 }
   2006 
   2007 void AsyncErrorReporter::SetException(JSContext* aCx,
   2008                                      JS::Handle<JS::Value> aException) {
   2009  MOZ_ASSERT(NS_IsMainThread());
   2010  mException.init(aCx, aException);
   2011  mHasException = true;
   2012 }
   2013 
   2014 NS_IMETHODIMP AsyncErrorReporter::Run() {
   2015  AutoJSAPI jsapi;
   2016  // We're only using this context to deserialize a stack to report to the
   2017  // console, so the scope we use doesn't matter. Stack frame filtering happens
   2018  // based on the principal encoded into the frame and the caller compartment,
   2019  // not the compartment of the frame object, and the console reporting code
   2020  // will not be using our context, and therefore will not care what compartment
   2021  // it has entered.
   2022  DebugOnly<bool> ok = jsapi.Init(xpc::PrivilegedJunkScope());
   2023  MOZ_ASSERT(ok, "Problem with system global?");
   2024  JSContext* cx = jsapi.cx();
   2025  JS::Rooted<JSObject*> stack(cx);
   2026  JS::Rooted<JSObject*> stackGlobal(cx);
   2027  if (mStackHolder) {
   2028    stack = mStackHolder->ReadStack(cx);
   2029    if (stack) {
   2030      stackGlobal = JS::CurrentGlobalOrNull(cx);
   2031    }
   2032  }
   2033 
   2034  JS::Rooted<Maybe<JS::Value>> exception(cx, Nothing());
   2035  if (mHasException) {
   2036    MOZ_ASSERT(NS_IsMainThread());
   2037    exception = Some(mException);
   2038    // Remove our reference to the exception.
   2039    mException.setUndefined();
   2040    mHasException = false;
   2041  }
   2042 
   2043  mReport->LogToConsoleWithStack(nullptr, exception, stack, stackGlobal);
   2044  return NS_OK;
   2045 }
   2046 
   2047 // A fast-array class for JS.  This class supports both nsIJSScriptArray and
   2048 // nsIArray.  If it is JS itself providing and consuming this class, all work
   2049 // can be done via nsIJSScriptArray, and avoid the conversion of elements
   2050 // to/from nsISupports.
   2051 // When consumed by non-JS (eg, another script language), conversion is done
   2052 // on-the-fly.
   2053 class nsJSArgArray final : public nsIJSArgArray {
   2054 public:
   2055  nsJSArgArray(JSContext* aContext, uint32_t argc, const JS::Value* argv,
   2056               nsresult* prv);
   2057 
   2058  // nsISupports
   2059  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   2060  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray,
   2061                                                         nsIJSArgArray)
   2062 
   2063  // nsIArray
   2064  NS_DECL_NSIARRAY
   2065 
   2066  // nsIJSArgArray
   2067  nsresult GetArgs(uint32_t* argc, void** argv) override;
   2068 
   2069  void ReleaseJSObjects();
   2070 
   2071 protected:
   2072  ~nsJSArgArray();
   2073  JSContext* mContext;
   2074  JS::Heap<JS::Value>* mArgv;
   2075  uint32_t mArgc;
   2076 };
   2077 
   2078 nsJSArgArray::nsJSArgArray(JSContext* aContext, uint32_t argc,
   2079                           const JS::Value* argv, nsresult* prv)
   2080    : mContext(aContext), mArgv(nullptr), mArgc(argc) {
   2081  // copy the array - we don't know its lifetime, and ours is tied to xpcom
   2082  // refcounting.
   2083  if (argc) {
   2084    mArgv = new (fallible) JS::Heap<JS::Value>[argc];
   2085    if (!mArgv) {
   2086      *prv = NS_ERROR_OUT_OF_MEMORY;
   2087      return;
   2088    }
   2089  }
   2090 
   2091  // Callers are allowed to pass in a null argv even for argc > 0. They can
   2092  // then use GetArgs to initialize the values.
   2093  if (argv) {
   2094    for (uint32_t i = 0; i < argc; ++i) mArgv[i] = argv[i];
   2095  }
   2096 
   2097  if (argc > 0) {
   2098    mozilla::HoldJSObjects(this);
   2099  }
   2100 
   2101  *prv = NS_OK;
   2102 }
   2103 
   2104 nsJSArgArray::~nsJSArgArray() { ReleaseJSObjects(); }
   2105 
   2106 void nsJSArgArray::ReleaseJSObjects() {
   2107  delete[] mArgv;
   2108 
   2109  if (mArgc > 0) {
   2110    mArgc = 0;
   2111    mozilla::DropJSObjects(this);
   2112  }
   2113 }
   2114 
   2115 // QueryInterface implementation for nsJSArgArray
   2116 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSArgArray)
   2117 
   2118 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSArgArray)
   2119  tmp->ReleaseJSObjects();
   2120 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   2121 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray)
   2122 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   2123 
   2124 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray)
   2125  if (tmp->mArgv) {
   2126    for (uint32_t i = 0; i < tmp->mArgc; ++i) {
   2127      NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mArgv[i])
   2128    }
   2129  }
   2130 NS_IMPL_CYCLE_COLLECTION_TRACE_END
   2131 
   2132 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSArgArray)
   2133  NS_INTERFACE_MAP_ENTRY(nsIArray)
   2134  NS_INTERFACE_MAP_ENTRY(nsIJSArgArray)
   2135  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSArgArray)
   2136 NS_INTERFACE_MAP_END
   2137 
   2138 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSArgArray)
   2139 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSArgArray)
   2140 
   2141 nsresult nsJSArgArray::GetArgs(uint32_t* argc, void** argv) {
   2142  *argv = (void*)mArgv;
   2143  *argc = mArgc;
   2144  return NS_OK;
   2145 }
   2146 
   2147 // nsIArray impl
   2148 NS_IMETHODIMP nsJSArgArray::GetLength(uint32_t* aLength) {
   2149  *aLength = mArgc;
   2150  return NS_OK;
   2151 }
   2152 
   2153 NS_IMETHODIMP nsJSArgArray::QueryElementAt(uint32_t index, const nsIID& uuid,
   2154                                           void** result) {
   2155  *result = nullptr;
   2156  if (index >= mArgc) return NS_ERROR_INVALID_ARG;
   2157 
   2158  if (uuid.Equals(NS_GET_IID(nsIVariant)) ||
   2159      uuid.Equals(NS_GET_IID(nsISupports))) {
   2160    // Have to copy a Heap into a Rooted to work with it.
   2161    JS::Rooted<JS::Value> val(mContext, mArgv[index]);
   2162    return nsContentUtils::XPConnect()->JSToVariant(mContext, val,
   2163                                                    (nsIVariant**)result);
   2164  }
   2165  NS_WARNING("nsJSArgArray only handles nsIVariant");
   2166  return NS_ERROR_NO_INTERFACE;
   2167 }
   2168 
   2169 NS_IMETHODIMP nsJSArgArray::IndexOf(uint32_t startIndex, nsISupports* element,
   2170                                    uint32_t* _retval) {
   2171  return NS_ERROR_NOT_IMPLEMENTED;
   2172 }
   2173 
   2174 NS_IMETHODIMP nsJSArgArray::ScriptedEnumerate(const nsIID& aElemIID,
   2175                                              uint8_t aArgc,
   2176                                              nsISimpleEnumerator** aResult) {
   2177  return NS_ERROR_NOT_IMPLEMENTED;
   2178 }
   2179 
   2180 NS_IMETHODIMP nsJSArgArray::EnumerateImpl(const nsID& aEntryIID,
   2181                                          nsISimpleEnumerator** _retval) {
   2182  return NS_ERROR_NOT_IMPLEMENTED;
   2183 }
   2184 
   2185 // The factory function
   2186 nsresult NS_CreateJSArgv(JSContext* aContext, uint32_t argc,
   2187                         const JS::Value* argv, nsIJSArgArray** aArray) {
   2188  nsresult rv;
   2189  nsCOMPtr<nsIJSArgArray> ret = new nsJSArgArray(aContext, argc, argv, &rv);
   2190  if (NS_FAILED(rv)) {
   2191    return rv;
   2192  }
   2193  ret.forget(aArray);
   2194  return NS_OK;
   2195 }