forked from mirrors/gecko-dev
		
	Also fix the null-check. Differential Revision: https://phabricator.services.mozilla.com/D198504
		
			
				
	
	
		
			2180 lines
		
	
	
	
		
			71 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2180 lines
		
	
	
	
		
			71 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#include "ChromeUtils.h"
 | 
						|
 | 
						|
#include "JSOracleParent.h"
 | 
						|
#include "js/CallAndConstruct.h"  // JS::Call
 | 
						|
#include "js/ColumnNumber.h"  // JS::TaggedColumnNumberOneOrigin, JS::ColumnNumberOneOrigin
 | 
						|
#include "js/friend/DumpFunctions.h"
 | 
						|
#include "js/CharacterEncoding.h"
 | 
						|
#include "js/Date.h"                // JS::IsISOStyleDate
 | 
						|
#include "js/Object.h"              // JS::GetClass
 | 
						|
#include "js/PropertyAndElement.h"  // JS_DefineProperty, JS_DefinePropertyById, JS_Enumerate, JS_GetProperty, JS_GetPropertyById, JS_SetProperty, JS_SetPropertyById, JS::IdVector
 | 
						|
#include "js/PropertyDescriptor.h"  // JS::PropertyDescriptor, JS_GetOwnPropertyDescriptorById
 | 
						|
#include "js/SavedFrameAPI.h"
 | 
						|
#include "js/Value.h"  // JS::Value, JS::StringValue
 | 
						|
#include "jsfriendapi.h"
 | 
						|
#include "WrapperFactory.h"
 | 
						|
 | 
						|
#include "mozilla/Base64.h"
 | 
						|
#include "mozilla/CycleCollectedJSRuntime.h"
 | 
						|
#include "mozilla/ErrorNames.h"
 | 
						|
#include "mozilla/EventStateManager.h"
 | 
						|
#include "mozilla/FormAutofillNative.h"
 | 
						|
#include "mozilla/IntentionalCrash.h"
 | 
						|
#include "mozilla/PerfStats.h"
 | 
						|
#include "mozilla/Preferences.h"
 | 
						|
#include "mozilla/ProcInfo.h"
 | 
						|
#include "mozilla/ResultExtensions.h"
 | 
						|
#include "mozilla/ScopeExit.h"
 | 
						|
#include "mozilla/ScrollingMetrics.h"
 | 
						|
#include "mozilla/SharedStyleSheetCache.h"
 | 
						|
#include "mozilla/SpinEventLoopUntil.h"
 | 
						|
#include "mozilla/TimeStamp.h"
 | 
						|
#include "mozilla/dom/ContentParent.h"
 | 
						|
#include "mozilla/dom/IdleDeadline.h"
 | 
						|
#include "mozilla/dom/InProcessParent.h"
 | 
						|
#include "mozilla/dom/JSActorService.h"
 | 
						|
#include "mozilla/dom/MediaSessionBinding.h"
 | 
						|
#include "mozilla/dom/PBrowserParent.h"
 | 
						|
#include "mozilla/dom/Performance.h"
 | 
						|
#include "mozilla/dom/PopupBlocker.h"
 | 
						|
#include "mozilla/dom/Promise.h"
 | 
						|
#include "mozilla/dom/Record.h"
 | 
						|
#include "mozilla/dom/ReportingHeader.h"
 | 
						|
#include "mozilla/dom/UnionTypes.h"
 | 
						|
#include "mozilla/dom/WindowBinding.h"  // For IdleRequestCallback/Options
 | 
						|
#include "mozilla/dom/WindowGlobalParent.h"
 | 
						|
#include "mozilla/dom/WorkerScope.h"
 | 
						|
#include "mozilla/ipc/GeckoChildProcessHost.h"
 | 
						|
#include "mozilla/ipc/UtilityProcessSandboxing.h"
 | 
						|
#include "mozilla/ipc/UtilityProcessManager.h"
 | 
						|
#include "mozilla/ipc/UtilityProcessHost.h"
 | 
						|
#include "mozilla/net/UrlClassifierFeatureFactory.h"
 | 
						|
#include "mozilla/RemoteDecoderManagerChild.h"
 | 
						|
#include "mozilla/KeySystemConfig.h"
 | 
						|
#include "mozilla/WheelHandlingHelper.h"
 | 
						|
#include "IOActivityMonitor.h"
 | 
						|
#include "nsNativeTheme.h"
 | 
						|
#include "nsThreadUtils.h"
 | 
						|
#include "mozJSModuleLoader.h"
 | 
						|
#include "mozilla/ProfilerLabels.h"
 | 
						|
#include "mozilla/ProfilerMarkers.h"
 | 
						|
#include "nsDocShell.h"
 | 
						|
#include "nsIException.h"
 | 
						|
#include "VsyncSource.h"
 | 
						|
 | 
						|
#ifdef XP_UNIX
 | 
						|
#  include <errno.h>
 | 
						|
#  include <unistd.h>
 | 
						|
#  include <fcntl.h>
 | 
						|
#  include <poll.h>
 | 
						|
#  include <sys/wait.h>
 | 
						|
 | 
						|
#  ifdef XP_LINUX
 | 
						|
#    include <sys/prctl.h>
 | 
						|
#  endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef MOZ_WMF_CDM
 | 
						|
#  include "mozilla/MFCDMParent.h"
 | 
						|
#endif
 | 
						|
 | 
						|
namespace mozilla::dom {
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::NondeterministicGetWeakMapKeys(
 | 
						|
    GlobalObject& aGlobal, JS::Handle<JS::Value> aMap,
 | 
						|
    JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
 | 
						|
  if (!aMap.isObject()) {
 | 
						|
    aRetval.setUndefined();
 | 
						|
  } else {
 | 
						|
    JSContext* cx = aGlobal.Context();
 | 
						|
    JS::Rooted<JSObject*> objRet(cx);
 | 
						|
    JS::Rooted<JSObject*> mapObj(cx, &aMap.toObject());
 | 
						|
    if (!JS_NondeterministicGetWeakMapKeys(cx, mapObj, &objRet)) {
 | 
						|
      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    } else {
 | 
						|
      aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::NondeterministicGetWeakSetKeys(
 | 
						|
    GlobalObject& aGlobal, JS::Handle<JS::Value> aSet,
 | 
						|
    JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
 | 
						|
  if (!aSet.isObject()) {
 | 
						|
    aRetval.setUndefined();
 | 
						|
  } else {
 | 
						|
    JSContext* cx = aGlobal.Context();
 | 
						|
    JS::Rooted<JSObject*> objRet(cx);
 | 
						|
    JS::Rooted<JSObject*> setObj(cx, &aSet.toObject());
 | 
						|
    if (!JS_NondeterministicGetWeakSetKeys(cx, setObj, &objRet)) {
 | 
						|
      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
    } else {
 | 
						|
      aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::Base64URLEncode(GlobalObject& aGlobal,
 | 
						|
                                  const ArrayBufferViewOrArrayBuffer& aSource,
 | 
						|
                                  const Base64URLEncodeOptions& aOptions,
 | 
						|
                                  nsACString& aResult, ErrorResult& aRv) {
 | 
						|
  auto paddingPolicy = aOptions.mPad ? Base64URLEncodePaddingPolicy::Include
 | 
						|
                                     : Base64URLEncodePaddingPolicy::Omit;
 | 
						|
  ProcessTypedArrays(
 | 
						|
      aSource, [&](const Span<uint8_t>& aData, JS::AutoCheckCannotGC&&) {
 | 
						|
        nsresult rv = mozilla::Base64URLEncode(aData.Length(), aData.Elements(),
 | 
						|
                                               paddingPolicy, aResult);
 | 
						|
        if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
          aResult.Truncate();
 | 
						|
          aRv.Throw(rv);
 | 
						|
        }
 | 
						|
      });
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::Base64URLDecode(GlobalObject& aGlobal,
 | 
						|
                                  const nsACString& aString,
 | 
						|
                                  const Base64URLDecodeOptions& aOptions,
 | 
						|
                                  JS::MutableHandle<JSObject*> aRetval,
 | 
						|
                                  ErrorResult& aRv) {
 | 
						|
  Base64URLDecodePaddingPolicy paddingPolicy;
 | 
						|
  switch (aOptions.mPadding) {
 | 
						|
    case Base64URLDecodePadding::Require:
 | 
						|
      paddingPolicy = Base64URLDecodePaddingPolicy::Require;
 | 
						|
      break;
 | 
						|
 | 
						|
    case Base64URLDecodePadding::Ignore:
 | 
						|
      paddingPolicy = Base64URLDecodePaddingPolicy::Ignore;
 | 
						|
      break;
 | 
						|
 | 
						|
    case Base64URLDecodePadding::Reject:
 | 
						|
      paddingPolicy = Base64URLDecodePaddingPolicy::Reject;
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      aRv.Throw(NS_ERROR_INVALID_ARG);
 | 
						|
      return;
 | 
						|
  }
 | 
						|
  FallibleTArray<uint8_t> data;
 | 
						|
  nsresult rv = mozilla::Base64URLDecode(aString, paddingPolicy, data);
 | 
						|
  if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
    aRv.Throw(rv);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> buffer(
 | 
						|
      aGlobal.Context(), ArrayBuffer::Create(aGlobal.Context(), data, aRv));
 | 
						|
  if (aRv.Failed()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  aRetval.set(buffer);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::ReleaseAssert(GlobalObject& aGlobal, bool aCondition,
 | 
						|
                                const nsAString& aMessage) {
 | 
						|
  // If the condition didn't fail, which is the likely case, immediately return.
 | 
						|
  if (MOZ_LIKELY(aCondition)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Extract the current stack from the JS runtime to embed in the crash reason.
 | 
						|
  nsAutoString filename;
 | 
						|
  uint32_t lineNo = 0;
 | 
						|
 | 
						|
  if (nsCOMPtr<nsIStackFrame> location = GetCurrentJSStack(1)) {
 | 
						|
    location->GetFilename(aGlobal.Context(), filename);
 | 
						|
    lineNo = location->GetLineNumber(aGlobal.Context());
 | 
						|
  } else {
 | 
						|
    filename.Assign(u"<unknown>"_ns);
 | 
						|
  }
 | 
						|
 | 
						|
  // Convert to utf-8 for adding as the MozCrashReason.
 | 
						|
  NS_ConvertUTF16toUTF8 filenameUtf8(filename);
 | 
						|
  NS_ConvertUTF16toUTF8 messageUtf8(aMessage);
 | 
						|
 | 
						|
  // Actually crash.
 | 
						|
  MOZ_CRASH_UNSAFE_PRINTF("Failed ChromeUtils.releaseAssert(\"%s\") @ %s:%u",
 | 
						|
                          messageUtf8.get(), filenameUtf8.get(), lineNo);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::AddProfilerMarker(
 | 
						|
    GlobalObject& aGlobal, const nsACString& aName,
 | 
						|
    const ProfilerMarkerOptionsOrDouble& aOptions,
 | 
						|
    const Optional<nsACString>& aText) {
 | 
						|
  if (!profiler_thread_is_being_profiled_for_markers()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  MarkerOptions options;
 | 
						|
 | 
						|
  MarkerCategory category = ::geckoprofiler::category::JS;
 | 
						|
 | 
						|
  DOMHighResTimeStamp startTime = 0;
 | 
						|
  uint64_t innerWindowId = 0;
 | 
						|
  if (aOptions.IsDouble()) {
 | 
						|
    startTime = aOptions.GetAsDouble();
 | 
						|
  } else {
 | 
						|
    const ProfilerMarkerOptions& opt = aOptions.GetAsProfilerMarkerOptions();
 | 
						|
    startTime = opt.mStartTime;
 | 
						|
    innerWindowId = opt.mInnerWindowId;
 | 
						|
 | 
						|
    if (opt.mCaptureStack) {
 | 
						|
      // If we will be capturing a stack, change the category of the
 | 
						|
      // ChromeUtils.addProfilerMarker label automatically added by the webidl
 | 
						|
      // binding from DOM to PROFILER so that this function doesn't appear in
 | 
						|
      // the marker stack.
 | 
						|
      JSContext* cx = aGlobal.Context();
 | 
						|
      ProfilingStack* stack = js::GetContextProfilingStackIfEnabled(cx);
 | 
						|
      if (MOZ_LIKELY(stack)) {
 | 
						|
        uint32_t sp = stack->stackPointer;
 | 
						|
        if (MOZ_LIKELY(sp > 0)) {
 | 
						|
          js::ProfilingStackFrame& frame = stack->frames[sp - 1];
 | 
						|
          if (frame.isLabelFrame() && "ChromeUtils"_ns.Equals(frame.label()) &&
 | 
						|
              "addProfilerMarker"_ns.Equals(frame.dynamicString())) {
 | 
						|
            frame.setLabelCategory(JS::ProfilingCategoryPair::PROFILER);
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      options.Set(MarkerStack::Capture());
 | 
						|
    }
 | 
						|
#define BEGIN_CATEGORY(name, labelAsString, color) \
 | 
						|
  if (opt.mCategory.Equals(labelAsString)) {       \
 | 
						|
    category = ::geckoprofiler::category::name;    \
 | 
						|
  } else
 | 
						|
#define SUBCATEGORY(supercategory, name, labelAsString)
 | 
						|
#define END_CATEGORY
 | 
						|
    MOZ_PROFILING_CATEGORY_LIST(BEGIN_CATEGORY, SUBCATEGORY, END_CATEGORY)
 | 
						|
#undef BEGIN_CATEGORY
 | 
						|
#undef SUBCATEGORY
 | 
						|
#undef END_CATEGORY
 | 
						|
    {
 | 
						|
      category = ::geckoprofiler::category::OTHER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (startTime) {
 | 
						|
    RefPtr<Performance> performance;
 | 
						|
 | 
						|
    if (NS_IsMainThread()) {
 | 
						|
      nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
 | 
						|
          do_QueryInterface(aGlobal.GetAsSupports());
 | 
						|
      if (ownerWindow) {
 | 
						|
        performance = ownerWindow->GetPerformance();
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      JSContext* cx = aGlobal.Context();
 | 
						|
      WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
 | 
						|
      if (workerPrivate) {
 | 
						|
        performance = workerPrivate->GlobalScope()->GetPerformance();
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (performance) {
 | 
						|
      options.Set(MarkerTiming::IntervalUntilNowFrom(
 | 
						|
          performance->CreationTimeStamp() +
 | 
						|
          TimeDuration::FromMilliseconds(startTime)));
 | 
						|
    } else {
 | 
						|
      options.Set(MarkerTiming::IntervalUntilNowFrom(
 | 
						|
          TimeStamp::ProcessCreation() +
 | 
						|
          TimeDuration::FromMilliseconds(startTime)));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (innerWindowId) {
 | 
						|
    options.Set(MarkerInnerWindowId(innerWindowId));
 | 
						|
  } else {
 | 
						|
    options.Set(MarkerInnerWindowIdFromJSContext(aGlobal.Context()));
 | 
						|
  }
 | 
						|
 | 
						|
  {
 | 
						|
    AUTO_PROFILER_STATS(ChromeUtils_AddProfilerMarker);
 | 
						|
    if (aText.WasPassed()) {
 | 
						|
      profiler_add_marker(aName, category, std::move(options),
 | 
						|
                          ::geckoprofiler::markers::TextMarker{},
 | 
						|
                          aText.Value());
 | 
						|
    } else {
 | 
						|
      profiler_add_marker(aName, category, std::move(options));
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::GetXPCOMErrorName(GlobalObject& aGlobal, uint32_t aErrorCode,
 | 
						|
                                    nsACString& aRetval) {
 | 
						|
  GetErrorName((nsresult)aErrorCode, aRetval);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::WaiveXrays(GlobalObject& aGlobal, JS::Handle<JS::Value> aVal,
 | 
						|
                             JS::MutableHandle<JS::Value> aRetval,
 | 
						|
                             ErrorResult& aRv) {
 | 
						|
  JS::Rooted<JS::Value> value(aGlobal.Context(), aVal);
 | 
						|
  if (!xpc::WrapperFactory::WaiveXrayAndWrap(aGlobal.Context(), &value)) {
 | 
						|
    aRv.NoteJSContextException(aGlobal.Context());
 | 
						|
  } else {
 | 
						|
    aRetval.set(value);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::UnwaiveXrays(GlobalObject& aGlobal,
 | 
						|
                               JS::Handle<JS::Value> aVal,
 | 
						|
                               JS::MutableHandle<JS::Value> aRetval,
 | 
						|
                               ErrorResult& aRv) {
 | 
						|
  if (!aVal.isObject()) {
 | 
						|
    aRetval.set(aVal);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> obj(aGlobal.Context(),
 | 
						|
                            js::UncheckedUnwrap(&aVal.toObject()));
 | 
						|
  if (!JS_WrapObject(aGlobal.Context(), &obj)) {
 | 
						|
    aRv.NoteJSContextException(aGlobal.Context());
 | 
						|
  } else {
 | 
						|
    aRetval.setObject(*obj);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::GetClassName(GlobalObject& aGlobal,
 | 
						|
                               JS::Handle<JSObject*> aObj, bool aUnwrap,
 | 
						|
                               nsAString& aRetval) {
 | 
						|
  JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
 | 
						|
  if (aUnwrap) {
 | 
						|
    obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
 | 
						|
  }
 | 
						|
 | 
						|
  aRetval = NS_ConvertUTF8toUTF16(nsDependentCString(JS::GetClass(obj)->name));
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
bool ChromeUtils::IsDOMObject(GlobalObject& aGlobal, JS::Handle<JSObject*> aObj,
 | 
						|
                              bool aUnwrap) {
 | 
						|
  JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
 | 
						|
  if (aUnwrap) {
 | 
						|
    obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
 | 
						|
  }
 | 
						|
 | 
						|
  return mozilla::dom::IsDOMObject(obj);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
bool ChromeUtils::IsISOStyleDate(GlobalObject& aGlobal,
 | 
						|
                                 const nsACString& aStr) {
 | 
						|
  // aStr is a UTF-8 string, however we can cast to JS::Latin1Chars
 | 
						|
  // because JS::IsISOStyleDate handles ASCII only
 | 
						|
  return JS::IsISOStyleDate(aGlobal.Context(),
 | 
						|
                            JS::Latin1Chars(aStr.Data(), aStr.Length()));
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::ShallowClone(GlobalObject& aGlobal,
 | 
						|
                               JS::Handle<JSObject*> aObj,
 | 
						|
                               JS::Handle<JSObject*> aTarget,
 | 
						|
                               JS::MutableHandle<JSObject*> aRetval,
 | 
						|
                               ErrorResult& aRv) {
 | 
						|
  JSContext* cx = aGlobal.Context();
 | 
						|
 | 
						|
  auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
 | 
						|
 | 
						|
  JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
 | 
						|
  JS::RootedVector<JS::Value> values(cx);
 | 
						|
  JS::RootedVector<jsid> valuesIds(cx);
 | 
						|
 | 
						|
  {
 | 
						|
    // cx represents our current Realm, so it makes sense to use it for the
 | 
						|
    // CheckedUnwrapDynamic call.  We do want CheckedUnwrapDynamic, in case
 | 
						|
    // someone is shallow-cloning a Window.
 | 
						|
    JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapDynamic(aObj, cx));
 | 
						|
    if (!obj) {
 | 
						|
      js::ReportAccessDenied(cx);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (js::IsScriptedProxy(obj)) {
 | 
						|
      JS_ReportErrorASCII(cx, "Shallow cloning a proxy object is not allowed");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    JSAutoRealm ar(cx, obj);
 | 
						|
 | 
						|
    if (!JS_Enumerate(cx, obj, &ids) || !values.reserve(ids.length()) ||
 | 
						|
        !valuesIds.reserve(ids.length())) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    JS::Rooted<Maybe<JS::PropertyDescriptor>> desc(cx);
 | 
						|
    JS::Rooted<JS::PropertyKey> id(cx);
 | 
						|
    for (jsid idVal : ids) {
 | 
						|
      id = idVal;
 | 
						|
      if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      if (desc.isNothing() || desc->isAccessorDescriptor()) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      valuesIds.infallibleAppend(id);
 | 
						|
      values.infallibleAppend(desc->value());
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> obj(cx);
 | 
						|
  {
 | 
						|
    Maybe<JSAutoRealm> ar;
 | 
						|
    if (aTarget) {
 | 
						|
      // Our target could be anything, so we want CheckedUnwrapDynamic here.
 | 
						|
      // "cx" represents the current Realm when we were called from bindings, so
 | 
						|
      // we can just use that.
 | 
						|
      JS::Rooted<JSObject*> target(cx, js::CheckedUnwrapDynamic(aTarget, cx));
 | 
						|
      if (!target) {
 | 
						|
        js::ReportAccessDenied(cx);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      ar.emplace(cx, target);
 | 
						|
    }
 | 
						|
 | 
						|
    obj = JS_NewPlainObject(cx);
 | 
						|
    if (!obj) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    JS::Rooted<JS::Value> value(cx);
 | 
						|
    JS::Rooted<JS::PropertyKey> id(cx);
 | 
						|
    for (uint32_t i = 0; i < valuesIds.length(); i++) {
 | 
						|
      id = valuesIds[i];
 | 
						|
      value = values[i];
 | 
						|
 | 
						|
      JS_MarkCrossZoneId(cx, id);
 | 
						|
      if (!JS_WrapValue(cx, &value) ||
 | 
						|
          !JS_SetPropertyById(cx, obj, id, value)) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (aTarget && !JS_WrapObject(cx, &obj)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  cleanup.release();
 | 
						|
  aRetval.set(obj);
 | 
						|
}
 | 
						|
 | 
						|
namespace {
 | 
						|
class IdleDispatchRunnable final : public IdleRunnable,
 | 
						|
                                   public nsITimerCallback {
 | 
						|
 public:
 | 
						|
  NS_DECL_ISUPPORTS_INHERITED
 | 
						|
 | 
						|
  IdleDispatchRunnable(nsIGlobalObject* aParent, IdleRequestCallback& aCallback)
 | 
						|
      : IdleRunnable("ChromeUtils::IdleDispatch"),
 | 
						|
        mCallback(&aCallback),
 | 
						|
        mParent(aParent) {}
 | 
						|
 | 
						|
  // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT.
 | 
						|
  // See bug 1535398.
 | 
						|
  MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
 | 
						|
    if (mCallback) {
 | 
						|
      CancelTimer();
 | 
						|
 | 
						|
      auto deadline = mDeadline - TimeStamp::ProcessCreation();
 | 
						|
 | 
						|
      ErrorResult rv;
 | 
						|
      RefPtr<IdleDeadline> idleDeadline =
 | 
						|
          new IdleDeadline(mParent, mTimedOut, deadline.ToMilliseconds());
 | 
						|
 | 
						|
      RefPtr<IdleRequestCallback> callback(std::move(mCallback));
 | 
						|
      MOZ_ASSERT(!mCallback);
 | 
						|
      callback->Call(*idleDeadline, "ChromeUtils::IdleDispatch handler");
 | 
						|
      mParent = nullptr;
 | 
						|
    }
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  void SetDeadline(TimeStamp aDeadline) override { mDeadline = aDeadline; }
 | 
						|
 | 
						|
  NS_IMETHOD Notify(nsITimer* aTimer) override {
 | 
						|
    mTimedOut = true;
 | 
						|
    SetDeadline(TimeStamp::Now());
 | 
						|
    return Run();
 | 
						|
  }
 | 
						|
 | 
						|
  void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override {
 | 
						|
    MOZ_ASSERT(aTarget);
 | 
						|
    MOZ_ASSERT(!mTimer);
 | 
						|
    NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, aDelay,
 | 
						|
                            nsITimer::TYPE_ONE_SHOT, aTarget);
 | 
						|
  }
 | 
						|
 | 
						|
 protected:
 | 
						|
  virtual ~IdleDispatchRunnable() { CancelTimer(); }
 | 
						|
 | 
						|
 private:
 | 
						|
  void CancelTimer() {
 | 
						|
    if (mTimer) {
 | 
						|
      mTimer->Cancel();
 | 
						|
      mTimer = nullptr;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<IdleRequestCallback> mCallback;
 | 
						|
  nsCOMPtr<nsIGlobalObject> mParent;
 | 
						|
 | 
						|
  nsCOMPtr<nsITimer> mTimer;
 | 
						|
 | 
						|
  TimeStamp mDeadline{};
 | 
						|
  bool mTimedOut = false;
 | 
						|
};
 | 
						|
 | 
						|
NS_IMPL_ISUPPORTS_INHERITED(IdleDispatchRunnable, IdleRunnable,
 | 
						|
                            nsITimerCallback)
 | 
						|
}  // anonymous namespace
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::IdleDispatch(const GlobalObject& aGlobal,
 | 
						|
                               IdleRequestCallback& aCallback,
 | 
						|
                               const IdleRequestOptions& aOptions,
 | 
						|
                               ErrorResult& aRv) {
 | 
						|
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 | 
						|
  MOZ_ASSERT(global);
 | 
						|
 | 
						|
  auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback);
 | 
						|
 | 
						|
  if (aOptions.mTimeout.WasPassed()) {
 | 
						|
    aRv = NS_DispatchToCurrentThreadQueue(
 | 
						|
        runnable.forget(), aOptions.mTimeout.Value(), EventQueuePriority::Idle);
 | 
						|
  } else {
 | 
						|
    aRv = NS_DispatchToCurrentThreadQueue(runnable.forget(),
 | 
						|
                                          EventQueuePriority::Idle);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::Import(const GlobalObject& aGlobal,
 | 
						|
                         const nsACString& aResourceURI,
 | 
						|
                         const Optional<JS::Handle<JSObject*>>& aTargetObj,
 | 
						|
                         JS::MutableHandle<JSObject*> aRetval,
 | 
						|
                         ErrorResult& aRv) {
 | 
						|
  RefPtr moduleloader = mozJSModuleLoader::Get();
 | 
						|
  MOZ_ASSERT(moduleloader);
 | 
						|
 | 
						|
  AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE("ChromeUtils::Import",
 | 
						|
                                                     OTHER, aResourceURI);
 | 
						|
 | 
						|
  JSContext* cx = aGlobal.Context();
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> global(cx);
 | 
						|
  JS::Rooted<JSObject*> exports(cx);
 | 
						|
  nsresult rv = moduleloader->Import(cx, aResourceURI, &global, &exports);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    aRv.Throw(rv);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Import() on the component loader can return NS_OK while leaving an
 | 
						|
  // exception on the JSContext.  Check for that case.
 | 
						|
  if (JS_IsExceptionPending(cx)) {
 | 
						|
    aRv.NoteJSContextException(cx);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (aTargetObj.WasPassed()) {
 | 
						|
    if (!JS_AssignObject(cx, aTargetObj.Value(), exports)) {
 | 
						|
      aRv.Throw(NS_ERROR_FAILURE);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!JS_WrapObject(cx, &exports)) {
 | 
						|
    aRv.Throw(NS_ERROR_FAILURE);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  aRetval.set(exports);
 | 
						|
}
 | 
						|
 | 
						|
static mozJSModuleLoader* GetModuleLoaderForCurrentGlobal(
 | 
						|
    JSContext* aCx, const GlobalObject& aGlobal,
 | 
						|
    Maybe<loader::NonSharedGlobalSyncModuleLoaderScope>&
 | 
						|
        aMaybeSyncLoaderScope) {
 | 
						|
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 | 
						|
 | 
						|
  if (mozJSModuleLoader::IsSharedSystemGlobal(global)) {
 | 
						|
    return mozJSModuleLoader::Get();
 | 
						|
  }
 | 
						|
  if (mozJSModuleLoader::IsDevToolsLoaderGlobal(global)) {
 | 
						|
    return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
 | 
						|
  }
 | 
						|
 | 
						|
  if (loader::NonSharedGlobalSyncModuleLoaderScope::IsActive()) {
 | 
						|
    mozJSModuleLoader* moduleloader =
 | 
						|
        loader::NonSharedGlobalSyncModuleLoaderScope::ActiveLoader();
 | 
						|
 | 
						|
    if (!moduleloader->IsLoaderGlobal(global->GetGlobalJSObject())) {
 | 
						|
      JS_ReportErrorASCII(aCx,
 | 
						|
                          "global: \"current\" option cannot be used for "
 | 
						|
                          "different global while other importESModule "
 | 
						|
                          "with global: \"current\" is on the stack");
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
    return moduleloader;
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr targetModuleLoader = global->GetModuleLoader(aCx);
 | 
						|
  if (!targetModuleLoader) {
 | 
						|
    // Sandbox without associated window returns nullptr for GetModuleLoader.
 | 
						|
    js::DumpBacktrace(aCx);
 | 
						|
    JS_ReportErrorASCII(aCx, "No ModuleLoader found for the current context");
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  if (targetModuleLoader->HasFetchingModules()) {
 | 
						|
    if (!NS_IsMainThread()) {
 | 
						|
      JS_ReportErrorASCII(aCx,
 | 
						|
                          "ChromeUtils.importESModule cannot be used in worker "
 | 
						|
                          "when there is ongoing dynamic import");
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!mozilla::SpinEventLoopUntil(
 | 
						|
            "importESModule for current global"_ns, [&]() -> bool {
 | 
						|
              return !targetModuleLoader->HasFetchingModules();
 | 
						|
            })) {
 | 
						|
      JS_ReportErrorASCII(aCx, "Failed to wait for ongoing module requests");
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  aMaybeSyncLoaderScope.emplace(aCx, global);
 | 
						|
  return aMaybeSyncLoaderScope->ActiveLoader();
 | 
						|
}
 | 
						|
 | 
						|
static mozJSModuleLoader* GetModuleLoaderForOptions(
 | 
						|
    JSContext* aCx, const GlobalObject& aGlobal,
 | 
						|
    const ImportESModuleOptionsDictionary& aOptions,
 | 
						|
    Maybe<loader::NonSharedGlobalSyncModuleLoaderScope>&
 | 
						|
        aMaybeSyncLoaderScope) {
 | 
						|
  if (!aOptions.mGlobal.WasPassed()) {
 | 
						|
    return mozJSModuleLoader::Get();
 | 
						|
  }
 | 
						|
 | 
						|
  switch (aOptions.mGlobal.Value()) {
 | 
						|
    case ImportESModuleTargetGlobal::Shared:
 | 
						|
      return mozJSModuleLoader::Get();
 | 
						|
 | 
						|
    case ImportESModuleTargetGlobal::Devtools:
 | 
						|
      return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
 | 
						|
 | 
						|
    case ImportESModuleTargetGlobal::Contextual: {
 | 
						|
      if (!NS_IsMainThread()) {
 | 
						|
        return GetModuleLoaderForCurrentGlobal(aCx, aGlobal,
 | 
						|
                                               aMaybeSyncLoaderScope);
 | 
						|
      }
 | 
						|
 | 
						|
      RefPtr devToolsModuleloader = mozJSModuleLoader::GetDevToolsLoader();
 | 
						|
      if (devToolsModuleloader &&
 | 
						|
          devToolsModuleloader->IsLoaderGlobal(aGlobal.Get())) {
 | 
						|
        return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
 | 
						|
      }
 | 
						|
      return mozJSModuleLoader::Get();
 | 
						|
    }
 | 
						|
 | 
						|
    case ImportESModuleTargetGlobal::Current:
 | 
						|
      return GetModuleLoaderForCurrentGlobal(aCx, aGlobal,
 | 
						|
                                             aMaybeSyncLoaderScope);
 | 
						|
 | 
						|
    default:
 | 
						|
      MOZ_CRASH("Unknown ImportESModuleTargetGlobal");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static bool ValidateImportOptions(
 | 
						|
    JSContext* aCx, const GlobalObject& aGlobal,
 | 
						|
    const ImportESModuleOptionsDictionary& aOptions) {
 | 
						|
  if (!NS_IsMainThread() &&
 | 
						|
      (!aOptions.mGlobal.WasPassed() ||
 | 
						|
       (aOptions.mGlobal.Value() != ImportESModuleTargetGlobal::Current &&
 | 
						|
        aOptions.mGlobal.Value() != ImportESModuleTargetGlobal::Contextual))) {
 | 
						|
    JS_ReportErrorASCII(aCx,
 | 
						|
                        "ChromeUtils.importESModule: Only { global: "
 | 
						|
                        "\"current\" } and { global: \"contextual\" } options "
 | 
						|
                        "are supported on worker");
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NS_IsMainThread()) {
 | 
						|
    nsCOMPtr<nsIGlobalObject> global =
 | 
						|
        do_QueryInterface(aGlobal.GetAsSupports());
 | 
						|
 | 
						|
    if (mozJSModuleLoader::IsDevToolsLoaderGlobal(global) &&
 | 
						|
        !aOptions.mGlobal.WasPassed()) {
 | 
						|
      JS_ReportErrorASCII(aCx,
 | 
						|
                          "ChromeUtils.importESModule: global option is "
 | 
						|
                          "required in DevTools distinct global");
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::ImportESModule(
 | 
						|
    const GlobalObject& aGlobal, const nsAString& aResourceURI,
 | 
						|
    const ImportESModuleOptionsDictionary& aOptions,
 | 
						|
    JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) {
 | 
						|
  JSContext* cx = aGlobal.Context();
 | 
						|
 | 
						|
  if (!ValidateImportOptions(cx, aGlobal, aOptions)) {
 | 
						|
    aRv.Throw(NS_ERROR_FAILURE);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Maybe<loader::NonSharedGlobalSyncModuleLoaderScope> maybeSyncLoaderScope;
 | 
						|
  RefPtr<mozJSModuleLoader> moduleloader =
 | 
						|
      GetModuleLoaderForOptions(cx, aGlobal, aOptions, maybeSyncLoaderScope);
 | 
						|
  if (!moduleloader) {
 | 
						|
    aRv.Throw(NS_ERROR_FAILURE);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  NS_ConvertUTF16toUTF8 registryLocation(aResourceURI);
 | 
						|
 | 
						|
  AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE(
 | 
						|
      "ChromeUtils::ImportESModule", OTHER, registryLocation);
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> moduleNamespace(cx);
 | 
						|
  nsresult rv =
 | 
						|
      moduleloader->ImportESModule(cx, registryLocation, &moduleNamespace);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    aRv.Throw(rv);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
 | 
						|
 | 
						|
  if (!JS_WrapObject(cx, &moduleNamespace)) {
 | 
						|
    aRv.Throw(NS_ERROR_FAILURE);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  aRetval.set(moduleNamespace);
 | 
						|
 | 
						|
  if (maybeSyncLoaderScope) {
 | 
						|
    maybeSyncLoaderScope->Finish();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// An integer encoding for ImportESModuleOptionsDictionary, to pass the value
 | 
						|
// to the lazy getters.
 | 
						|
class EncodedOptions {
 | 
						|
 public:
 | 
						|
  explicit EncodedOptions(const ImportESModuleOptionsDictionary& aOptions) {
 | 
						|
    if (aOptions.mGlobal.WasPassed()) {
 | 
						|
      mValue = uint32_t(aOptions.mGlobal.Value()) + 1;
 | 
						|
    } else {
 | 
						|
      mValue = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  explicit EncodedOptions(uint32_t aValue) : mValue(aValue) {}
 | 
						|
 | 
						|
  int32_t toInt32() const { return int32_t(mValue); }
 | 
						|
 | 
						|
  void DecodeInto(ImportESModuleOptionsDictionary& aOptions) {
 | 
						|
    if (mValue == 0) {
 | 
						|
      aOptions.mGlobal.Reset();
 | 
						|
    } else {
 | 
						|
      aOptions.mGlobal.Construct(ImportESModuleTargetGlobal(mValue - 1));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  uint32_t mValue = 0;
 | 
						|
};
 | 
						|
 | 
						|
namespace lazy_getter {
 | 
						|
 | 
						|
// The property id of the getter.
 | 
						|
// Used by all lazy getters.
 | 
						|
static const size_t SLOT_ID = 0;
 | 
						|
 | 
						|
// The URI of the module to import.
 | 
						|
// Used by ChromeUtils.defineModuleGetter and ChromeUtils.defineESModuleGetters.
 | 
						|
static const size_t SLOT_URI = 1;
 | 
						|
 | 
						|
// An array object that contians values for PARAM_INDEX_TARGET and
 | 
						|
// PARAM_INDEX_LAMBDA.
 | 
						|
// Used by ChromeUtils.defineLazyGetter.
 | 
						|
static const size_t SLOT_PARAMS = 1;
 | 
						|
 | 
						|
// The EncodedOptions value.
 | 
						|
// Used by ChromeUtils.defineESModuleGetters.
 | 
						|
static const size_t SLOT_OPTIONS = 2;
 | 
						|
 | 
						|
static const size_t PARAM_INDEX_TARGET = 0;
 | 
						|
static const size_t PARAM_INDEX_LAMBDA = 1;
 | 
						|
static const size_t PARAMS_COUNT = 2;
 | 
						|
 | 
						|
static bool ExtractArgs(JSContext* aCx, JS::CallArgs& aArgs,
 | 
						|
                        JS::MutableHandle<JSObject*> aCallee,
 | 
						|
                        JS::MutableHandle<JSObject*> aThisObj,
 | 
						|
                        JS::MutableHandle<jsid> aId) {
 | 
						|
  aCallee.set(&aArgs.callee());
 | 
						|
 | 
						|
  JS::Handle<JS::Value> thisv = aArgs.thisv();
 | 
						|
  if (!thisv.isObject()) {
 | 
						|
    JS_ReportErrorASCII(aCx, "Invalid target object");
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  aThisObj.set(&thisv.toObject());
 | 
						|
 | 
						|
  JS::Rooted<JS::Value> id(aCx,
 | 
						|
                           js::GetFunctionNativeReserved(aCallee, SLOT_ID));
 | 
						|
  MOZ_ALWAYS_TRUE(JS_ValueToId(aCx, id, aId));
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
static bool JSLazyGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
 | 
						|
  JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> callee(aCx);
 | 
						|
  JS::Rooted<JSObject*> unused(aCx);
 | 
						|
  JS::Rooted<jsid> id(aCx);
 | 
						|
  if (!ExtractArgs(aCx, args, &callee, &unused, &id)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  JS::Rooted<JS::Value> paramsVal(
 | 
						|
      aCx, js::GetFunctionNativeReserved(callee, SLOT_PARAMS));
 | 
						|
  if (paramsVal.isUndefined()) {
 | 
						|
    args.rval().setUndefined();
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  // Avoid calling the lambda multiple times, in case of:
 | 
						|
  //   * the getter function is retrieved from property descriptor and called
 | 
						|
  //   * the lambda gets the property again
 | 
						|
  //   * the getter function throws and accessed again
 | 
						|
  js::SetFunctionNativeReserved(callee, SLOT_PARAMS, JS::UndefinedHandleValue);
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> paramsObj(aCx, ¶msVal.toObject());
 | 
						|
 | 
						|
  JS::Rooted<JS::Value> targetVal(aCx);
 | 
						|
  JS::Rooted<JS::Value> lambdaVal(aCx);
 | 
						|
  if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_TARGET, &targetVal)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_LAMBDA, &lambdaVal)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> targetObj(aCx, &targetVal.toObject());
 | 
						|
 | 
						|
  JS::Rooted<JS::Value> value(aCx);
 | 
						|
  if (!JS::Call(aCx, targetObj, lambdaVal, JS::HandleValueArray::empty(),
 | 
						|
                &value)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!JS_DefinePropertyById(aCx, targetObj, id, value, JSPROP_ENUMERATE)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  args.rval().set(value);
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
static bool DefineLazyGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
 | 
						|
                             JS::Handle<JS::Value> aName,
 | 
						|
                             JS::Handle<JSObject*> aLambda) {
 | 
						|
  JS::Rooted<jsid> id(aCx);
 | 
						|
  if (!JS_ValueToId(aCx, aName, &id)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> getter(
 | 
						|
      aCx, JS_GetFunctionObject(
 | 
						|
               js::NewFunctionByIdWithReserved(aCx, JSLazyGetter, 0, 0, id)));
 | 
						|
  if (!getter) {
 | 
						|
    JS_ReportOutOfMemory(aCx);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  JS::RootedVector<JS::Value> params(aCx);
 | 
						|
  if (!params.resize(PARAMS_COUNT)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  params[PARAM_INDEX_TARGET].setObject(*aTarget);
 | 
						|
  params[PARAM_INDEX_LAMBDA].setObject(*aLambda);
 | 
						|
  JS::Rooted<JSObject*> paramsObj(aCx, JS::NewArrayObject(aCx, params));
 | 
						|
  if (!paramsObj) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  js::SetFunctionNativeReserved(getter, SLOT_ID, aName);
 | 
						|
  js::SetFunctionNativeReserved(getter, SLOT_PARAMS,
 | 
						|
                                JS::ObjectValue(*paramsObj));
 | 
						|
 | 
						|
  return JS_DefinePropertyById(aCx, aTarget, id, getter, nullptr,
 | 
						|
                               JSPROP_ENUMERATE);
 | 
						|
}
 | 
						|
 | 
						|
enum class ModuleType { JSM, ESM };
 | 
						|
 | 
						|
static bool ModuleGetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
 | 
						|
                             ModuleType aType) {
 | 
						|
  JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> callee(aCx);
 | 
						|
  JS::Rooted<JSObject*> thisObj(aCx);
 | 
						|
  JS::Rooted<jsid> id(aCx);
 | 
						|
  if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  JS::Rooted<JSString*> moduleURI(
 | 
						|
      aCx, js::GetFunctionNativeReserved(callee, SLOT_URI).toString());
 | 
						|
  JS::UniqueChars bytes = JS_EncodeStringToUTF8(aCx, moduleURI);
 | 
						|
  if (!bytes) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  nsDependentCString uri(bytes.get());
 | 
						|
 | 
						|
  JS::Rooted<JS::Value> value(aCx);
 | 
						|
  if (aType == ModuleType::JSM) {
 | 
						|
    RefPtr moduleloader = mozJSModuleLoader::Get();
 | 
						|
    MOZ_ASSERT(moduleloader);
 | 
						|
 | 
						|
    JS::Rooted<JSObject*> moduleGlobal(aCx);
 | 
						|
    JS::Rooted<JSObject*> moduleExports(aCx);
 | 
						|
    nsresult rv = moduleloader->Import(aCx, uri, &moduleGlobal, &moduleExports);
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      Throw(aCx, rv);
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    // JSM's exports is from the same realm.
 | 
						|
    if (!JS_GetPropertyById(aCx, moduleExports, id, &value)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    EncodedOptions encodedOptions(
 | 
						|
        js::GetFunctionNativeReserved(callee, SLOT_OPTIONS).toInt32());
 | 
						|
 | 
						|
    ImportESModuleOptionsDictionary options;
 | 
						|
    encodedOptions.DecodeInto(options);
 | 
						|
 | 
						|
    GlobalObject global(aCx, callee);
 | 
						|
 | 
						|
    Maybe<loader::NonSharedGlobalSyncModuleLoaderScope> maybeSyncLoaderScope;
 | 
						|
    RefPtr<mozJSModuleLoader> moduleloader =
 | 
						|
        GetModuleLoaderForOptions(aCx, global, options, maybeSyncLoaderScope);
 | 
						|
    if (!moduleloader) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    JS::Rooted<JSObject*> moduleNamespace(aCx);
 | 
						|
    nsresult rv = moduleloader->ImportESModule(aCx, uri, &moduleNamespace);
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      Throw(aCx, rv);
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    // ESM's namespace is from the module's realm.
 | 
						|
    {
 | 
						|
      JSAutoRealm ar(aCx, moduleNamespace);
 | 
						|
      if (!JS_GetPropertyById(aCx, moduleNamespace, id, &value)) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (!JS_WrapValue(aCx, &value)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    if (maybeSyncLoaderScope) {
 | 
						|
      maybeSyncLoaderScope->Finish();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!JS_DefinePropertyById(aCx, thisObj, id, value, JSPROP_ENUMERATE)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  args.rval().set(value);
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
static bool JSModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
 | 
						|
  return ModuleGetterImpl(aCx, aArgc, aVp, ModuleType::JSM);
 | 
						|
}
 | 
						|
 | 
						|
static bool ESModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
 | 
						|
  return ModuleGetterImpl(aCx, aArgc, aVp, ModuleType::ESM);
 | 
						|
}
 | 
						|
 | 
						|
static bool ModuleSetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
 | 
						|
  JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> callee(aCx);
 | 
						|
  JS::Rooted<JSObject*> thisObj(aCx);
 | 
						|
  JS::Rooted<jsid> id(aCx);
 | 
						|
  if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  return JS_DefinePropertyById(aCx, thisObj, id, args.get(0), JSPROP_ENUMERATE);
 | 
						|
}
 | 
						|
 | 
						|
static bool JSModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
 | 
						|
  return ModuleSetterImpl(aCx, aArgc, aVp);
 | 
						|
}
 | 
						|
 | 
						|
static bool ESModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
 | 
						|
  return ModuleSetterImpl(aCx, aArgc, aVp);
 | 
						|
}
 | 
						|
 | 
						|
static bool DefineJSModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
 | 
						|
                                 const nsAString& aId,
 | 
						|
                                 const nsAString& aResourceURI) {
 | 
						|
  JS::Rooted<JS::Value> uri(aCx);
 | 
						|
  JS::Rooted<JS::Value> idValue(aCx);
 | 
						|
  JS::Rooted<jsid> id(aCx);
 | 
						|
  if (!xpc::NonVoidStringToJsval(aCx, aResourceURI, &uri) ||
 | 
						|
      !xpc::NonVoidStringToJsval(aCx, aId, &idValue) ||
 | 
						|
      !JS_ValueToId(aCx, idValue, &id)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  idValue = js::IdToValue(id);
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> getter(
 | 
						|
      aCx, JS_GetFunctionObject(
 | 
						|
               js::NewFunctionByIdWithReserved(aCx, JSModuleGetter, 0, 0, id)));
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> setter(
 | 
						|
      aCx, JS_GetFunctionObject(
 | 
						|
               js::NewFunctionByIdWithReserved(aCx, JSModuleSetter, 0, 0, id)));
 | 
						|
 | 
						|
  if (!getter || !setter) {
 | 
						|
    JS_ReportOutOfMemory(aCx);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  js::SetFunctionNativeReserved(getter, SLOT_ID, idValue);
 | 
						|
  js::SetFunctionNativeReserved(setter, SLOT_ID, idValue);
 | 
						|
 | 
						|
  js::SetFunctionNativeReserved(getter, SLOT_URI, uri);
 | 
						|
 | 
						|
  return JS_DefinePropertyById(aCx, aTarget, id, getter, setter,
 | 
						|
                               JSPROP_ENUMERATE);
 | 
						|
}
 | 
						|
 | 
						|
static bool DefineESModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
 | 
						|
                                 JS::Handle<JS::PropertyKey> aId,
 | 
						|
                                 JS::Handle<JS::Value> aResourceURI,
 | 
						|
                                 const EncodedOptions& encodedOptions) {
 | 
						|
  JS::Rooted<JS::Value> idVal(aCx, JS::StringValue(aId.toString()));
 | 
						|
 | 
						|
  JS::Rooted<JS::Value> optionsVal(aCx,
 | 
						|
                                   JS::Int32Value(encodedOptions.toInt32()));
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> getter(
 | 
						|
      aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
 | 
						|
               aCx, ESModuleGetter, 0, 0, aId)));
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> setter(
 | 
						|
      aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
 | 
						|
               aCx, ESModuleSetter, 0, 0, aId)));
 | 
						|
 | 
						|
  if (!getter || !setter) {
 | 
						|
    JS_ReportOutOfMemory(aCx);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  js::SetFunctionNativeReserved(getter, SLOT_ID, idVal);
 | 
						|
  js::SetFunctionNativeReserved(setter, SLOT_ID, idVal);
 | 
						|
 | 
						|
  js::SetFunctionNativeReserved(getter, SLOT_URI, aResourceURI);
 | 
						|
 | 
						|
  js::SetFunctionNativeReserved(getter, SLOT_OPTIONS, optionsVal);
 | 
						|
 | 
						|
  return JS_DefinePropertyById(aCx, aTarget, aId, getter, setter,
 | 
						|
                               JSPROP_ENUMERATE);
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace lazy_getter
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::DefineLazyGetter(const GlobalObject& aGlobal,
 | 
						|
                                   JS::Handle<JSObject*> aTarget,
 | 
						|
                                   JS::Handle<JS::Value> aName,
 | 
						|
                                   JS::Handle<JSObject*> aLambda,
 | 
						|
                                   ErrorResult& aRv) {
 | 
						|
  JSContext* cx = aGlobal.Context();
 | 
						|
  if (!lazy_getter::DefineLazyGetter(cx, aTarget, aName, aLambda)) {
 | 
						|
    aRv.NoteJSContextException(cx);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::DefineModuleGetter(const GlobalObject& global,
 | 
						|
                                     JS::Handle<JSObject*> target,
 | 
						|
                                     const nsAString& id,
 | 
						|
                                     const nsAString& resourceURI,
 | 
						|
                                     ErrorResult& aRv) {
 | 
						|
  if (!lazy_getter::DefineJSModuleGetter(global.Context(), target, id,
 | 
						|
                                         resourceURI)) {
 | 
						|
    aRv.NoteJSContextException(global.Context());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::DefineESModuleGetters(
 | 
						|
    const GlobalObject& global, JS::Handle<JSObject*> target,
 | 
						|
    JS::Handle<JSObject*> modules,
 | 
						|
    const ImportESModuleOptionsDictionary& aOptions, ErrorResult& aRv) {
 | 
						|
  JSContext* cx = global.Context();
 | 
						|
 | 
						|
  JS::Rooted<JS::IdVector> props(cx, JS::IdVector(cx));
 | 
						|
  if (!JS_Enumerate(cx, modules, &props)) {
 | 
						|
    aRv.NoteJSContextException(cx);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidateImportOptions(cx, global, aOptions)) {
 | 
						|
    aRv.Throw(NS_ERROR_FAILURE);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  EncodedOptions encodedOptions(aOptions);
 | 
						|
 | 
						|
  JS::Rooted<JS::PropertyKey> prop(cx);
 | 
						|
  JS::Rooted<JS::Value> resourceURIVal(cx);
 | 
						|
  for (JS::PropertyKey tmp : props) {
 | 
						|
    prop = tmp;
 | 
						|
 | 
						|
    if (!prop.isString()) {
 | 
						|
      aRv.Throw(NS_ERROR_FAILURE);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!JS_GetPropertyById(cx, modules, prop, &resourceURIVal)) {
 | 
						|
      aRv.NoteJSContextException(cx);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!lazy_getter::DefineESModuleGetter(cx, target, prop, resourceURIVal,
 | 
						|
                                           encodedOptions)) {
 | 
						|
      aRv.NoteJSContextException(cx);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
#ifdef XP_UNIX
 | 
						|
/* static */
 | 
						|
void ChromeUtils::GetLibcConstants(const GlobalObject&,
 | 
						|
                                   LibcConstants& aConsts) {
 | 
						|
  aConsts.mEINTR.Construct(EINTR);
 | 
						|
  aConsts.mEACCES.Construct(EACCES);
 | 
						|
  aConsts.mEAGAIN.Construct(EAGAIN);
 | 
						|
  aConsts.mEINVAL.Construct(EINVAL);
 | 
						|
  aConsts.mENOSYS.Construct(ENOSYS);
 | 
						|
 | 
						|
  aConsts.mF_SETFD.Construct(F_SETFD);
 | 
						|
  aConsts.mF_SETFL.Construct(F_SETFL);
 | 
						|
 | 
						|
  aConsts.mFD_CLOEXEC.Construct(FD_CLOEXEC);
 | 
						|
 | 
						|
  aConsts.mAT_EACCESS.Construct(AT_EACCESS);
 | 
						|
 | 
						|
  aConsts.mO_CREAT.Construct(O_CREAT);
 | 
						|
  aConsts.mO_NONBLOCK.Construct(O_NONBLOCK);
 | 
						|
  aConsts.mO_WRONLY.Construct(O_WRONLY);
 | 
						|
 | 
						|
  aConsts.mPOLLERR.Construct(POLLERR);
 | 
						|
  aConsts.mPOLLHUP.Construct(POLLHUP);
 | 
						|
  aConsts.mPOLLIN.Construct(POLLIN);
 | 
						|
  aConsts.mPOLLNVAL.Construct(POLLNVAL);
 | 
						|
  aConsts.mPOLLOUT.Construct(POLLOUT);
 | 
						|
 | 
						|
  aConsts.mWNOHANG.Construct(WNOHANG);
 | 
						|
 | 
						|
#  ifdef XP_LINUX
 | 
						|
  aConsts.mPR_CAPBSET_READ.Construct(PR_CAPBSET_READ);
 | 
						|
#  endif
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::OriginAttributesToSuffix(
 | 
						|
    dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
 | 
						|
    nsCString& aSuffix)
 | 
						|
 | 
						|
{
 | 
						|
  OriginAttributes attrs(aAttrs);
 | 
						|
  attrs.CreateSuffix(aSuffix);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
bool ChromeUtils::OriginAttributesMatchPattern(
 | 
						|
    dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
 | 
						|
    const dom::OriginAttributesPatternDictionary& aPattern) {
 | 
						|
  OriginAttributes attrs(aAttrs);
 | 
						|
  OriginAttributesPattern pattern(aPattern);
 | 
						|
  return pattern.Matches(attrs);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::CreateOriginAttributesFromOrigin(
 | 
						|
    dom::GlobalObject& aGlobal, const nsAString& aOrigin,
 | 
						|
    dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
 | 
						|
  OriginAttributes attrs;
 | 
						|
  nsAutoCString suffix;
 | 
						|
  if (!attrs.PopulateFromOrigin(NS_ConvertUTF16toUTF8(aOrigin), suffix)) {
 | 
						|
    aRv.Throw(NS_ERROR_FAILURE);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  aAttrs = attrs;
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::CreateOriginAttributesFromOriginSuffix(
 | 
						|
    dom::GlobalObject& aGlobal, const nsAString& aSuffix,
 | 
						|
    dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
 | 
						|
  OriginAttributes attrs;
 | 
						|
  nsAutoCString suffix;
 | 
						|
  if (!attrs.PopulateFromSuffix(NS_ConvertUTF16toUTF8(aSuffix))) {
 | 
						|
    aRv.Throw(NS_ERROR_FAILURE);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  aAttrs = attrs;
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::FillNonDefaultOriginAttributes(
 | 
						|
    dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
 | 
						|
    dom::OriginAttributesDictionary& aNewAttrs) {
 | 
						|
  aNewAttrs = aAttrs;
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
bool ChromeUtils::IsOriginAttributesEqual(
 | 
						|
    dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aA,
 | 
						|
    const dom::OriginAttributesDictionary& aB) {
 | 
						|
  return IsOriginAttributesEqual(aA, aB);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
bool ChromeUtils::IsOriginAttributesEqual(
 | 
						|
    const dom::OriginAttributesDictionary& aA,
 | 
						|
    const dom::OriginAttributesDictionary& aB) {
 | 
						|
  return aA == aB;
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::GetBaseDomainFromPartitionKey(dom::GlobalObject& aGlobal,
 | 
						|
                                                const nsAString& aPartitionKey,
 | 
						|
                                                nsAString& aBaseDomain,
 | 
						|
                                                ErrorResult& aRv) {
 | 
						|
  nsString scheme;
 | 
						|
  nsString pkBaseDomain;
 | 
						|
  int32_t port;
 | 
						|
 | 
						|
  if (!mozilla::OriginAttributes::ParsePartitionKey(aPartitionKey, scheme,
 | 
						|
                                                    pkBaseDomain, port)) {
 | 
						|
    aRv.Throw(NS_ERROR_FAILURE);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  aBaseDomain = pkBaseDomain;
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::GetPartitionKeyFromURL(dom::GlobalObject& aGlobal,
 | 
						|
                                         const nsAString& aURL,
 | 
						|
                                         nsAString& aPartitionKey,
 | 
						|
                                         ErrorResult& aRv) {
 | 
						|
  nsCOMPtr<nsIURI> uri;
 | 
						|
  nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL);
 | 
						|
  if (NS_SUCCEEDED(rv) && uri->SchemeIs("chrome")) {
 | 
						|
    rv = NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
    aPartitionKey.Truncate();
 | 
						|
    aRv.Throw(rv);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  mozilla::OriginAttributes attrs;
 | 
						|
  attrs.SetPartitionKey(uri);
 | 
						|
 | 
						|
  aPartitionKey = attrs.mPartitionKey;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef NIGHTLY_BUILD
 | 
						|
/* static */
 | 
						|
void ChromeUtils::GetRecentJSDevError(GlobalObject& aGlobal,
 | 
						|
                                      JS::MutableHandle<JS::Value> aRetval,
 | 
						|
                                      ErrorResult& aRv) {
 | 
						|
  aRetval.setUndefined();
 | 
						|
  auto runtime = CycleCollectedJSRuntime::Get();
 | 
						|
  MOZ_ASSERT(runtime);
 | 
						|
 | 
						|
  auto cx = aGlobal.Context();
 | 
						|
  if (!runtime->GetRecentDevError(cx, aRetval)) {
 | 
						|
    aRv.NoteJSContextException(cx);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::ClearRecentJSDevError(GlobalObject&) {
 | 
						|
  auto runtime = CycleCollectedJSRuntime::Get();
 | 
						|
  MOZ_ASSERT(runtime);
 | 
						|
 | 
						|
  runtime->ClearRecentDevError();
 | 
						|
}
 | 
						|
#endif  // NIGHTLY_BUILD
 | 
						|
 | 
						|
void ChromeUtils::ClearStyleSheetCacheByPrincipal(GlobalObject&,
 | 
						|
                                                  nsIPrincipal* aForPrincipal) {
 | 
						|
  SharedStyleSheetCache::Clear(aForPrincipal);
 | 
						|
}
 | 
						|
 | 
						|
void ChromeUtils::ClearStyleSheetCacheByBaseDomain(
 | 
						|
    GlobalObject&, const nsACString& aBaseDomain) {
 | 
						|
  SharedStyleSheetCache::Clear(nullptr, &aBaseDomain);
 | 
						|
}
 | 
						|
 | 
						|
void ChromeUtils::ClearStyleSheetCache(GlobalObject&) {
 | 
						|
  SharedStyleSheetCache::Clear();
 | 
						|
}
 | 
						|
 | 
						|
#define PROCTYPE_TO_WEBIDL_CASE(_procType, _webidl) \
 | 
						|
  case mozilla::ProcType::_procType:                \
 | 
						|
    return WebIDLProcType::_webidl
 | 
						|
 | 
						|
static WebIDLProcType ProcTypeToWebIDL(mozilla::ProcType aType) {
 | 
						|
  // Max is the value of the last enum, not the length, so add one.
 | 
						|
  static_assert(
 | 
						|
      static_cast<size_t>(MaxContiguousEnumValue<WebIDLProcType>::value) ==
 | 
						|
          static_cast<size_t>(ProcType::Max),
 | 
						|
      "In order for this static cast to be okay, "
 | 
						|
      "WebIDLProcType must match ProcType exactly");
 | 
						|
 | 
						|
  // These must match the similar ones in E10SUtils.sys.mjs, RemoteTypes.h,
 | 
						|
  // ProcInfo.h and ChromeUtils.webidl
 | 
						|
  switch (aType) {
 | 
						|
    PROCTYPE_TO_WEBIDL_CASE(Web, Web);
 | 
						|
    PROCTYPE_TO_WEBIDL_CASE(WebIsolated, WebIsolated);
 | 
						|
    PROCTYPE_TO_WEBIDL_CASE(File, File);
 | 
						|
    PROCTYPE_TO_WEBIDL_CASE(Extension, Extension);
 | 
						|
    PROCTYPE_TO_WEBIDL_CASE(PrivilegedAbout, Privilegedabout);
 | 
						|
    PROCTYPE_TO_WEBIDL_CASE(PrivilegedMozilla, Privilegedmozilla);
 | 
						|
    PROCTYPE_TO_WEBIDL_CASE(WebCOOPCOEP, WithCoopCoep);
 | 
						|
    PROCTYPE_TO_WEBIDL_CASE(WebServiceWorker, WebServiceWorker);
 | 
						|
 | 
						|
#define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
 | 
						|
                           process_bin_type, procinfo_typename,               \
 | 
						|
                           webidl_typename, allcaps_name)                     \
 | 
						|
  PROCTYPE_TO_WEBIDL_CASE(procinfo_typename, webidl_typename);
 | 
						|
#define SKIP_PROCESS_TYPE_CONTENT
 | 
						|
#ifndef MOZ_ENABLE_FORKSERVER
 | 
						|
#  define SKIP_PROCESS_TYPE_FORKSERVER
 | 
						|
#endif  // MOZ_ENABLE_FORKSERVER
 | 
						|
#include "mozilla/GeckoProcessTypes.h"
 | 
						|
#undef SKIP_PROCESS_TYPE_CONTENT
 | 
						|
#ifndef MOZ_ENABLE_FORKSERVER
 | 
						|
#  undef SKIP_PROCESS_TYPE_FORKSERVER
 | 
						|
#endif  // MOZ_ENABLE_FORKSERVER
 | 
						|
#undef GECKO_PROCESS_TYPE
 | 
						|
 | 
						|
    PROCTYPE_TO_WEBIDL_CASE(Preallocated, Preallocated);
 | 
						|
    PROCTYPE_TO_WEBIDL_CASE(Unknown, Unknown);
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(false, "Unhandled case in ProcTypeToWebIDL");
 | 
						|
  return WebIDLProcType::Unknown;
 | 
						|
}
 | 
						|
 | 
						|
#undef PROCTYPE_TO_WEBIDL_CASE
 | 
						|
 | 
						|
/* static */
 | 
						|
already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
 | 
						|
                                                       ErrorResult& aRv) {
 | 
						|
  // This function will use IPDL to enable threads info on macOS
 | 
						|
  // see https://bugzilla.mozilla.org/show_bug.cgi?id=1529023
 | 
						|
  if (!XRE_IsParentProcess()) {
 | 
						|
    aRv.Throw(NS_ERROR_FAILURE);
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  // Prepare the JS promise that will hold our response.
 | 
						|
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 | 
						|
  MOZ_ASSERT(global);
 | 
						|
  RefPtr<Promise> domPromise = Promise::Create(global, aRv);
 | 
						|
  if (NS_WARN_IF(aRv.Failed())) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  MOZ_ASSERT(domPromise);
 | 
						|
 | 
						|
  // Get a list of processes to examine and pre-fill them with available info.
 | 
						|
  // Note that this is subject to race conditions: just because we have a
 | 
						|
  // process in the list doesn't mean that the process will still be alive when
 | 
						|
  // we attempt to get its information. Followup code MUST be able to fail
 | 
						|
  // gracefully on some processes and still return whichever information is
 | 
						|
  // available.
 | 
						|
 | 
						|
  // Get all the content parents.
 | 
						|
  // Note that this array includes even the long dead content parents, so we
 | 
						|
  // might have some garbage, especially with Fission.
 | 
						|
  // SAFETY NOTE: `contentParents` is only valid if used synchronously.
 | 
						|
  // Anything else and you may end up dealing with dangling pointers.
 | 
						|
  nsTArray<ContentParent*> contentParents;
 | 
						|
  ContentParent::GetAll(contentParents);
 | 
						|
 | 
						|
  // Prepare our background request.
 | 
						|
  // We reserve one more slot for the browser process itself.
 | 
						|
  nsTArray<ProcInfoRequest> requests(contentParents.Length() + 1);
 | 
						|
  // Requesting process info for the browser process itself.
 | 
						|
  requests.EmplaceBack(
 | 
						|
      /* aPid = */ base::GetCurrentProcId(),
 | 
						|
      /* aProcessType = */ ProcType::Browser,
 | 
						|
      /* aOrigin = */ ""_ns,
 | 
						|
      /* aWindowInfo = */ nsTArray<WindowInfo>(),
 | 
						|
      /* aUtilityInfo = */ nsTArray<UtilityInfo>());
 | 
						|
 | 
						|
  // First handle non-ContentParent processes.
 | 
						|
  mozilla::ipc::GeckoChildProcessHost::GetAll(
 | 
						|
      [&requests](mozilla::ipc::GeckoChildProcessHost* aGeckoProcess) {
 | 
						|
        base::ProcessId childPid = aGeckoProcess->GetChildProcessId();
 | 
						|
        if (childPid == 0) {
 | 
						|
          // Something went wrong with this process, it may be dead already,
 | 
						|
          // fail gracefully.
 | 
						|
          return;
 | 
						|
        }
 | 
						|
        mozilla::ProcType type = mozilla::ProcType::Unknown;
 | 
						|
 | 
						|
        switch (aGeckoProcess->GetProcessType()) {
 | 
						|
          case GeckoProcessType::GeckoProcessType_Content: {
 | 
						|
            // These processes are handled separately.
 | 
						|
            return;
 | 
						|
          }
 | 
						|
 | 
						|
#define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
 | 
						|
                           process_bin_type, procinfo_typename,               \
 | 
						|
                           webidl_typename, allcaps_name)                     \
 | 
						|
  case GeckoProcessType::GeckoProcessType_##enum_name: {                      \
 | 
						|
    type = mozilla::ProcType::procinfo_typename;                              \
 | 
						|
    break;                                                                    \
 | 
						|
  }
 | 
						|
#define SKIP_PROCESS_TYPE_CONTENT
 | 
						|
#ifndef MOZ_ENABLE_FORKSERVER
 | 
						|
#  define SKIP_PROCESS_TYPE_FORKSERVER
 | 
						|
#endif  // MOZ_ENABLE_FORKSERVER
 | 
						|
#include "mozilla/GeckoProcessTypes.h"
 | 
						|
#ifndef MOZ_ENABLE_FORKSERVER
 | 
						|
#  undef SKIP_PROCESS_TYPE_FORKSERVER
 | 
						|
#endif  // MOZ_ENABLE_FORKSERVER
 | 
						|
#undef SKIP_PROCESS_TYPE_CONTENT
 | 
						|
#undef GECKO_PROCESS_TYPE
 | 
						|
          default:
 | 
						|
            // Leave the default Unknown value in |type|.
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        // Attach utility actor information to the process.
 | 
						|
        nsTArray<UtilityInfo> utilityActors;
 | 
						|
        if (aGeckoProcess->GetProcessType() ==
 | 
						|
            GeckoProcessType::GeckoProcessType_Utility) {
 | 
						|
          RefPtr<mozilla::ipc::UtilityProcessManager> upm =
 | 
						|
              mozilla::ipc::UtilityProcessManager::GetSingleton();
 | 
						|
          if (!utilityActors.AppendElements(upm->GetActors(aGeckoProcess),
 | 
						|
                                            fallible)) {
 | 
						|
            NS_WARNING("Error adding actors");
 | 
						|
            return;
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        requests.EmplaceBack(
 | 
						|
            /* aPid = */ childPid,
 | 
						|
            /* aProcessType = */ type,
 | 
						|
            /* aOrigin = */ ""_ns,
 | 
						|
            /* aWindowInfo = */ nsTArray<WindowInfo>(),  // Without a
 | 
						|
                                                         // ContentProcess, no
 | 
						|
                                                         // DOM windows.
 | 
						|
            /* aUtilityInfo = */ std::move(utilityActors),
 | 
						|
            /* aChild = */ 0  // Without a ContentProcess, no ChildId.
 | 
						|
#ifdef XP_MACOSX
 | 
						|
            ,
 | 
						|
            /* aChildTask = */ aGeckoProcess->GetChildTask()
 | 
						|
#endif  // XP_MACOSX
 | 
						|
        );
 | 
						|
      });
 | 
						|
 | 
						|
  // Now handle ContentParents.
 | 
						|
  for (const auto* contentParent : contentParents) {
 | 
						|
    if (!contentParent || !contentParent->Process()) {
 | 
						|
      // Presumably, the process is dead or dying.
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    base::ProcessId pid = contentParent->Process()->GetChildProcessId();
 | 
						|
    if (pid == 0) {
 | 
						|
      // Presumably, the process is dead or dying.
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    if (contentParent->Process()->GetProcessType() !=
 | 
						|
        GeckoProcessType::GeckoProcessType_Content) {
 | 
						|
      // We're probably racing against a process changing type.
 | 
						|
      // We'll get it in the next call, skip it for the moment.
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    // Since this code is executed synchronously on the main thread,
 | 
						|
    // processes cannot die while we're in this loop.
 | 
						|
    mozilla::ProcType type = mozilla::ProcType::Unknown;
 | 
						|
 | 
						|
    // Convert the remoteType into a ProcType.
 | 
						|
    // Ideally, the remoteType should be strongly typed
 | 
						|
    // upstream, this would make the conversion less brittle.
 | 
						|
    const nsAutoCString remoteType(contentParent->GetRemoteType());
 | 
						|
    if (StringBeginsWith(remoteType, FISSION_WEB_REMOTE_TYPE)) {
 | 
						|
      // WARNING: Do not change the order, as
 | 
						|
      // `DEFAULT_REMOTE_TYPE` is a prefix of
 | 
						|
      // `FISSION_WEB_REMOTE_TYPE`.
 | 
						|
      type = mozilla::ProcType::WebIsolated;
 | 
						|
    } else if (StringBeginsWith(remoteType, SERVICEWORKER_REMOTE_TYPE)) {
 | 
						|
      type = mozilla::ProcType::WebServiceWorker;
 | 
						|
    } else if (StringBeginsWith(remoteType,
 | 
						|
                                WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
 | 
						|
      type = mozilla::ProcType::WebCOOPCOEP;
 | 
						|
    } else if (remoteType == FILE_REMOTE_TYPE) {
 | 
						|
      type = mozilla::ProcType::File;
 | 
						|
    } else if (remoteType == EXTENSION_REMOTE_TYPE) {
 | 
						|
      type = mozilla::ProcType::Extension;
 | 
						|
    } else if (remoteType == PRIVILEGEDABOUT_REMOTE_TYPE) {
 | 
						|
      type = mozilla::ProcType::PrivilegedAbout;
 | 
						|
    } else if (remoteType == PRIVILEGEDMOZILLA_REMOTE_TYPE) {
 | 
						|
      type = mozilla::ProcType::PrivilegedMozilla;
 | 
						|
    } else if (remoteType == PREALLOC_REMOTE_TYPE) {
 | 
						|
      type = mozilla::ProcType::Preallocated;
 | 
						|
    } else if (StringBeginsWith(remoteType, DEFAULT_REMOTE_TYPE)) {
 | 
						|
      type = mozilla::ProcType::Web;
 | 
						|
    } else {
 | 
						|
      MOZ_CRASH_UNSAFE_PRINTF("Unknown remoteType '%s'", remoteType.get());
 | 
						|
    }
 | 
						|
 | 
						|
    // By convention, everything after '=' is the origin.
 | 
						|
    nsAutoCString origin;
 | 
						|
    nsACString::const_iterator cursor;
 | 
						|
    nsACString::const_iterator end;
 | 
						|
    remoteType.BeginReading(cursor);
 | 
						|
    remoteType.EndReading(end);
 | 
						|
    if (FindCharInReadable('=', cursor, end)) {
 | 
						|
      origin = Substring(++cursor, end);
 | 
						|
    }
 | 
						|
 | 
						|
    // Attach DOM window information to the process.
 | 
						|
    nsTArray<WindowInfo> windows;
 | 
						|
    for (const auto& browserParentWrapperKey :
 | 
						|
         contentParent->ManagedPBrowserParent()) {
 | 
						|
      for (const auto& windowGlobalParentWrapperKey :
 | 
						|
           browserParentWrapperKey->ManagedPWindowGlobalParent()) {
 | 
						|
        // WindowGlobalParent is the only immediate subclass of
 | 
						|
        // PWindowGlobalParent.
 | 
						|
        auto* windowGlobalParent =
 | 
						|
            static_cast<WindowGlobalParent*>(windowGlobalParentWrapperKey);
 | 
						|
 | 
						|
        nsString documentTitle;
 | 
						|
        windowGlobalParent->GetDocumentTitle(documentTitle);
 | 
						|
        WindowInfo* window = windows.EmplaceBack(
 | 
						|
            fallible,
 | 
						|
            /* aOuterWindowId = */ windowGlobalParent->OuterWindowId(),
 | 
						|
            /* aDocumentURI = */ windowGlobalParent->GetDocumentURI(),
 | 
						|
            /* aDocumentTitle = */ std::move(documentTitle),
 | 
						|
            /* aIsProcessRoot = */ windowGlobalParent->IsProcessRoot(),
 | 
						|
            /* aIsInProcess = */ windowGlobalParent->IsInProcess());
 | 
						|
        if (!window) {
 | 
						|
          aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
          return nullptr;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    requests.EmplaceBack(
 | 
						|
        /* aPid = */ pid,
 | 
						|
        /* aProcessType = */ type,
 | 
						|
        /* aOrigin = */ origin,
 | 
						|
        /* aWindowInfo = */ std::move(windows),
 | 
						|
        /* aUtilityInfo = */ nsTArray<UtilityInfo>(),
 | 
						|
        /* aChild = */ contentParent->ChildID()
 | 
						|
#ifdef XP_MACOSX
 | 
						|
            ,
 | 
						|
        /* aChildTask = */ contentParent->Process()->GetChildTask()
 | 
						|
#endif  // XP_MACOSX
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  // Now place background request.
 | 
						|
  RefPtr<nsISerialEventTarget> target = global->SerialEventTarget();
 | 
						|
  mozilla::GetProcInfo(std::move(requests))
 | 
						|
      ->Then(
 | 
						|
          target, __func__,
 | 
						|
          [target,
 | 
						|
           domPromise](const HashMap<base::ProcessId, ProcInfo>& aSysProcInfo) {
 | 
						|
            ParentProcInfoDictionary parentInfo;
 | 
						|
            if (aSysProcInfo.count() == 0) {
 | 
						|
              // For some reason, we couldn't get *any* info.
 | 
						|
              // Maybe a sandboxing issue?
 | 
						|
              domPromise->MaybeReject(NS_ERROR_UNEXPECTED);
 | 
						|
              return;
 | 
						|
            }
 | 
						|
            nsTArray<ChildProcInfoDictionary> childrenInfo(
 | 
						|
                aSysProcInfo.count() - 1);
 | 
						|
            for (auto iter = aSysProcInfo.iter(); !iter.done(); iter.next()) {
 | 
						|
              const auto& sysProcInfo = iter.get().value();
 | 
						|
              nsresult rv;
 | 
						|
              if (sysProcInfo.type == ProcType::Browser) {
 | 
						|
                rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, &parentInfo);
 | 
						|
                if (NS_FAILED(rv)) {
 | 
						|
                  // Failing to copy? That's probably not something from we can
 | 
						|
                  // (or should) try to recover gracefully.
 | 
						|
                  domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
                  return;
 | 
						|
                }
 | 
						|
                MOZ_ASSERT(sysProcInfo.childId == 0);
 | 
						|
                MOZ_ASSERT(sysProcInfo.origin.IsEmpty());
 | 
						|
              } else {
 | 
						|
                mozilla::dom::ChildProcInfoDictionary* childInfo =
 | 
						|
                    childrenInfo.AppendElement(fallible);
 | 
						|
                if (!childInfo) {
 | 
						|
                  domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
                  return;
 | 
						|
                }
 | 
						|
                rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, childInfo);
 | 
						|
                if (NS_FAILED(rv)) {
 | 
						|
                  domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
                  return;
 | 
						|
                }
 | 
						|
                // Copy Firefox info.
 | 
						|
                childInfo->mChildID = sysProcInfo.childId;
 | 
						|
                childInfo->mOrigin = sysProcInfo.origin;
 | 
						|
                childInfo->mType = ProcTypeToWebIDL(sysProcInfo.type);
 | 
						|
 | 
						|
                for (const auto& source : sysProcInfo.windows) {
 | 
						|
                  auto* dest = childInfo->mWindows.AppendElement(fallible);
 | 
						|
                  if (!dest) {
 | 
						|
                    domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
                    return;
 | 
						|
                  }
 | 
						|
                  dest->mOuterWindowId = source.outerWindowId;
 | 
						|
                  dest->mDocumentURI = source.documentURI;
 | 
						|
                  dest->mDocumentTitle = source.documentTitle;
 | 
						|
                  dest->mIsProcessRoot = source.isProcessRoot;
 | 
						|
                  dest->mIsInProcess = source.isInProcess;
 | 
						|
                }
 | 
						|
 | 
						|
                if (sysProcInfo.type == ProcType::Utility) {
 | 
						|
                  for (const auto& source : sysProcInfo.utilityActors) {
 | 
						|
                    auto* dest =
 | 
						|
                        childInfo->mUtilityActors.AppendElement(fallible);
 | 
						|
                    if (!dest) {
 | 
						|
                      domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
 | 
						|
                      return;
 | 
						|
                    }
 | 
						|
 | 
						|
                    dest->mActorName = source.actorName;
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
            }
 | 
						|
 | 
						|
            // Attach the children to the parent.
 | 
						|
            mozilla::dom::Sequence<mozilla::dom::ChildProcInfoDictionary>
 | 
						|
                children(std::move(childrenInfo));
 | 
						|
            parentInfo.mChildren = std::move(children);
 | 
						|
            domPromise->MaybeResolve(parentInfo);
 | 
						|
          },
 | 
						|
          [domPromise](nsresult aRv) { domPromise->MaybeReject(aRv); });
 | 
						|
  MOZ_ASSERT(domPromise);
 | 
						|
 | 
						|
  // sending back the promise instance
 | 
						|
  return domPromise.forget();
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
bool ChromeUtils::VsyncEnabled(GlobalObject& aGlobal) {
 | 
						|
  return mozilla::gfx::VsyncSource::GetFastestVsyncRate().isSome();
 | 
						|
}
 | 
						|
 | 
						|
void ChromeUtils::SetPerfStatsCollectionMask(GlobalObject& aGlobal,
 | 
						|
                                             uint64_t aMask) {
 | 
						|
  PerfStats::SetCollectionMask(static_cast<PerfStats::MetricMask>(aMask));
 | 
						|
}
 | 
						|
 | 
						|
already_AddRefed<Promise> ChromeUtils::CollectPerfStats(GlobalObject& aGlobal,
 | 
						|
                                                        ErrorResult& aRv) {
 | 
						|
  // Creating a JS promise
 | 
						|
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 | 
						|
  MOZ_ASSERT(global);
 | 
						|
 | 
						|
  RefPtr<Promise> promise = Promise::Create(global, aRv);
 | 
						|
  if (aRv.Failed()) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<PerfStats::PerfStatsPromise> extPromise =
 | 
						|
      PerfStats::CollectPerfStatsJSON();
 | 
						|
 | 
						|
  extPromise->Then(
 | 
						|
      GetCurrentSerialEventTarget(), __func__,
 | 
						|
      [promise](const nsCString& aResult) {
 | 
						|
        promise->MaybeResolve(NS_ConvertUTF8toUTF16(aResult));
 | 
						|
      },
 | 
						|
      [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
 | 
						|
 | 
						|
  return promise.forget();
 | 
						|
}
 | 
						|
 | 
						|
constexpr auto kSkipSelfHosted = JS::SavedFrameSelfHosted::Exclude;
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::GetCallerLocation(const GlobalObject& aGlobal,
 | 
						|
                                    nsIPrincipal* aPrincipal,
 | 
						|
                                    JS::MutableHandle<JSObject*> aRetval) {
 | 
						|
  JSContext* cx = aGlobal.Context();
 | 
						|
 | 
						|
  auto* principals = nsJSPrincipals::get(aPrincipal);
 | 
						|
 | 
						|
  JS::StackCapture captureMode(JS::FirstSubsumedFrame(cx, principals));
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> frame(cx);
 | 
						|
  if (!JS::CaptureCurrentStack(cx, &frame, std::move(captureMode))) {
 | 
						|
    JS_ClearPendingException(cx);
 | 
						|
    aRetval.set(nullptr);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // FirstSubsumedFrame gets us a stack which stops at the first principal which
 | 
						|
  // is subsumed by the given principal. That means that we may have a lot of
 | 
						|
  // privileged frames that we don't care about at the top of the stack, though.
 | 
						|
  // We need to filter those out to get the frame we actually want.
 | 
						|
  aRetval.set(
 | 
						|
      js::GetFirstSubsumedSavedFrame(cx, principals, frame, kSkipSelfHosted));
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::CreateError(const GlobalObject& aGlobal,
 | 
						|
                              const nsAString& aMessage,
 | 
						|
                              JS::Handle<JSObject*> aStack,
 | 
						|
                              JS::MutableHandle<JSObject*> aRetVal,
 | 
						|
                              ErrorResult& aRv) {
 | 
						|
  if (aStack && !JS::IsMaybeWrappedSavedFrame(aStack)) {
 | 
						|
    aRv.Throw(NS_ERROR_INVALID_ARG);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  JSContext* cx = aGlobal.Context();
 | 
						|
 | 
						|
  auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
 | 
						|
 | 
						|
  JS::Rooted<JSObject*> retVal(cx);
 | 
						|
  {
 | 
						|
    JS::Rooted<JSString*> fileName(cx, JS_GetEmptyString(cx));
 | 
						|
    uint32_t line = 0;
 | 
						|
    JS::TaggedColumnNumberOneOrigin column;
 | 
						|
 | 
						|
    Maybe<JSAutoRealm> ar;
 | 
						|
    JS::Rooted<JSObject*> stack(cx);
 | 
						|
    if (aStack) {
 | 
						|
      stack = UncheckedUnwrap(aStack);
 | 
						|
      ar.emplace(cx, stack);
 | 
						|
 | 
						|
      JSPrincipals* principals =
 | 
						|
          JS::GetRealmPrincipals(js::GetContextRealm(cx));
 | 
						|
      if (JS::GetSavedFrameLine(cx, principals, stack, &line) !=
 | 
						|
              JS::SavedFrameResult::Ok ||
 | 
						|
          JS::GetSavedFrameColumn(cx, principals, stack, &column) !=
 | 
						|
              JS::SavedFrameResult::Ok ||
 | 
						|
          JS::GetSavedFrameSource(cx, principals, stack, &fileName) !=
 | 
						|
              JS::SavedFrameResult::Ok) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    JS::Rooted<JSString*> message(cx);
 | 
						|
    {
 | 
						|
      JS::Rooted<JS::Value> msgVal(cx);
 | 
						|
      if (!xpc::NonVoidStringToJsval(cx, aMessage, &msgVal)) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      message = msgVal.toString();
 | 
						|
    }
 | 
						|
 | 
						|
    JS::Rooted<JS::Value> err(cx);
 | 
						|
    if (!JS::CreateError(cx, JSEXN_ERR, stack, fileName, line,
 | 
						|
                         JS::ColumnNumberOneOrigin(column.oneOriginValue()),
 | 
						|
                         nullptr, message, JS::NothingHandleValue, &err)) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    MOZ_ASSERT(err.isObject());
 | 
						|
    retVal = &err.toObject();
 | 
						|
  }
 | 
						|
 | 
						|
  if (aStack && !JS_WrapObject(cx, &retVal)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  cleanup.release();
 | 
						|
  aRetVal.set(retVal);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
already_AddRefed<Promise> ChromeUtils::RequestIOActivity(GlobalObject& aGlobal,
 | 
						|
                                                         ErrorResult& aRv) {
 | 
						|
  MOZ_ASSERT(XRE_IsParentProcess());
 | 
						|
  MOZ_ASSERT(Preferences::GetBool(IO_ACTIVITY_ENABLED_PREF, false));
 | 
						|
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 | 
						|
  MOZ_ASSERT(global);
 | 
						|
  RefPtr<Promise> domPromise = Promise::Create(global, aRv);
 | 
						|
  if (NS_WARN_IF(aRv.Failed())) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  MOZ_ASSERT(domPromise);
 | 
						|
  mozilla::net::IOActivityMonitor::RequestActivities(domPromise);
 | 
						|
  return domPromise.forget();
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
bool ChromeUtils::HasReportingHeaderForOrigin(GlobalObject& global,
 | 
						|
                                              const nsAString& aOrigin,
 | 
						|
                                              ErrorResult& aRv) {
 | 
						|
  if (!XRE_IsParentProcess()) {
 | 
						|
    aRv.Throw(NS_ERROR_FAILURE);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  return ReportingHeader::HasReportingHeaderForOrigin(
 | 
						|
      NS_ConvertUTF16toUTF8(aOrigin));
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
PopupBlockerState ChromeUtils::GetPopupControlState(GlobalObject& aGlobal) {
 | 
						|
  switch (PopupBlocker::GetPopupControlState()) {
 | 
						|
    case PopupBlocker::PopupControlState::openAllowed:
 | 
						|
      return PopupBlockerState::OpenAllowed;
 | 
						|
 | 
						|
    case PopupBlocker::PopupControlState::openControlled:
 | 
						|
      return PopupBlockerState::OpenControlled;
 | 
						|
 | 
						|
    case PopupBlocker::PopupControlState::openBlocked:
 | 
						|
      return PopupBlockerState::OpenBlocked;
 | 
						|
 | 
						|
    case PopupBlocker::PopupControlState::openAbused:
 | 
						|
      return PopupBlockerState::OpenAbused;
 | 
						|
 | 
						|
    case PopupBlocker::PopupControlState::openOverridden:
 | 
						|
      return PopupBlockerState::OpenOverridden;
 | 
						|
 | 
						|
    default:
 | 
						|
      MOZ_CRASH(
 | 
						|
          "PopupBlocker::PopupControlState and PopupBlockerState are out of "
 | 
						|
          "sync");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
double ChromeUtils::LastExternalProtocolIframeAllowed(GlobalObject& aGlobal) {
 | 
						|
  TimeStamp when = PopupBlocker::WhenLastExternalProtocolIframeAllowed();
 | 
						|
  if (when.IsNull()) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  TimeDuration duration = TimeStamp::Now() - when;
 | 
						|
  return duration.ToMilliseconds();
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::ResetLastExternalProtocolIframeAllowed(
 | 
						|
    GlobalObject& aGlobal) {
 | 
						|
  PopupBlocker::ResetLastExternalProtocolIframeAllowed();
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::EndWheelTransaction(GlobalObject& aGlobal) {
 | 
						|
  // This allows us to end the current wheel transaction from the browser
 | 
						|
  // chrome. We do not need to perform any checks before calling
 | 
						|
  // EndTransaction(), as it should do nothing in the case that there is
 | 
						|
  // no current wheel transaction.
 | 
						|
  WheelTransaction::EndTransaction();
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::RegisterWindowActor(const GlobalObject& aGlobal,
 | 
						|
                                      const nsACString& aName,
 | 
						|
                                      const WindowActorOptions& aOptions,
 | 
						|
                                      ErrorResult& aRv) {
 | 
						|
  MOZ_ASSERT(XRE_IsParentProcess());
 | 
						|
 | 
						|
  RefPtr<JSActorService> service = JSActorService::GetSingleton();
 | 
						|
  service->RegisterWindowActor(aName, aOptions, aRv);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::UnregisterWindowActor(const GlobalObject& aGlobal,
 | 
						|
                                        const nsACString& aName) {
 | 
						|
  MOZ_ASSERT(XRE_IsParentProcess());
 | 
						|
 | 
						|
  RefPtr<JSActorService> service = JSActorService::GetSingleton();
 | 
						|
  service->UnregisterWindowActor(aName);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::RegisterProcessActor(const GlobalObject& aGlobal,
 | 
						|
                                       const nsACString& aName,
 | 
						|
                                       const ProcessActorOptions& aOptions,
 | 
						|
                                       ErrorResult& aRv) {
 | 
						|
  MOZ_ASSERT(XRE_IsParentProcess());
 | 
						|
 | 
						|
  RefPtr<JSActorService> service = JSActorService::GetSingleton();
 | 
						|
  service->RegisterProcessActor(aName, aOptions, aRv);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::UnregisterProcessActor(const GlobalObject& aGlobal,
 | 
						|
                                         const nsACString& aName) {
 | 
						|
  MOZ_ASSERT(XRE_IsParentProcess());
 | 
						|
 | 
						|
  RefPtr<JSActorService> service = JSActorService::GetSingleton();
 | 
						|
  service->UnregisterProcessActor(aName);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
bool ChromeUtils::IsClassifierBlockingErrorCode(GlobalObject& aGlobal,
 | 
						|
                                                uint32_t aError) {
 | 
						|
  return net::UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(
 | 
						|
      static_cast<nsresult>(aError));
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::PrivateNoteIntentionalCrash(const GlobalObject& aGlobal,
 | 
						|
                                              ErrorResult& aError) {
 | 
						|
  if (XRE_IsContentProcess()) {
 | 
						|
    NoteIntentionalCrash("tab");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
nsIDOMProcessChild* ChromeUtils::GetDomProcessChild(const GlobalObject&) {
 | 
						|
  return nsIDOMProcessChild::GetSingleton();
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::GetAllDOMProcesses(
 | 
						|
    GlobalObject& aGlobal, nsTArray<RefPtr<nsIDOMProcessParent>>& aParents,
 | 
						|
    ErrorResult& aRv) {
 | 
						|
  if (!XRE_IsParentProcess()) {
 | 
						|
    aRv.ThrowNotAllowedError(
 | 
						|
        "getAllDOMProcesses() may only be called in the parent process");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  aParents.Clear();
 | 
						|
  // Always add the parent process nsIDOMProcessParent first
 | 
						|
  aParents.AppendElement(InProcessParent::Singleton());
 | 
						|
 | 
						|
  // Before adding nsIDOMProcessParent for all the content processes
 | 
						|
  for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
 | 
						|
    aParents.AppendElement(cp);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::ConsumeInteractionData(
 | 
						|
    GlobalObject& aGlobal, Record<nsString, InteractionData>& aInteractions,
 | 
						|
    ErrorResult& aRv) {
 | 
						|
  if (!XRE_IsParentProcess()) {
 | 
						|
    aRv.ThrowNotAllowedError(
 | 
						|
        "consumeInteractionData() may only be called in the parent "
 | 
						|
        "process");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  EventStateManager::ConsumeInteractionData(aInteractions);
 | 
						|
}
 | 
						|
 | 
						|
already_AddRefed<Promise> ChromeUtils::CollectScrollingData(
 | 
						|
    GlobalObject& aGlobal, ErrorResult& aRv) {
 | 
						|
  // Creating a JS promise
 | 
						|
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 | 
						|
  MOZ_ASSERT(global);
 | 
						|
 | 
						|
  RefPtr<Promise> promise = Promise::Create(global, aRv);
 | 
						|
  if (aRv.Failed()) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<ScrollingMetrics::ScrollingMetricsPromise> extPromise =
 | 
						|
      ScrollingMetrics::CollectScrollingMetrics();
 | 
						|
 | 
						|
  extPromise->Then(
 | 
						|
      GetCurrentSerialEventTarget(), __func__,
 | 
						|
      [promise](const std::tuple<uint32_t, uint32_t>& aResult) {
 | 
						|
        InteractionData out = {};
 | 
						|
        out.mInteractionTimeInMilliseconds = std::get<0>(aResult);
 | 
						|
        out.mScrollingDistanceInPixels = std::get<1>(aResult);
 | 
						|
        promise->MaybeResolve(out);
 | 
						|
      },
 | 
						|
      [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
 | 
						|
 | 
						|
  return promise.forget();
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::GetFormAutofillConfidences(
 | 
						|
    GlobalObject& aGlobal, const Sequence<OwningNonNull<Element>>& aElements,
 | 
						|
    nsTArray<FormAutofillConfidences>& aResults, ErrorResult& aRv) {
 | 
						|
  FormAutofillNative::GetFormAutofillConfidences(aGlobal, aElements, aResults,
 | 
						|
                                                 aRv);
 | 
						|
}
 | 
						|
 | 
						|
bool ChromeUtils::IsDarkBackground(GlobalObject&, Element& aElement) {
 | 
						|
  nsIFrame* f = aElement.GetPrimaryFrame(FlushType::Frames);
 | 
						|
  if (!f) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return nsNativeTheme::IsDarkBackground(f);
 | 
						|
}
 | 
						|
 | 
						|
double ChromeUtils::DateNow(GlobalObject&) { return JS_Now() / 1000.0; }
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::EnsureJSOracleStarted(GlobalObject&) {
 | 
						|
  if (StaticPrefs::browser_opaqueResponseBlocking_javascriptValidator()) {
 | 
						|
    JSOracleParent::WithJSOracle([](JSOracleParent* aParent) {});
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
unsigned ChromeUtils::AliveUtilityProcesses(const GlobalObject&) {
 | 
						|
  const auto& utilityProcessManager =
 | 
						|
      mozilla::ipc::UtilityProcessManager::GetIfExists();
 | 
						|
  return utilityProcessManager ? utilityProcessManager->AliveProcesses() : 0;
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::GetAllPossibleUtilityActorNames(GlobalObject& aGlobal,
 | 
						|
                                                  nsTArray<nsCString>& aNames) {
 | 
						|
  aNames.Clear();
 | 
						|
  for (UtilityActorName idlName :
 | 
						|
       MakeWebIDLEnumeratedRange<WebIDLUtilityActorName>()) {
 | 
						|
    aNames.AppendElement(GetEnumString(idlName));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
bool ChromeUtils::ShouldResistFingerprinting(
 | 
						|
    GlobalObject& aGlobal, JSRFPTarget aTarget,
 | 
						|
    const Nullable<uint64_t>& aOverriddenFingerprintingSettings) {
 | 
						|
  RFPTarget target;
 | 
						|
  switch (aTarget) {
 | 
						|
    case JSRFPTarget::RoundWindowSize:
 | 
						|
      target = RFPTarget::RoundWindowSize;
 | 
						|
      break;
 | 
						|
    case JSRFPTarget::SiteSpecificZoom:
 | 
						|
      target = RFPTarget::SiteSpecificZoom;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      MOZ_CRASH("Unhandled JSRFPTarget enum value");
 | 
						|
  }
 | 
						|
 | 
						|
  bool isPBM = false;
 | 
						|
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 | 
						|
  if (global) {
 | 
						|
    nsPIDOMWindowInner* win = global->GetAsInnerWindow();
 | 
						|
    if (win) {
 | 
						|
      nsIDocShell* docshell = win->GetDocShell();
 | 
						|
      if (docshell) {
 | 
						|
        nsDocShell::Cast(docshell)->GetUsePrivateBrowsing(&isPBM);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Maybe<RFPTarget> overriddenFingerprintingSettings;
 | 
						|
  if (!aOverriddenFingerprintingSettings.IsNull()) {
 | 
						|
    overriddenFingerprintingSettings.emplace(
 | 
						|
        RFPTarget(aOverriddenFingerprintingSettings.Value()));
 | 
						|
  }
 | 
						|
 | 
						|
  // This global object appears to be the global window, not for individual
 | 
						|
  // sites so to exempt individual sites (instead of just PBM/Not-PBM windows)
 | 
						|
  // more work would be needed to get the correct context.
 | 
						|
  return nsRFPService::IsRFPEnabledFor(isPBM, target,
 | 
						|
                                       overriddenFingerprintingSettings);
 | 
						|
}
 | 
						|
 | 
						|
std::atomic<uint32_t> ChromeUtils::sDevToolsOpenedCount = 0;
 | 
						|
 | 
						|
/* static */
 | 
						|
bool ChromeUtils::IsDevToolsOpened() {
 | 
						|
  return ChromeUtils::sDevToolsOpenedCount > 0;
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
bool ChromeUtils::IsDevToolsOpened(GlobalObject& aGlobal) {
 | 
						|
  return ChromeUtils::IsDevToolsOpened();
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::NotifyDevToolsOpened(GlobalObject& aGlobal) {
 | 
						|
  ChromeUtils::sDevToolsOpenedCount++;
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ChromeUtils::NotifyDevToolsClosed(GlobalObject& aGlobal) {
 | 
						|
  MOZ_ASSERT(ChromeUtils::sDevToolsOpenedCount >= 1);
 | 
						|
  ChromeUtils::sDevToolsOpenedCount--;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef MOZ_WMF_CDM
 | 
						|
/* static */
 | 
						|
already_AddRefed<Promise> ChromeUtils::GetWMFContentDecryptionModuleInformation(
 | 
						|
    GlobalObject& aGlobal, ErrorResult& aRv) {
 | 
						|
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 | 
						|
  MOZ_ASSERT(global);
 | 
						|
  RefPtr<Promise> domPromise = Promise::Create(global, aRv);
 | 
						|
  if (NS_WARN_IF(aRv.Failed())) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  MOZ_ASSERT(domPromise);
 | 
						|
  MFCDMService::GetAllKeySystemsCapabilities(domPromise);
 | 
						|
  return domPromise.forget();
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
already_AddRefed<Promise> ChromeUtils::GetGMPContentDecryptionModuleInformation(
 | 
						|
    GlobalObject& aGlobal, ErrorResult& aRv) {
 | 
						|
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 | 
						|
  MOZ_ASSERT(global);
 | 
						|
  RefPtr<Promise> domPromise = Promise::Create(global, aRv);
 | 
						|
  if (NS_WARN_IF(aRv.Failed())) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  MOZ_ASSERT(domPromise);
 | 
						|
  KeySystemConfig::GetGMPKeySystemConfigs(domPromise);
 | 
						|
  return domPromise.forget();
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace mozilla::dom
 |