Bug 1908539 restrict MacOS platform audio processing to Nightly r=webrtc-reviewers...
[gecko.git] / dom / base / ChromeUtils.cpp
blob3e4a1fe0120fdcbb502d2e82161919b36d5c82c2
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ChromeUtils.h"
9 #include "JSOracleParent.h"
10 #include "js/CallAndConstruct.h" // JS::Call
11 #include "js/ColumnNumber.h" // JS::TaggedColumnNumberOneOrigin, JS::ColumnNumberOneOrigin
12 #include "js/CharacterEncoding.h"
13 #include "js/Date.h" // JS::IsISOStyleDate
14 #include "js/Object.h" // JS::GetClass
15 #include "js/PropertyAndElement.h" // JS_DefineProperty, JS_DefinePropertyById, JS_Enumerate, JS_GetProperty, JS_GetPropertyById, JS_SetProperty, JS_SetPropertyById, JS::IdVector
16 #include "js/PropertyDescriptor.h" // JS::PropertyDescriptor, JS_GetOwnPropertyDescriptorById
17 #include "js/SavedFrameAPI.h"
18 #include "js/Value.h" // JS::Value, JS::StringValue
19 #include "jsfriendapi.h"
20 #include "WrapperFactory.h"
22 #include "mozilla/Base64.h"
23 #include "mozilla/CycleCollectedJSRuntime.h"
24 #include "mozilla/ErrorNames.h"
25 #include "mozilla/EventStateManager.h"
26 #include "mozilla/FormAutofillNative.h"
27 #include "mozilla/IntentionalCrash.h"
28 #include "mozilla/PerfStats.h"
29 #include "mozilla/Preferences.h"
30 #include "mozilla/ProcInfo.h"
31 #include "mozilla/ResultExtensions.h"
32 #include "mozilla/ScopeExit.h"
33 #include "mozilla/ScrollingMetrics.h"
34 #include "mozilla/SharedStyleSheetCache.h"
35 #include "mozilla/SpinEventLoopUntil.h"
36 #include "mozilla/TimeStamp.h"
37 #include "mozilla/dom/ContentParent.h"
38 #include "mozilla/dom/IdleDeadline.h"
39 #include "mozilla/dom/InProcessParent.h"
40 #include "mozilla/dom/JSActorService.h"
41 #include "mozilla/dom/MediaSessionBinding.h"
42 #include "mozilla/dom/PBrowserParent.h"
43 #include "mozilla/dom/Performance.h"
44 #include "mozilla/dom/PopupBlocker.h"
45 #include "mozilla/dom/Promise.h"
46 #include "mozilla/dom/Record.h"
47 #include "mozilla/dom/ReportingHeader.h"
48 #include "mozilla/dom/UnionTypes.h"
49 #include "mozilla/dom/WindowBinding.h" // For IdleRequestCallback/Options
50 #include "mozilla/dom/WindowGlobalParent.h"
51 #include "mozilla/dom/WorkerScope.h"
52 #include "mozilla/ipc/GeckoChildProcessHost.h"
53 #include "mozilla/ipc/UtilityProcessSandboxing.h"
54 #include "mozilla/ipc/UtilityProcessManager.h"
55 #include "mozilla/ipc/UtilityProcessHost.h"
56 #include "mozilla/net/UrlClassifierFeatureFactory.h"
57 #include "mozilla/RemoteDecoderManagerChild.h"
58 #include "mozilla/KeySystemConfig.h"
59 #include "mozilla/WheelHandlingHelper.h"
60 #include "nsNativeTheme.h"
61 #include "nsThreadUtils.h"
62 #include "mozJSModuleLoader.h"
63 #include "mozilla/ProfilerLabels.h"
64 #include "mozilla/ProfilerMarkers.h"
65 #include "nsDocShell.h"
66 #include "nsIException.h"
67 #include "VsyncSource.h"
69 #ifdef XP_UNIX
70 # include <errno.h>
71 # include <unistd.h>
72 # include <fcntl.h>
73 # include <poll.h>
74 # include <sys/wait.h>
76 # ifdef XP_LINUX
77 # include <sys/prctl.h>
78 # endif
79 #endif
81 #ifdef MOZ_WMF_CDM
82 # include "mozilla/MFCDMParent.h"
83 #endif
85 namespace mozilla::dom {
87 /* static */
88 void ChromeUtils::NondeterministicGetWeakMapKeys(
89 GlobalObject& aGlobal, JS::Handle<JS::Value> aMap,
90 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
91 if (!aMap.isObject()) {
92 aRetval.setUndefined();
93 } else {
94 JSContext* cx = aGlobal.Context();
95 JS::Rooted<JSObject*> objRet(cx);
96 JS::Rooted<JSObject*> mapObj(cx, &aMap.toObject());
97 if (!JS_NondeterministicGetWeakMapKeys(cx, mapObj, &objRet)) {
98 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
99 } else {
100 aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
105 /* static */
106 void ChromeUtils::NondeterministicGetWeakSetKeys(
107 GlobalObject& aGlobal, JS::Handle<JS::Value> aSet,
108 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
109 if (!aSet.isObject()) {
110 aRetval.setUndefined();
111 } else {
112 JSContext* cx = aGlobal.Context();
113 JS::Rooted<JSObject*> objRet(cx);
114 JS::Rooted<JSObject*> setObj(cx, &aSet.toObject());
115 if (!JS_NondeterministicGetWeakSetKeys(cx, setObj, &objRet)) {
116 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
117 } else {
118 aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
123 /* static */
124 void ChromeUtils::Base64URLEncode(GlobalObject& aGlobal,
125 const ArrayBufferViewOrArrayBuffer& aSource,
126 const Base64URLEncodeOptions& aOptions,
127 nsACString& aResult, ErrorResult& aRv) {
128 auto paddingPolicy = aOptions.mPad ? Base64URLEncodePaddingPolicy::Include
129 : Base64URLEncodePaddingPolicy::Omit;
130 ProcessTypedArrays(
131 aSource, [&](const Span<uint8_t>& aData, JS::AutoCheckCannotGC&&) {
132 nsresult rv = mozilla::Base64URLEncode(aData.Length(), aData.Elements(),
133 paddingPolicy, aResult);
134 if (NS_WARN_IF(NS_FAILED(rv))) {
135 aResult.Truncate();
136 aRv.Throw(rv);
141 /* static */
142 void ChromeUtils::Base64URLDecode(GlobalObject& aGlobal,
143 const nsACString& aString,
144 const Base64URLDecodeOptions& aOptions,
145 JS::MutableHandle<JSObject*> aRetval,
146 ErrorResult& aRv) {
147 Base64URLDecodePaddingPolicy paddingPolicy;
148 switch (aOptions.mPadding) {
149 case Base64URLDecodePadding::Require:
150 paddingPolicy = Base64URLDecodePaddingPolicy::Require;
151 break;
153 case Base64URLDecodePadding::Ignore:
154 paddingPolicy = Base64URLDecodePaddingPolicy::Ignore;
155 break;
157 case Base64URLDecodePadding::Reject:
158 paddingPolicy = Base64URLDecodePaddingPolicy::Reject;
159 break;
161 default:
162 aRv.Throw(NS_ERROR_INVALID_ARG);
163 return;
165 FallibleTArray<uint8_t> data;
166 nsresult rv = mozilla::Base64URLDecode(aString, paddingPolicy, data);
167 if (NS_WARN_IF(NS_FAILED(rv))) {
168 aRv.Throw(rv);
169 return;
172 JS::Rooted<JSObject*> buffer(
173 aGlobal.Context(), ArrayBuffer::Create(aGlobal.Context(), data, aRv));
174 if (aRv.Failed()) {
175 return;
177 aRetval.set(buffer);
180 /* static */
181 void ChromeUtils::ReleaseAssert(GlobalObject& aGlobal, bool aCondition,
182 const nsAString& aMessage) {
183 // If the condition didn't fail, which is the likely case, immediately return.
184 if (MOZ_LIKELY(aCondition)) {
185 return;
188 // Extract the current stack from the JS runtime to embed in the crash reason.
189 nsAutoString filename;
190 uint32_t lineNo = 0;
192 if (nsCOMPtr<nsIStackFrame> location = GetCurrentJSStack(1)) {
193 location->GetFilename(aGlobal.Context(), filename);
194 lineNo = location->GetLineNumber(aGlobal.Context());
195 } else {
196 filename.Assign(u"<unknown>"_ns);
199 // Convert to utf-8 for adding as the MozCrashReason.
200 NS_ConvertUTF16toUTF8 filenameUtf8(filename);
201 NS_ConvertUTF16toUTF8 messageUtf8(aMessage);
203 // Actually crash.
204 MOZ_CRASH_UNSAFE_PRINTF("Failed ChromeUtils.releaseAssert(\"%s\") @ %s:%u",
205 messageUtf8.get(), filenameUtf8.get(), lineNo);
208 /* static */
209 void ChromeUtils::AddProfilerMarker(
210 GlobalObject& aGlobal, const nsACString& aName,
211 const ProfilerMarkerOptionsOrDouble& aOptions,
212 const Optional<nsACString>& aText) {
213 if (!profiler_thread_is_being_profiled_for_markers()) {
214 return;
217 MarkerOptions options;
219 MarkerCategory category = ::geckoprofiler::category::JS;
221 DOMHighResTimeStamp startTime = 0;
222 uint64_t innerWindowId = 0;
223 if (aOptions.IsDouble()) {
224 startTime = aOptions.GetAsDouble();
225 } else {
226 const ProfilerMarkerOptions& opt = aOptions.GetAsProfilerMarkerOptions();
227 startTime = opt.mStartTime;
228 innerWindowId = opt.mInnerWindowId;
230 if (opt.mCaptureStack) {
231 // If we will be capturing a stack, change the category of the
232 // ChromeUtils.addProfilerMarker label automatically added by the webidl
233 // binding from DOM to PROFILER so that this function doesn't appear in
234 // the marker stack.
235 JSContext* cx = aGlobal.Context();
236 ProfilingStack* stack = js::GetContextProfilingStackIfEnabled(cx);
237 if (MOZ_LIKELY(stack)) {
238 uint32_t sp = stack->stackPointer;
239 if (MOZ_LIKELY(sp > 0)) {
240 js::ProfilingStackFrame& frame = stack->frames[sp - 1];
241 if (frame.isLabelFrame() && "ChromeUtils"_ns.Equals(frame.label()) &&
242 "addProfilerMarker"_ns.Equals(frame.dynamicString())) {
243 frame.setLabelCategory(JS::ProfilingCategoryPair::PROFILER);
248 options.Set(MarkerStack::Capture());
250 #define BEGIN_CATEGORY(name, labelAsString, color) \
251 if (opt.mCategory.Equals(labelAsString)) { \
252 category = ::geckoprofiler::category::name; \
253 } else
254 #define SUBCATEGORY(supercategory, name, labelAsString)
255 #define END_CATEGORY
256 MOZ_PROFILING_CATEGORY_LIST(BEGIN_CATEGORY, SUBCATEGORY, END_CATEGORY)
257 #undef BEGIN_CATEGORY
258 #undef SUBCATEGORY
259 #undef END_CATEGORY
261 category = ::geckoprofiler::category::OTHER;
264 if (startTime) {
265 RefPtr<Performance> performance;
267 if (NS_IsMainThread()) {
268 nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
269 do_QueryInterface(aGlobal.GetAsSupports());
270 if (ownerWindow) {
271 performance = ownerWindow->GetPerformance();
273 } else {
274 JSContext* cx = aGlobal.Context();
275 WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
276 if (workerPrivate) {
277 performance = workerPrivate->GlobalScope()->GetPerformance();
281 if (performance) {
282 options.Set(MarkerTiming::IntervalUntilNowFrom(
283 performance->CreationTimeStamp() +
284 TimeDuration::FromMilliseconds(startTime)));
285 } else {
286 options.Set(MarkerTiming::IntervalUntilNowFrom(
287 TimeStamp::ProcessCreation() +
288 TimeDuration::FromMilliseconds(startTime)));
292 if (innerWindowId) {
293 options.Set(MarkerInnerWindowId(innerWindowId));
294 } else {
295 options.Set(MarkerInnerWindowIdFromJSContext(aGlobal.Context()));
299 AUTO_PROFILER_STATS(ChromeUtils_AddProfilerMarker);
300 if (aText.WasPassed()) {
301 profiler_add_marker(aName, category, std::move(options),
302 ::geckoprofiler::markers::TextMarker{},
303 aText.Value());
304 } else {
305 profiler_add_marker(aName, category, std::move(options));
310 /* static */
311 void ChromeUtils::GetXPCOMErrorName(GlobalObject& aGlobal, uint32_t aErrorCode,
312 nsACString& aRetval) {
313 GetErrorName((nsresult)aErrorCode, aRetval);
316 /* static */
317 void ChromeUtils::WaiveXrays(GlobalObject& aGlobal, JS::Handle<JS::Value> aVal,
318 JS::MutableHandle<JS::Value> aRetval,
319 ErrorResult& aRv) {
320 JS::Rooted<JS::Value> value(aGlobal.Context(), aVal);
321 if (!xpc::WrapperFactory::WaiveXrayAndWrap(aGlobal.Context(), &value)) {
322 aRv.NoteJSContextException(aGlobal.Context());
323 } else {
324 aRetval.set(value);
328 /* static */
329 void ChromeUtils::UnwaiveXrays(GlobalObject& aGlobal,
330 JS::Handle<JS::Value> aVal,
331 JS::MutableHandle<JS::Value> aRetval,
332 ErrorResult& aRv) {
333 if (!aVal.isObject()) {
334 aRetval.set(aVal);
335 return;
338 JS::Rooted<JSObject*> obj(aGlobal.Context(),
339 js::UncheckedUnwrap(&aVal.toObject()));
340 if (!JS_WrapObject(aGlobal.Context(), &obj)) {
341 aRv.NoteJSContextException(aGlobal.Context());
342 } else {
343 aRetval.setObject(*obj);
347 /* static */
348 void ChromeUtils::GetClassName(GlobalObject& aGlobal,
349 JS::Handle<JSObject*> aObj, bool aUnwrap,
350 nsAString& aRetval) {
351 JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
352 if (aUnwrap) {
353 obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
356 aRetval = NS_ConvertUTF8toUTF16(nsDependentCString(JS::GetClass(obj)->name));
359 /* static */
360 bool ChromeUtils::IsDOMObject(GlobalObject& aGlobal, JS::Handle<JSObject*> aObj,
361 bool aUnwrap) {
362 JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
363 if (aUnwrap) {
364 obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
367 return mozilla::dom::IsDOMObject(obj);
370 /* static */
371 bool ChromeUtils::IsISOStyleDate(GlobalObject& aGlobal,
372 const nsACString& aStr) {
373 // aStr is a UTF-8 string, however we can cast to JS::Latin1Chars
374 // because JS::IsISOStyleDate handles ASCII only
375 return JS::IsISOStyleDate(aGlobal.Context(),
376 JS::Latin1Chars(aStr.Data(), aStr.Length()));
379 /* static */
380 void ChromeUtils::ShallowClone(GlobalObject& aGlobal,
381 JS::Handle<JSObject*> aObj,
382 JS::Handle<JSObject*> aTarget,
383 JS::MutableHandle<JSObject*> aRetval,
384 ErrorResult& aRv) {
385 JSContext* cx = aGlobal.Context();
387 auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
389 JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
390 JS::RootedVector<JS::Value> values(cx);
391 JS::RootedVector<jsid> valuesIds(cx);
394 // cx represents our current Realm, so it makes sense to use it for the
395 // CheckedUnwrapDynamic call. We do want CheckedUnwrapDynamic, in case
396 // someone is shallow-cloning a Window.
397 JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapDynamic(aObj, cx));
398 if (!obj) {
399 js::ReportAccessDenied(cx);
400 return;
403 if (js::IsScriptedProxy(obj)) {
404 JS_ReportErrorASCII(cx, "Shallow cloning a proxy object is not allowed");
405 return;
408 JSAutoRealm ar(cx, obj);
410 if (!JS_Enumerate(cx, obj, &ids) || !values.reserve(ids.length()) ||
411 !valuesIds.reserve(ids.length())) {
412 return;
415 JS::Rooted<Maybe<JS::PropertyDescriptor>> desc(cx);
416 JS::Rooted<JS::PropertyKey> id(cx);
417 for (jsid idVal : ids) {
418 id = idVal;
419 if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) {
420 continue;
422 if (desc.isNothing() || desc->isAccessorDescriptor()) {
423 continue;
425 valuesIds.infallibleAppend(id);
426 values.infallibleAppend(desc->value());
430 JS::Rooted<JSObject*> obj(cx);
432 Maybe<JSAutoRealm> ar;
433 if (aTarget) {
434 // Our target could be anything, so we want CheckedUnwrapDynamic here.
435 // "cx" represents the current Realm when we were called from bindings, so
436 // we can just use that.
437 JS::Rooted<JSObject*> target(cx, js::CheckedUnwrapDynamic(aTarget, cx));
438 if (!target) {
439 js::ReportAccessDenied(cx);
440 return;
442 ar.emplace(cx, target);
445 obj = JS_NewPlainObject(cx);
446 if (!obj) {
447 return;
450 JS::Rooted<JS::Value> value(cx);
451 JS::Rooted<JS::PropertyKey> id(cx);
452 for (uint32_t i = 0; i < valuesIds.length(); i++) {
453 id = valuesIds[i];
454 value = values[i];
456 JS_MarkCrossZoneId(cx, id);
457 if (!JS_WrapValue(cx, &value) ||
458 !JS_SetPropertyById(cx, obj, id, value)) {
459 return;
464 if (aTarget && !JS_WrapObject(cx, &obj)) {
465 return;
468 cleanup.release();
469 aRetval.set(obj);
472 namespace {
473 class IdleDispatchRunnable final : public IdleRunnable,
474 public nsITimerCallback {
475 public:
476 NS_DECL_ISUPPORTS_INHERITED
478 IdleDispatchRunnable(nsIGlobalObject* aParent, IdleRequestCallback& aCallback)
479 : IdleRunnable("ChromeUtils::IdleDispatch"),
480 mCallback(&aCallback),
481 mParent(aParent) {}
483 // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT.
484 // See bug 1535398.
485 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
486 if (mCallback) {
487 CancelTimer();
489 auto deadline = mDeadline - TimeStamp::ProcessCreation();
491 ErrorResult rv;
492 RefPtr<IdleDeadline> idleDeadline =
493 new IdleDeadline(mParent, mTimedOut, deadline.ToMilliseconds());
495 RefPtr<IdleRequestCallback> callback(std::move(mCallback));
496 MOZ_ASSERT(!mCallback);
497 callback->Call(*idleDeadline, "ChromeUtils::IdleDispatch handler");
498 mParent = nullptr;
500 return NS_OK;
503 void SetDeadline(TimeStamp aDeadline) override { mDeadline = aDeadline; }
505 NS_IMETHOD Notify(nsITimer* aTimer) override {
506 mTimedOut = true;
507 SetDeadline(TimeStamp::Now());
508 return Run();
511 void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override {
512 MOZ_ASSERT(aTarget);
513 MOZ_ASSERT(!mTimer);
514 NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, aDelay,
515 nsITimer::TYPE_ONE_SHOT, aTarget);
518 protected:
519 virtual ~IdleDispatchRunnable() { CancelTimer(); }
521 private:
522 void CancelTimer() {
523 if (mTimer) {
524 mTimer->Cancel();
525 mTimer = nullptr;
529 RefPtr<IdleRequestCallback> mCallback;
530 nsCOMPtr<nsIGlobalObject> mParent;
532 nsCOMPtr<nsITimer> mTimer;
534 TimeStamp mDeadline{};
535 bool mTimedOut = false;
538 NS_IMPL_ISUPPORTS_INHERITED(IdleDispatchRunnable, IdleRunnable,
539 nsITimerCallback)
540 } // anonymous namespace
542 /* static */
543 void ChromeUtils::IdleDispatch(const GlobalObject& aGlobal,
544 IdleRequestCallback& aCallback,
545 const IdleRequestOptions& aOptions,
546 ErrorResult& aRv) {
547 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
548 MOZ_ASSERT(global);
550 auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback);
552 if (aOptions.mTimeout.WasPassed()) {
553 aRv = NS_DispatchToCurrentThreadQueue(
554 runnable.forget(), aOptions.mTimeout.Value(), EventQueuePriority::Idle);
555 } else {
556 aRv = NS_DispatchToCurrentThreadQueue(runnable.forget(),
557 EventQueuePriority::Idle);
561 /* static */
562 void ChromeUtils::Import(const GlobalObject& aGlobal,
563 const nsACString& aResourceURI,
564 const Optional<JS::Handle<JSObject*>>& aTargetObj,
565 JS::MutableHandle<JSObject*> aRetval,
566 ErrorResult& aRv) {
567 RefPtr moduleloader = mozJSModuleLoader::Get();
568 MOZ_ASSERT(moduleloader);
570 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE("ChromeUtils::Import",
571 OTHER, aResourceURI);
573 JSContext* cx = aGlobal.Context();
575 JS::Rooted<JSObject*> global(cx);
576 JS::Rooted<JSObject*> exports(cx);
577 nsresult rv = moduleloader->Import(cx, aResourceURI, &global, &exports);
578 if (NS_FAILED(rv)) {
579 aRv.Throw(rv);
580 return;
583 // Import() on the component loader can return NS_OK while leaving an
584 // exception on the JSContext. Check for that case.
585 if (JS_IsExceptionPending(cx)) {
586 aRv.NoteJSContextException(cx);
587 return;
590 if (aTargetObj.WasPassed()) {
591 if (!JS_AssignObject(cx, aTargetObj.Value(), exports)) {
592 aRv.Throw(NS_ERROR_FAILURE);
593 return;
597 if (!JS_WrapObject(cx, &exports)) {
598 aRv.Throw(NS_ERROR_FAILURE);
599 return;
601 aRetval.set(exports);
604 static mozJSModuleLoader* GetModuleLoaderForCurrentGlobal(
605 JSContext* aCx, const GlobalObject& aGlobal,
606 Maybe<loader::NonSharedGlobalSyncModuleLoaderScope>&
607 aMaybeSyncLoaderScope) {
608 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
610 if (mozJSModuleLoader::IsSharedSystemGlobal(global)) {
611 return mozJSModuleLoader::Get();
613 if (mozJSModuleLoader::IsDevToolsLoaderGlobal(global)) {
614 return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
617 if (loader::NonSharedGlobalSyncModuleLoaderScope::IsActive()) {
618 mozJSModuleLoader* moduleloader =
619 loader::NonSharedGlobalSyncModuleLoaderScope::ActiveLoader();
621 if (!moduleloader->IsLoaderGlobal(global->GetGlobalJSObject())) {
622 JS_ReportErrorASCII(aCx,
623 "global: \"current\" option cannot be used for "
624 "different global while other importESModule "
625 "with global: \"current\" is on the stack");
626 return nullptr;
629 return moduleloader;
632 RefPtr targetModuleLoader = global->GetModuleLoader(aCx);
633 if (!targetModuleLoader) {
634 // Sandbox without associated window returns nullptr for GetModuleLoader.
635 JS_ReportErrorASCII(aCx, "No ModuleLoader found for the current context");
636 return nullptr;
639 if (targetModuleLoader->HasFetchingModules()) {
640 if (!NS_IsMainThread()) {
641 JS_ReportErrorASCII(aCx,
642 "ChromeUtils.importESModule cannot be used in worker "
643 "when there is ongoing dynamic import");
644 return nullptr;
647 if (!mozilla::SpinEventLoopUntil(
648 "importESModule for current global"_ns, [&]() -> bool {
649 return !targetModuleLoader->HasFetchingModules();
650 })) {
651 JS_ReportErrorASCII(aCx, "Failed to wait for ongoing module requests");
652 return nullptr;
656 aMaybeSyncLoaderScope.emplace(aCx, global);
657 return aMaybeSyncLoaderScope->ActiveLoader();
660 static mozJSModuleLoader* GetModuleLoaderForOptions(
661 JSContext* aCx, const GlobalObject& aGlobal,
662 const ImportESModuleOptionsDictionary& aOptions,
663 Maybe<loader::NonSharedGlobalSyncModuleLoaderScope>&
664 aMaybeSyncLoaderScope) {
665 if (!aOptions.mGlobal.WasPassed()) {
666 return mozJSModuleLoader::Get();
669 switch (aOptions.mGlobal.Value()) {
670 case ImportESModuleTargetGlobal::Shared:
671 return mozJSModuleLoader::Get();
673 case ImportESModuleTargetGlobal::Devtools:
674 return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
676 case ImportESModuleTargetGlobal::Contextual: {
677 if (!NS_IsMainThread()) {
678 return GetModuleLoaderForCurrentGlobal(aCx, aGlobal,
679 aMaybeSyncLoaderScope);
682 RefPtr devToolsModuleloader = mozJSModuleLoader::GetDevToolsLoader();
683 if (devToolsModuleloader &&
684 devToolsModuleloader->IsLoaderGlobal(aGlobal.Get())) {
685 return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
687 return mozJSModuleLoader::Get();
690 case ImportESModuleTargetGlobal::Current:
691 return GetModuleLoaderForCurrentGlobal(aCx, aGlobal,
692 aMaybeSyncLoaderScope);
694 default:
695 MOZ_CRASH("Unknown ImportESModuleTargetGlobal");
699 static bool ValidateImportOptions(
700 JSContext* aCx, const GlobalObject& aGlobal,
701 const ImportESModuleOptionsDictionary& aOptions) {
702 if (!NS_IsMainThread() &&
703 (!aOptions.mGlobal.WasPassed() ||
704 (aOptions.mGlobal.Value() != ImportESModuleTargetGlobal::Current &&
705 aOptions.mGlobal.Value() != ImportESModuleTargetGlobal::Contextual))) {
706 JS_ReportErrorASCII(aCx,
707 "ChromeUtils.importESModule: Only { global: "
708 "\"current\" } and { global: \"contextual\" } options "
709 "are supported on worker");
710 return false;
713 if (NS_IsMainThread()) {
714 nsCOMPtr<nsIGlobalObject> global =
715 do_QueryInterface(aGlobal.GetAsSupports());
717 if (mozJSModuleLoader::IsDevToolsLoaderGlobal(global) &&
718 !aOptions.mGlobal.WasPassed()) {
719 JS_ReportErrorASCII(aCx,
720 "ChromeUtils.importESModule: global option is "
721 "required in DevTools distinct global");
722 return false;
726 return true;
729 /* static */
730 void ChromeUtils::ImportESModule(
731 const GlobalObject& aGlobal, const nsAString& aResourceURI,
732 const ImportESModuleOptionsDictionary& aOptions,
733 JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) {
734 JSContext* cx = aGlobal.Context();
736 if (!ValidateImportOptions(cx, aGlobal, aOptions)) {
737 aRv.Throw(NS_ERROR_FAILURE);
738 return;
741 Maybe<loader::NonSharedGlobalSyncModuleLoaderScope> maybeSyncLoaderScope;
742 RefPtr<mozJSModuleLoader> moduleloader =
743 GetModuleLoaderForOptions(cx, aGlobal, aOptions, maybeSyncLoaderScope);
744 if (!moduleloader) {
745 aRv.Throw(NS_ERROR_FAILURE);
746 return;
749 NS_ConvertUTF16toUTF8 registryLocation(aResourceURI);
751 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE(
752 "ChromeUtils::ImportESModule", OTHER, registryLocation);
754 JS::Rooted<JSObject*> moduleNamespace(cx);
755 nsresult rv =
756 moduleloader->ImportESModule(cx, registryLocation, &moduleNamespace);
757 if (NS_FAILED(rv)) {
758 aRv.Throw(rv);
759 return;
762 MOZ_ASSERT(!JS_IsExceptionPending(cx));
764 if (!JS_WrapObject(cx, &moduleNamespace)) {
765 aRv.Throw(NS_ERROR_FAILURE);
766 return;
768 aRetval.set(moduleNamespace);
770 if (maybeSyncLoaderScope) {
771 maybeSyncLoaderScope->Finish();
775 // An integer encoding for ImportESModuleOptionsDictionary, to pass the value
776 // to the lazy getters.
777 class EncodedOptions {
778 public:
779 explicit EncodedOptions(const ImportESModuleOptionsDictionary& aOptions) {
780 if (aOptions.mGlobal.WasPassed()) {
781 mValue = uint32_t(aOptions.mGlobal.Value()) + 1;
782 } else {
783 mValue = 0;
787 explicit EncodedOptions(uint32_t aValue) : mValue(aValue) {}
789 int32_t toInt32() const { return int32_t(mValue); }
791 void DecodeInto(ImportESModuleOptionsDictionary& aOptions) {
792 if (mValue == 0) {
793 aOptions.mGlobal.Reset();
794 } else {
795 aOptions.mGlobal.Construct(ImportESModuleTargetGlobal(mValue - 1));
799 private:
800 uint32_t mValue = 0;
803 namespace lazy_getter {
805 // The property id of the getter.
806 // Used by all lazy getters.
807 static const size_t SLOT_ID = 0;
809 // The URI of the module to import.
810 // Used by ChromeUtils.defineModuleGetter and ChromeUtils.defineESModuleGetters.
811 static const size_t SLOT_URI = 1;
813 // An array object that contians values for PARAM_INDEX_TARGET and
814 // PARAM_INDEX_LAMBDA.
815 // Used by ChromeUtils.defineLazyGetter.
816 static const size_t SLOT_PARAMS = 1;
818 // The EncodedOptions value.
819 // Used by ChromeUtils.defineESModuleGetters.
820 static const size_t SLOT_OPTIONS = 2;
822 static const size_t PARAM_INDEX_TARGET = 0;
823 static const size_t PARAM_INDEX_LAMBDA = 1;
824 static const size_t PARAMS_COUNT = 2;
826 static bool ExtractArgs(JSContext* aCx, JS::CallArgs& aArgs,
827 JS::MutableHandle<JSObject*> aCallee,
828 JS::MutableHandle<JSObject*> aThisObj,
829 JS::MutableHandle<jsid> aId) {
830 aCallee.set(&aArgs.callee());
832 JS::Handle<JS::Value> thisv = aArgs.thisv();
833 if (!thisv.isObject()) {
834 JS_ReportErrorASCII(aCx, "Invalid target object");
835 return false;
838 aThisObj.set(&thisv.toObject());
840 JS::Rooted<JS::Value> id(aCx,
841 js::GetFunctionNativeReserved(aCallee, SLOT_ID));
842 MOZ_ALWAYS_TRUE(JS_ValueToId(aCx, id, aId));
843 return true;
846 static bool JSLazyGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
847 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
849 JS::Rooted<JSObject*> callee(aCx);
850 JS::Rooted<JSObject*> unused(aCx);
851 JS::Rooted<jsid> id(aCx);
852 if (!ExtractArgs(aCx, args, &callee, &unused, &id)) {
853 return false;
856 JS::Rooted<JS::Value> paramsVal(
857 aCx, js::GetFunctionNativeReserved(callee, SLOT_PARAMS));
858 if (paramsVal.isUndefined()) {
859 args.rval().setUndefined();
860 return true;
862 // Avoid calling the lambda multiple times, in case of:
863 // * the getter function is retrieved from property descriptor and called
864 // * the lambda gets the property again
865 // * the getter function throws and accessed again
866 js::SetFunctionNativeReserved(callee, SLOT_PARAMS, JS::UndefinedHandleValue);
868 JS::Rooted<JSObject*> paramsObj(aCx, &paramsVal.toObject());
870 JS::Rooted<JS::Value> targetVal(aCx);
871 JS::Rooted<JS::Value> lambdaVal(aCx);
872 if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_TARGET, &targetVal)) {
873 return false;
875 if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_LAMBDA, &lambdaVal)) {
876 return false;
879 JS::Rooted<JSObject*> targetObj(aCx, &targetVal.toObject());
881 JS::Rooted<JS::Value> value(aCx);
882 if (!JS::Call(aCx, targetObj, lambdaVal, JS::HandleValueArray::empty(),
883 &value)) {
884 return false;
887 if (!JS_DefinePropertyById(aCx, targetObj, id, value, JSPROP_ENUMERATE)) {
888 return false;
891 args.rval().set(value);
892 return true;
895 static bool DefineLazyGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
896 JS::Handle<JS::Value> aName,
897 JS::Handle<JSObject*> aLambda) {
898 JS::Rooted<JS::PropertyKey> id(aCx);
899 if (!JS_ValueToId(aCx, aName, &id)) {
900 return false;
903 JS::Rooted<JS::PropertyKey> funId(aCx);
904 if (id.isAtom()) {
905 funId = id;
906 } else {
907 // Don't care int and symbol cases.
908 funId = JS::PropertyKey::NonIntAtom(JS_GetEmptyString(aCx));
911 JS::Rooted<JSObject*> getter(
912 aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
913 aCx, JSLazyGetter, 0, 0, funId)));
914 if (!getter) {
915 JS_ReportOutOfMemory(aCx);
916 return false;
919 JS::RootedVector<JS::Value> params(aCx);
920 if (!params.resize(PARAMS_COUNT)) {
921 return false;
923 params[PARAM_INDEX_TARGET].setObject(*aTarget);
924 params[PARAM_INDEX_LAMBDA].setObject(*aLambda);
925 JS::Rooted<JSObject*> paramsObj(aCx, JS::NewArrayObject(aCx, params));
926 if (!paramsObj) {
927 return false;
930 js::SetFunctionNativeReserved(getter, SLOT_ID, aName);
931 js::SetFunctionNativeReserved(getter, SLOT_PARAMS,
932 JS::ObjectValue(*paramsObj));
934 return JS_DefinePropertyById(aCx, aTarget, id, getter, nullptr,
935 JSPROP_ENUMERATE);
938 enum class ModuleType { JSM, ESM };
940 static bool ModuleGetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
941 ModuleType aType) {
942 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
944 JS::Rooted<JSObject*> callee(aCx);
945 JS::Rooted<JSObject*> thisObj(aCx);
946 JS::Rooted<jsid> id(aCx);
947 if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
948 return false;
951 JS::Rooted<JSString*> moduleURI(
952 aCx, js::GetFunctionNativeReserved(callee, SLOT_URI).toString());
953 JS::UniqueChars bytes = JS_EncodeStringToUTF8(aCx, moduleURI);
954 if (!bytes) {
955 return false;
957 nsDependentCString uri(bytes.get());
959 JS::Rooted<JS::Value> value(aCx);
960 if (aType == ModuleType::JSM) {
961 RefPtr moduleloader = mozJSModuleLoader::Get();
962 MOZ_ASSERT(moduleloader);
964 JS::Rooted<JSObject*> moduleGlobal(aCx);
965 JS::Rooted<JSObject*> moduleExports(aCx);
966 nsresult rv = moduleloader->Import(aCx, uri, &moduleGlobal, &moduleExports);
967 if (NS_FAILED(rv)) {
968 Throw(aCx, rv);
969 return false;
972 // JSM's exports is from the same realm.
973 if (!JS_GetPropertyById(aCx, moduleExports, id, &value)) {
974 return false;
976 } else {
977 EncodedOptions encodedOptions(
978 js::GetFunctionNativeReserved(callee, SLOT_OPTIONS).toInt32());
980 ImportESModuleOptionsDictionary options;
981 encodedOptions.DecodeInto(options);
983 GlobalObject global(aCx, callee);
985 Maybe<loader::NonSharedGlobalSyncModuleLoaderScope> maybeSyncLoaderScope;
986 RefPtr<mozJSModuleLoader> moduleloader =
987 GetModuleLoaderForOptions(aCx, global, options, maybeSyncLoaderScope);
988 if (!moduleloader) {
989 return false;
992 JS::Rooted<JSObject*> moduleNamespace(aCx);
993 nsresult rv = moduleloader->ImportESModule(aCx, uri, &moduleNamespace);
994 if (NS_FAILED(rv)) {
995 Throw(aCx, rv);
996 return false;
999 // ESM's namespace is from the module's realm.
1001 JSAutoRealm ar(aCx, moduleNamespace);
1002 if (!JS_GetPropertyById(aCx, moduleNamespace, id, &value)) {
1003 return false;
1006 if (!JS_WrapValue(aCx, &value)) {
1007 return false;
1010 if (maybeSyncLoaderScope) {
1011 maybeSyncLoaderScope->Finish();
1015 if (!JS_DefinePropertyById(aCx, thisObj, id, value, JSPROP_ENUMERATE)) {
1016 return false;
1019 args.rval().set(value);
1020 return true;
1023 static bool JSModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
1024 return ModuleGetterImpl(aCx, aArgc, aVp, ModuleType::JSM);
1027 static bool ESModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
1028 return ModuleGetterImpl(aCx, aArgc, aVp, ModuleType::ESM);
1031 static bool ModuleSetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
1032 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
1034 JS::Rooted<JSObject*> callee(aCx);
1035 JS::Rooted<JSObject*> thisObj(aCx);
1036 JS::Rooted<jsid> id(aCx);
1037 if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
1038 return false;
1041 return JS_DefinePropertyById(aCx, thisObj, id, args.get(0), JSPROP_ENUMERATE);
1044 static bool JSModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
1045 return ModuleSetterImpl(aCx, aArgc, aVp);
1048 static bool ESModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
1049 return ModuleSetterImpl(aCx, aArgc, aVp);
1052 static bool DefineJSModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
1053 const nsAString& aId,
1054 const nsAString& aResourceURI) {
1055 JS::Rooted<JS::Value> uri(aCx);
1056 JS::Rooted<JS::Value> idValue(aCx);
1057 JS::Rooted<jsid> id(aCx);
1058 if (!xpc::NonVoidStringToJsval(aCx, aResourceURI, &uri) ||
1059 !xpc::NonVoidStringToJsval(aCx, aId, &idValue) ||
1060 !JS_ValueToId(aCx, idValue, &id)) {
1061 return false;
1063 idValue = js::IdToValue(id);
1065 JS::Rooted<JSObject*> getter(
1066 aCx, JS_GetFunctionObject(
1067 js::NewFunctionByIdWithReserved(aCx, JSModuleGetter, 0, 0, id)));
1069 JS::Rooted<JSObject*> setter(
1070 aCx, JS_GetFunctionObject(
1071 js::NewFunctionByIdWithReserved(aCx, JSModuleSetter, 0, 0, id)));
1073 if (!getter || !setter) {
1074 JS_ReportOutOfMemory(aCx);
1075 return false;
1078 js::SetFunctionNativeReserved(getter, SLOT_ID, idValue);
1079 js::SetFunctionNativeReserved(setter, SLOT_ID, idValue);
1081 js::SetFunctionNativeReserved(getter, SLOT_URI, uri);
1083 return JS_DefinePropertyById(aCx, aTarget, id, getter, setter,
1084 JSPROP_ENUMERATE);
1087 static bool DefineESModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
1088 JS::Handle<JS::PropertyKey> aId,
1089 JS::Handle<JS::Value> aResourceURI,
1090 const EncodedOptions& encodedOptions) {
1091 JS::Rooted<JS::Value> idVal(aCx, JS::StringValue(aId.toString()));
1093 JS::Rooted<JS::Value> optionsVal(aCx,
1094 JS::Int32Value(encodedOptions.toInt32()));
1096 JS::Rooted<JSObject*> getter(
1097 aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
1098 aCx, ESModuleGetter, 0, 0, aId)));
1100 JS::Rooted<JSObject*> setter(
1101 aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
1102 aCx, ESModuleSetter, 0, 0, aId)));
1104 if (!getter || !setter) {
1105 JS_ReportOutOfMemory(aCx);
1106 return false;
1109 js::SetFunctionNativeReserved(getter, SLOT_ID, idVal);
1110 js::SetFunctionNativeReserved(setter, SLOT_ID, idVal);
1112 js::SetFunctionNativeReserved(getter, SLOT_URI, aResourceURI);
1114 js::SetFunctionNativeReserved(getter, SLOT_OPTIONS, optionsVal);
1116 return JS_DefinePropertyById(aCx, aTarget, aId, getter, setter,
1117 JSPROP_ENUMERATE);
1120 } // namespace lazy_getter
1122 /* static */
1123 void ChromeUtils::DefineLazyGetter(const GlobalObject& aGlobal,
1124 JS::Handle<JSObject*> aTarget,
1125 JS::Handle<JS::Value> aName,
1126 JS::Handle<JSObject*> aLambda,
1127 ErrorResult& aRv) {
1128 JSContext* cx = aGlobal.Context();
1129 if (!lazy_getter::DefineLazyGetter(cx, aTarget, aName, aLambda)) {
1130 aRv.NoteJSContextException(cx);
1131 return;
1135 /* static */
1136 void ChromeUtils::DefineModuleGetter(const GlobalObject& global,
1137 JS::Handle<JSObject*> target,
1138 const nsAString& id,
1139 const nsAString& resourceURI,
1140 ErrorResult& aRv) {
1141 if (!lazy_getter::DefineJSModuleGetter(global.Context(), target, id,
1142 resourceURI)) {
1143 aRv.NoteJSContextException(global.Context());
1147 /* static */
1148 void ChromeUtils::DefineESModuleGetters(
1149 const GlobalObject& global, JS::Handle<JSObject*> target,
1150 JS::Handle<JSObject*> modules,
1151 const ImportESModuleOptionsDictionary& aOptions, ErrorResult& aRv) {
1152 JSContext* cx = global.Context();
1154 JS::Rooted<JS::IdVector> props(cx, JS::IdVector(cx));
1155 if (!JS_Enumerate(cx, modules, &props)) {
1156 aRv.NoteJSContextException(cx);
1157 return;
1160 if (!ValidateImportOptions(cx, global, aOptions)) {
1161 aRv.Throw(NS_ERROR_FAILURE);
1162 return;
1165 EncodedOptions encodedOptions(aOptions);
1167 JS::Rooted<JS::PropertyKey> prop(cx);
1168 JS::Rooted<JS::Value> resourceURIVal(cx);
1169 for (JS::PropertyKey tmp : props) {
1170 prop = tmp;
1172 if (!prop.isString()) {
1173 aRv.Throw(NS_ERROR_FAILURE);
1174 return;
1177 if (!JS_GetPropertyById(cx, modules, prop, &resourceURIVal)) {
1178 aRv.NoteJSContextException(cx);
1179 return;
1182 if (!lazy_getter::DefineESModuleGetter(cx, target, prop, resourceURIVal,
1183 encodedOptions)) {
1184 aRv.NoteJSContextException(cx);
1185 return;
1190 #ifdef XP_UNIX
1191 /* static */
1192 void ChromeUtils::GetLibcConstants(const GlobalObject&,
1193 LibcConstants& aConsts) {
1194 aConsts.mEINTR.Construct(EINTR);
1195 aConsts.mEACCES.Construct(EACCES);
1196 aConsts.mEAGAIN.Construct(EAGAIN);
1197 aConsts.mEINVAL.Construct(EINVAL);
1198 aConsts.mENOSYS.Construct(ENOSYS);
1200 aConsts.mF_SETFD.Construct(F_SETFD);
1201 aConsts.mF_SETFL.Construct(F_SETFL);
1203 aConsts.mFD_CLOEXEC.Construct(FD_CLOEXEC);
1205 aConsts.mAT_EACCESS.Construct(AT_EACCESS);
1207 aConsts.mO_CREAT.Construct(O_CREAT);
1208 aConsts.mO_NONBLOCK.Construct(O_NONBLOCK);
1209 aConsts.mO_WRONLY.Construct(O_WRONLY);
1211 aConsts.mPOLLERR.Construct(POLLERR);
1212 aConsts.mPOLLHUP.Construct(POLLHUP);
1213 aConsts.mPOLLIN.Construct(POLLIN);
1214 aConsts.mPOLLNVAL.Construct(POLLNVAL);
1215 aConsts.mPOLLOUT.Construct(POLLOUT);
1217 aConsts.mWNOHANG.Construct(WNOHANG);
1219 # ifdef XP_LINUX
1220 aConsts.mPR_CAPBSET_READ.Construct(PR_CAPBSET_READ);
1221 # endif
1223 #endif
1225 /* static */
1226 void ChromeUtils::OriginAttributesToSuffix(
1227 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1228 nsCString& aSuffix)
1231 OriginAttributes attrs(aAttrs);
1232 attrs.CreateSuffix(aSuffix);
1235 /* static */
1236 bool ChromeUtils::OriginAttributesMatchPattern(
1237 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1238 const dom::OriginAttributesPatternDictionary& aPattern) {
1239 OriginAttributes attrs(aAttrs);
1240 OriginAttributesPattern pattern(aPattern);
1241 return pattern.Matches(attrs);
1244 /* static */
1245 void ChromeUtils::CreateOriginAttributesFromOrigin(
1246 dom::GlobalObject& aGlobal, const nsAString& aOrigin,
1247 dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
1248 OriginAttributes attrs;
1249 nsAutoCString suffix;
1250 if (!attrs.PopulateFromOrigin(NS_ConvertUTF16toUTF8(aOrigin), suffix)) {
1251 aRv.Throw(NS_ERROR_FAILURE);
1252 return;
1254 aAttrs = attrs;
1257 /* static */
1258 void ChromeUtils::CreateOriginAttributesFromOriginSuffix(
1259 dom::GlobalObject& aGlobal, const nsAString& aSuffix,
1260 dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
1261 OriginAttributes attrs;
1262 nsAutoCString suffix;
1263 if (!attrs.PopulateFromSuffix(NS_ConvertUTF16toUTF8(aSuffix))) {
1264 aRv.Throw(NS_ERROR_FAILURE);
1265 return;
1267 aAttrs = attrs;
1270 /* static */
1271 void ChromeUtils::FillNonDefaultOriginAttributes(
1272 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1273 dom::OriginAttributesDictionary& aNewAttrs) {
1274 aNewAttrs = aAttrs;
1277 /* static */
1278 bool ChromeUtils::IsOriginAttributesEqual(
1279 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aA,
1280 const dom::OriginAttributesDictionary& aB) {
1281 return IsOriginAttributesEqual(aA, aB);
1284 /* static */
1285 bool ChromeUtils::IsOriginAttributesEqual(
1286 const dom::OriginAttributesDictionary& aA,
1287 const dom::OriginAttributesDictionary& aB) {
1288 return aA == aB;
1291 /* static */
1292 void ChromeUtils::GetBaseDomainFromPartitionKey(dom::GlobalObject& aGlobal,
1293 const nsAString& aPartitionKey,
1294 nsAString& aBaseDomain,
1295 ErrorResult& aRv) {
1296 nsString scheme;
1297 nsString pkBaseDomain;
1298 int32_t port;
1299 bool ancestor;
1301 if (!mozilla::OriginAttributes::ParsePartitionKey(
1302 aPartitionKey, scheme, pkBaseDomain, port, ancestor)) {
1303 aRv.Throw(NS_ERROR_FAILURE);
1304 return;
1307 aBaseDomain = pkBaseDomain;
1310 /* static */
1311 void ChromeUtils::GetPartitionKeyFromURL(dom::GlobalObject& aGlobal,
1312 const nsAString& aURL,
1313 nsAString& aPartitionKey,
1314 ErrorResult& aRv) {
1315 nsCOMPtr<nsIURI> uri;
1316 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL);
1317 if (NS_SUCCEEDED(rv) && uri->SchemeIs("chrome")) {
1318 rv = NS_ERROR_FAILURE;
1321 if (NS_WARN_IF(NS_FAILED(rv))) {
1322 aPartitionKey.Truncate();
1323 aRv.Throw(rv);
1324 return;
1327 mozilla::OriginAttributes attrs;
1328 // For now, uses assume the partition key is cross-site.
1329 // We will need to not make this assumption to allow access
1330 // to same-site partitioned cookies in the cookie extension API.
1331 attrs.SetPartitionKey(uri, false);
1333 aPartitionKey = attrs.mPartitionKey;
1336 #ifdef NIGHTLY_BUILD
1337 /* static */
1338 void ChromeUtils::GetRecentJSDevError(GlobalObject& aGlobal,
1339 JS::MutableHandle<JS::Value> aRetval,
1340 ErrorResult& aRv) {
1341 aRetval.setUndefined();
1342 auto runtime = CycleCollectedJSRuntime::Get();
1343 MOZ_ASSERT(runtime);
1345 auto cx = aGlobal.Context();
1346 if (!runtime->GetRecentDevError(cx, aRetval)) {
1347 aRv.NoteJSContextException(cx);
1348 return;
1352 /* static */
1353 void ChromeUtils::ClearRecentJSDevError(GlobalObject&) {
1354 auto runtime = CycleCollectedJSRuntime::Get();
1355 MOZ_ASSERT(runtime);
1357 runtime->ClearRecentDevError();
1359 #endif // NIGHTLY_BUILD
1361 void ChromeUtils::ClearStyleSheetCacheByPrincipal(GlobalObject&,
1362 nsIPrincipal* aForPrincipal) {
1363 SharedStyleSheetCache::Clear(aForPrincipal);
1366 void ChromeUtils::ClearStyleSheetCacheByBaseDomain(
1367 GlobalObject&, const nsACString& aBaseDomain) {
1368 SharedStyleSheetCache::Clear(nullptr, &aBaseDomain);
1371 void ChromeUtils::ClearStyleSheetCache(GlobalObject&) {
1372 SharedStyleSheetCache::Clear();
1375 #define PROCTYPE_TO_WEBIDL_CASE(_procType, _webidl) \
1376 case mozilla::ProcType::_procType: \
1377 return WebIDLProcType::_webidl
1379 static WebIDLProcType ProcTypeToWebIDL(mozilla::ProcType aType) {
1380 // Max is the value of the last enum, not the length, so add one.
1381 static_assert(
1382 static_cast<size_t>(MaxContiguousEnumValue<WebIDLProcType>::value) ==
1383 static_cast<size_t>(ProcType::Max),
1384 "In order for this static cast to be okay, "
1385 "WebIDLProcType must match ProcType exactly");
1387 // These must match the similar ones in E10SUtils.sys.mjs, RemoteTypes.h,
1388 // ProcInfo.h and ChromeUtils.webidl
1389 switch (aType) {
1390 PROCTYPE_TO_WEBIDL_CASE(Web, Web);
1391 PROCTYPE_TO_WEBIDL_CASE(WebIsolated, WebIsolated);
1392 PROCTYPE_TO_WEBIDL_CASE(File, File);
1393 PROCTYPE_TO_WEBIDL_CASE(Extension, Extension);
1394 PROCTYPE_TO_WEBIDL_CASE(PrivilegedAbout, Privilegedabout);
1395 PROCTYPE_TO_WEBIDL_CASE(PrivilegedMozilla, Privilegedmozilla);
1396 PROCTYPE_TO_WEBIDL_CASE(WebCOOPCOEP, WithCoopCoep);
1397 PROCTYPE_TO_WEBIDL_CASE(WebServiceWorker, WebServiceWorker);
1398 PROCTYPE_TO_WEBIDL_CASE(Inference, Inference);
1400 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1401 process_bin_type, procinfo_typename, \
1402 webidl_typename, allcaps_name) \
1403 PROCTYPE_TO_WEBIDL_CASE(procinfo_typename, webidl_typename);
1404 #define SKIP_PROCESS_TYPE_CONTENT
1405 #ifndef MOZ_ENABLE_FORKSERVER
1406 # define SKIP_PROCESS_TYPE_FORKSERVER
1407 #endif // MOZ_ENABLE_FORKSERVER
1408 #include "mozilla/GeckoProcessTypes.h"
1409 #undef SKIP_PROCESS_TYPE_CONTENT
1410 #ifndef MOZ_ENABLE_FORKSERVER
1411 # undef SKIP_PROCESS_TYPE_FORKSERVER
1412 #endif // MOZ_ENABLE_FORKSERVER
1413 #undef GECKO_PROCESS_TYPE
1415 PROCTYPE_TO_WEBIDL_CASE(Preallocated, Preallocated);
1416 PROCTYPE_TO_WEBIDL_CASE(Unknown, Unknown);
1419 MOZ_ASSERT(false, "Unhandled case in ProcTypeToWebIDL");
1420 return WebIDLProcType::Unknown;
1423 #undef PROCTYPE_TO_WEBIDL_CASE
1425 /* static */
1426 already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
1427 ErrorResult& aRv) {
1428 // This function will use IPDL to enable threads info on macOS
1429 // see https://bugzilla.mozilla.org/show_bug.cgi?id=1529023
1430 if (!XRE_IsParentProcess()) {
1431 aRv.Throw(NS_ERROR_FAILURE);
1432 return nullptr;
1434 // Prepare the JS promise that will hold our response.
1435 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1436 MOZ_ASSERT(global);
1437 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
1438 if (NS_WARN_IF(aRv.Failed())) {
1439 return nullptr;
1441 MOZ_ASSERT(domPromise);
1443 // Get a list of processes to examine and pre-fill them with available info.
1444 // Note that this is subject to race conditions: just because we have a
1445 // process in the list doesn't mean that the process will still be alive when
1446 // we attempt to get its information. Followup code MUST be able to fail
1447 // gracefully on some processes and still return whichever information is
1448 // available.
1450 // Get all the content parents.
1451 // Note that this array includes even the long dead content parents, so we
1452 // might have some garbage, especially with Fission.
1453 // SAFETY NOTE: `contentParents` is only valid if used synchronously.
1454 // Anything else and you may end up dealing with dangling pointers.
1455 nsTArray<ContentParent*> contentParents;
1456 ContentParent::GetAll(contentParents);
1458 // Prepare our background request.
1459 // We reserve one more slot for the browser process itself.
1460 nsTArray<ProcInfoRequest> requests(contentParents.Length() + 1);
1461 // Requesting process info for the browser process itself.
1462 requests.EmplaceBack(
1463 /* aPid = */ base::GetCurrentProcId(),
1464 /* aProcessType = */ ProcType::Browser,
1465 /* aOrigin = */ ""_ns,
1466 /* aWindowInfo = */ nsTArray<WindowInfo>(),
1467 /* aUtilityInfo = */ nsTArray<UtilityInfo>());
1469 // First handle non-ContentParent processes.
1470 mozilla::ipc::GeckoChildProcessHost::GetAll(
1471 [&requests](mozilla::ipc::GeckoChildProcessHost* aGeckoProcess) {
1472 base::ProcessId childPid = aGeckoProcess->GetChildProcessId();
1473 if (childPid == 0) {
1474 // Something went wrong with this process, it may be dead already,
1475 // fail gracefully.
1476 return;
1478 mozilla::ProcType type = mozilla::ProcType::Unknown;
1480 switch (aGeckoProcess->GetProcessType()) {
1481 case GeckoProcessType::GeckoProcessType_Content: {
1482 // These processes are handled separately.
1483 return;
1486 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1487 process_bin_type, procinfo_typename, \
1488 webidl_typename, allcaps_name) \
1489 case GeckoProcessType::GeckoProcessType_##enum_name: { \
1490 type = mozilla::ProcType::procinfo_typename; \
1491 break; \
1493 #define SKIP_PROCESS_TYPE_CONTENT
1494 #ifndef MOZ_ENABLE_FORKSERVER
1495 # define SKIP_PROCESS_TYPE_FORKSERVER
1496 #endif // MOZ_ENABLE_FORKSERVER
1497 #include "mozilla/GeckoProcessTypes.h"
1498 #ifndef MOZ_ENABLE_FORKSERVER
1499 # undef SKIP_PROCESS_TYPE_FORKSERVER
1500 #endif // MOZ_ENABLE_FORKSERVER
1501 #undef SKIP_PROCESS_TYPE_CONTENT
1502 #undef GECKO_PROCESS_TYPE
1503 default:
1504 // Leave the default Unknown value in |type|.
1505 break;
1508 // Attach utility actor information to the process.
1509 nsTArray<UtilityInfo> utilityActors;
1510 if (aGeckoProcess->GetProcessType() ==
1511 GeckoProcessType::GeckoProcessType_Utility) {
1512 RefPtr<mozilla::ipc::UtilityProcessManager> upm =
1513 mozilla::ipc::UtilityProcessManager::GetSingleton();
1514 if (!utilityActors.AppendElements(upm->GetActors(aGeckoProcess),
1515 fallible)) {
1516 NS_WARNING("Error adding actors");
1517 return;
1521 requests.EmplaceBack(
1522 /* aPid = */ childPid,
1523 /* aProcessType = */ type,
1524 /* aOrigin = */ ""_ns,
1525 /* aWindowInfo = */ nsTArray<WindowInfo>(), // Without a
1526 // ContentProcess, no
1527 // DOM windows.
1528 /* aUtilityInfo = */ std::move(utilityActors),
1529 /* aChild = */ 0 // Without a ContentProcess, no ChildId.
1530 #ifdef XP_DARWIN
1532 /* aChildTask = */ aGeckoProcess->GetChildTask()
1533 #endif // XP_DARWIN
1537 // Now handle ContentParents.
1538 for (const auto* contentParent : contentParents) {
1539 if (!contentParent || !contentParent->Process()) {
1540 // Presumably, the process is dead or dying.
1541 continue;
1543 base::ProcessId pid = contentParent->Process()->GetChildProcessId();
1544 if (pid == 0) {
1545 // Presumably, the process is dead or dying.
1546 continue;
1548 if (contentParent->Process()->GetProcessType() !=
1549 GeckoProcessType::GeckoProcessType_Content) {
1550 // We're probably racing against a process changing type.
1551 // We'll get it in the next call, skip it for the moment.
1552 continue;
1555 // Since this code is executed synchronously on the main thread,
1556 // processes cannot die while we're in this loop.
1557 mozilla::ProcType type = mozilla::ProcType::Unknown;
1559 // Convert the remoteType into a ProcType.
1560 // Ideally, the remoteType should be strongly typed
1561 // upstream, this would make the conversion less brittle.
1562 const nsAutoCString remoteType(contentParent->GetRemoteType());
1563 if (StringBeginsWith(remoteType, FISSION_WEB_REMOTE_TYPE)) {
1564 // WARNING: Do not change the order, as
1565 // `DEFAULT_REMOTE_TYPE` is a prefix of
1566 // `FISSION_WEB_REMOTE_TYPE`.
1567 type = mozilla::ProcType::WebIsolated;
1568 } else if (StringBeginsWith(remoteType, SERVICEWORKER_REMOTE_TYPE)) {
1569 type = mozilla::ProcType::WebServiceWorker;
1570 } else if (StringBeginsWith(remoteType,
1571 WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
1572 type = mozilla::ProcType::WebCOOPCOEP;
1573 } else if (remoteType == FILE_REMOTE_TYPE) {
1574 type = mozilla::ProcType::File;
1575 } else if (remoteType == EXTENSION_REMOTE_TYPE) {
1576 type = mozilla::ProcType::Extension;
1577 } else if (remoteType == PRIVILEGEDABOUT_REMOTE_TYPE) {
1578 type = mozilla::ProcType::PrivilegedAbout;
1579 } else if (remoteType == PRIVILEGEDMOZILLA_REMOTE_TYPE) {
1580 type = mozilla::ProcType::PrivilegedMozilla;
1581 } else if (remoteType == PREALLOC_REMOTE_TYPE) {
1582 type = mozilla::ProcType::Preallocated;
1583 } else if (remoteType == INFERENCE_REMOTE_TYPE) {
1584 type = mozilla::ProcType::Inference;
1585 } else if (StringBeginsWith(remoteType, DEFAULT_REMOTE_TYPE)) {
1586 type = mozilla::ProcType::Web;
1587 } else {
1588 MOZ_CRASH_UNSAFE_PRINTF("Unknown remoteType '%s'", remoteType.get());
1591 // By convention, everything after '=' is the origin.
1592 nsAutoCString origin;
1593 nsACString::const_iterator cursor;
1594 nsACString::const_iterator end;
1595 remoteType.BeginReading(cursor);
1596 remoteType.EndReading(end);
1597 if (FindCharInReadable('=', cursor, end)) {
1598 origin = Substring(++cursor, end);
1601 // Attach DOM window information to the process.
1602 nsTArray<WindowInfo> windows;
1603 for (const auto& browserParentWrapperKey :
1604 contentParent->ManagedPBrowserParent()) {
1605 for (const auto& windowGlobalParentWrapperKey :
1606 browserParentWrapperKey->ManagedPWindowGlobalParent()) {
1607 // WindowGlobalParent is the only immediate subclass of
1608 // PWindowGlobalParent.
1609 auto* windowGlobalParent =
1610 static_cast<WindowGlobalParent*>(windowGlobalParentWrapperKey);
1612 nsString documentTitle;
1613 windowGlobalParent->GetDocumentTitle(documentTitle);
1614 WindowInfo* window = windows.EmplaceBack(
1615 fallible,
1616 /* aOuterWindowId = */ windowGlobalParent->OuterWindowId(),
1617 /* aDocumentURI = */ windowGlobalParent->GetDocumentURI(),
1618 /* aDocumentTitle = */ std::move(documentTitle),
1619 /* aIsProcessRoot = */ windowGlobalParent->IsProcessRoot(),
1620 /* aIsInProcess = */ windowGlobalParent->IsInProcess());
1621 if (!window) {
1622 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
1623 return nullptr;
1627 requests.EmplaceBack(
1628 /* aPid = */ pid,
1629 /* aProcessType = */ type,
1630 /* aOrigin = */ origin,
1631 /* aWindowInfo = */ std::move(windows),
1632 /* aUtilityInfo = */ nsTArray<UtilityInfo>(),
1633 /* aChild = */ contentParent->ChildID()
1634 #ifdef XP_DARWIN
1636 /* aChildTask = */ contentParent->Process()->GetChildTask()
1637 #endif // XP_DARWIN
1641 // Now place background request.
1642 RefPtr<nsISerialEventTarget> target = global->SerialEventTarget();
1643 mozilla::GetProcInfo(std::move(requests))
1644 ->Then(
1645 target, __func__,
1646 [target,
1647 domPromise](const HashMap<base::ProcessId, ProcInfo>& aSysProcInfo) {
1648 ParentProcInfoDictionary parentInfo;
1649 if (aSysProcInfo.count() == 0) {
1650 // For some reason, we couldn't get *any* info.
1651 // Maybe a sandboxing issue?
1652 domPromise->MaybeReject(NS_ERROR_UNEXPECTED);
1653 return;
1655 nsTArray<ChildProcInfoDictionary> childrenInfo(
1656 aSysProcInfo.count() - 1);
1657 for (auto iter = aSysProcInfo.iter(); !iter.done(); iter.next()) {
1658 const auto& sysProcInfo = iter.get().value();
1659 nsresult rv;
1660 if (sysProcInfo.type == ProcType::Browser) {
1661 rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, &parentInfo);
1662 if (NS_FAILED(rv)) {
1663 // Failing to copy? That's probably not something from we can
1664 // (or should) try to recover gracefully.
1665 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1666 return;
1668 MOZ_ASSERT(sysProcInfo.childId == 0);
1669 MOZ_ASSERT(sysProcInfo.origin.IsEmpty());
1670 } else {
1671 mozilla::dom::ChildProcInfoDictionary* childInfo =
1672 childrenInfo.AppendElement(fallible);
1673 if (!childInfo) {
1674 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1675 return;
1677 rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, childInfo);
1678 if (NS_FAILED(rv)) {
1679 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1680 return;
1682 // Copy Firefox info.
1683 childInfo->mChildID = sysProcInfo.childId;
1684 childInfo->mOrigin = sysProcInfo.origin;
1685 childInfo->mType = ProcTypeToWebIDL(sysProcInfo.type);
1687 for (const auto& source : sysProcInfo.windows) {
1688 auto* dest = childInfo->mWindows.AppendElement(fallible);
1689 if (!dest) {
1690 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1691 return;
1693 dest->mOuterWindowId = source.outerWindowId;
1694 dest->mDocumentURI = source.documentURI;
1695 dest->mDocumentTitle = source.documentTitle;
1696 dest->mIsProcessRoot = source.isProcessRoot;
1697 dest->mIsInProcess = source.isInProcess;
1700 if (sysProcInfo.type == ProcType::Utility) {
1701 for (const auto& source : sysProcInfo.utilityActors) {
1702 auto* dest =
1703 childInfo->mUtilityActors.AppendElement(fallible);
1704 if (!dest) {
1705 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1706 return;
1709 dest->mActorName = source.actorName;
1715 // Attach the children to the parent.
1716 mozilla::dom::Sequence<mozilla::dom::ChildProcInfoDictionary>
1717 children(std::move(childrenInfo));
1718 parentInfo.mChildren = std::move(children);
1719 domPromise->MaybeResolve(parentInfo);
1721 [domPromise](nsresult aRv) { domPromise->MaybeReject(aRv); });
1722 MOZ_ASSERT(domPromise);
1724 // sending back the promise instance
1725 return domPromise.forget();
1728 /* static */
1729 bool ChromeUtils::VsyncEnabled(GlobalObject& aGlobal) {
1730 return mozilla::gfx::VsyncSource::GetFastestVsyncRate().isSome();
1733 void ChromeUtils::SetPerfStatsCollectionMask(GlobalObject& aGlobal,
1734 uint64_t aMask) {
1735 PerfStats::SetCollectionMask(static_cast<PerfStats::MetricMask>(aMask));
1738 already_AddRefed<Promise> ChromeUtils::CollectPerfStats(GlobalObject& aGlobal,
1739 ErrorResult& aRv) {
1740 // Creating a JS promise
1741 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1742 MOZ_ASSERT(global);
1744 RefPtr<Promise> promise = Promise::Create(global, aRv);
1745 if (aRv.Failed()) {
1746 return nullptr;
1749 RefPtr<PerfStats::PerfStatsPromise> extPromise =
1750 PerfStats::CollectPerfStatsJSON();
1752 extPromise->Then(
1753 GetCurrentSerialEventTarget(), __func__,
1754 [promise](const nsCString& aResult) {
1755 promise->MaybeResolve(NS_ConvertUTF8toUTF16(aResult));
1757 [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
1759 return promise.forget();
1762 constexpr auto kSkipSelfHosted = JS::SavedFrameSelfHosted::Exclude;
1764 /* static */
1765 void ChromeUtils::GetCallerLocation(const GlobalObject& aGlobal,
1766 nsIPrincipal* aPrincipal,
1767 JS::MutableHandle<JSObject*> aRetval) {
1768 JSContext* cx = aGlobal.Context();
1770 auto* principals = nsJSPrincipals::get(aPrincipal);
1772 JS::StackCapture captureMode(JS::FirstSubsumedFrame(cx, principals));
1774 JS::Rooted<JSObject*> frame(cx);
1775 if (!JS::CaptureCurrentStack(cx, &frame, std::move(captureMode))) {
1776 JS_ClearPendingException(cx);
1777 aRetval.set(nullptr);
1778 return;
1781 // FirstSubsumedFrame gets us a stack which stops at the first principal which
1782 // is subsumed by the given principal. That means that we may have a lot of
1783 // privileged frames that we don't care about at the top of the stack, though.
1784 // We need to filter those out to get the frame we actually want.
1785 aRetval.set(
1786 js::GetFirstSubsumedSavedFrame(cx, principals, frame, kSkipSelfHosted));
1789 /* static */
1790 void ChromeUtils::CreateError(const GlobalObject& aGlobal,
1791 const nsAString& aMessage,
1792 JS::Handle<JSObject*> aStack,
1793 JS::MutableHandle<JSObject*> aRetVal,
1794 ErrorResult& aRv) {
1795 if (aStack && !JS::IsMaybeWrappedSavedFrame(aStack)) {
1796 aRv.Throw(NS_ERROR_INVALID_ARG);
1797 return;
1800 JSContext* cx = aGlobal.Context();
1802 auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
1804 JS::Rooted<JSObject*> retVal(cx);
1806 JS::Rooted<JSString*> fileName(cx, JS_GetEmptyString(cx));
1807 uint32_t line = 0;
1808 JS::TaggedColumnNumberOneOrigin column;
1810 Maybe<JSAutoRealm> ar;
1811 JS::Rooted<JSObject*> stack(cx);
1812 if (aStack) {
1813 stack = UncheckedUnwrap(aStack);
1814 ar.emplace(cx, stack);
1816 JSPrincipals* principals =
1817 JS::GetRealmPrincipals(js::GetContextRealm(cx));
1818 if (JS::GetSavedFrameLine(cx, principals, stack, &line) !=
1819 JS::SavedFrameResult::Ok ||
1820 JS::GetSavedFrameColumn(cx, principals, stack, &column) !=
1821 JS::SavedFrameResult::Ok ||
1822 JS::GetSavedFrameSource(cx, principals, stack, &fileName) !=
1823 JS::SavedFrameResult::Ok) {
1824 return;
1828 JS::Rooted<JSString*> message(cx);
1830 JS::Rooted<JS::Value> msgVal(cx);
1831 if (!xpc::NonVoidStringToJsval(cx, aMessage, &msgVal)) {
1832 return;
1834 message = msgVal.toString();
1837 JS::Rooted<JS::Value> err(cx);
1838 if (!JS::CreateError(cx, JSEXN_ERR, stack, fileName, line,
1839 JS::ColumnNumberOneOrigin(column.oneOriginValue()),
1840 nullptr, message, JS::NothingHandleValue, &err)) {
1841 return;
1844 MOZ_ASSERT(err.isObject());
1845 retVal = &err.toObject();
1848 if (aStack && !JS_WrapObject(cx, &retVal)) {
1849 return;
1852 cleanup.release();
1853 aRetVal.set(retVal);
1856 /* static */
1857 bool ChromeUtils::HasReportingHeaderForOrigin(GlobalObject& global,
1858 const nsAString& aOrigin,
1859 ErrorResult& aRv) {
1860 if (!XRE_IsParentProcess()) {
1861 aRv.Throw(NS_ERROR_FAILURE);
1862 return false;
1865 return ReportingHeader::HasReportingHeaderForOrigin(
1866 NS_ConvertUTF16toUTF8(aOrigin));
1869 /* static */
1870 PopupBlockerState ChromeUtils::GetPopupControlState(GlobalObject& aGlobal) {
1871 switch (PopupBlocker::GetPopupControlState()) {
1872 case PopupBlocker::PopupControlState::openAllowed:
1873 return PopupBlockerState::OpenAllowed;
1875 case PopupBlocker::PopupControlState::openControlled:
1876 return PopupBlockerState::OpenControlled;
1878 case PopupBlocker::PopupControlState::openBlocked:
1879 return PopupBlockerState::OpenBlocked;
1881 case PopupBlocker::PopupControlState::openAbused:
1882 return PopupBlockerState::OpenAbused;
1884 case PopupBlocker::PopupControlState::openOverridden:
1885 return PopupBlockerState::OpenOverridden;
1887 default:
1888 MOZ_CRASH(
1889 "PopupBlocker::PopupControlState and PopupBlockerState are out of "
1890 "sync");
1894 /* static */
1895 double ChromeUtils::LastExternalProtocolIframeAllowed(GlobalObject& aGlobal) {
1896 TimeStamp when = PopupBlocker::WhenLastExternalProtocolIframeAllowed();
1897 if (when.IsNull()) {
1898 return 0;
1901 TimeDuration duration = TimeStamp::Now() - when;
1902 return duration.ToMilliseconds();
1905 /* static */
1906 void ChromeUtils::ResetLastExternalProtocolIframeAllowed(
1907 GlobalObject& aGlobal) {
1908 PopupBlocker::ResetLastExternalProtocolIframeAllowed();
1911 /* static */
1912 void ChromeUtils::EndWheelTransaction(GlobalObject& aGlobal) {
1913 // This allows us to end the current wheel transaction from the browser
1914 // chrome. We do not need to perform any checks before calling
1915 // EndTransaction(), as it should do nothing in the case that there is
1916 // no current wheel transaction.
1917 WheelTransaction::EndTransaction();
1920 /* static */
1921 void ChromeUtils::RegisterWindowActor(const GlobalObject& aGlobal,
1922 const nsACString& aName,
1923 const WindowActorOptions& aOptions,
1924 ErrorResult& aRv) {
1925 MOZ_ASSERT(XRE_IsParentProcess());
1927 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1928 service->RegisterWindowActor(aName, aOptions, aRv);
1931 /* static */
1932 void ChromeUtils::UnregisterWindowActor(const GlobalObject& aGlobal,
1933 const nsACString& aName) {
1934 MOZ_ASSERT(XRE_IsParentProcess());
1936 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1937 service->UnregisterWindowActor(aName);
1940 /* static */
1941 void ChromeUtils::RegisterProcessActor(const GlobalObject& aGlobal,
1942 const nsACString& aName,
1943 const ProcessActorOptions& aOptions,
1944 ErrorResult& aRv) {
1945 MOZ_ASSERT(XRE_IsParentProcess());
1947 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1948 service->RegisterProcessActor(aName, aOptions, aRv);
1951 /* static */
1952 void ChromeUtils::UnregisterProcessActor(const GlobalObject& aGlobal,
1953 const nsACString& aName) {
1954 MOZ_ASSERT(XRE_IsParentProcess());
1956 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1957 service->UnregisterProcessActor(aName);
1960 /* static */
1961 bool ChromeUtils::IsClassifierBlockingErrorCode(GlobalObject& aGlobal,
1962 uint32_t aError) {
1963 return net::UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(
1964 static_cast<nsresult>(aError));
1967 /* static */
1968 void ChromeUtils::PrivateNoteIntentionalCrash(const GlobalObject& aGlobal,
1969 ErrorResult& aError) {
1970 if (XRE_IsContentProcess()) {
1971 NoteIntentionalCrash("tab");
1972 return;
1974 aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
1977 /* static */
1978 nsIDOMProcessChild* ChromeUtils::GetDomProcessChild(const GlobalObject&) {
1979 return nsIDOMProcessChild::GetSingleton();
1982 /* static */
1983 void ChromeUtils::GetAllDOMProcesses(
1984 GlobalObject& aGlobal, nsTArray<RefPtr<nsIDOMProcessParent>>& aParents,
1985 ErrorResult& aRv) {
1986 if (!XRE_IsParentProcess()) {
1987 aRv.ThrowNotAllowedError(
1988 "getAllDOMProcesses() may only be called in the parent process");
1989 return;
1991 aParents.Clear();
1992 // Always add the parent process nsIDOMProcessParent first
1993 aParents.AppendElement(InProcessParent::Singleton());
1995 // Before adding nsIDOMProcessParent for all the content processes
1996 for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
1997 aParents.AppendElement(cp);
2001 /* static */
2002 void ChromeUtils::ConsumeInteractionData(
2003 GlobalObject& aGlobal, Record<nsString, InteractionData>& aInteractions,
2004 ErrorResult& aRv) {
2005 if (!XRE_IsParentProcess()) {
2006 aRv.ThrowNotAllowedError(
2007 "consumeInteractionData() may only be called in the parent "
2008 "process");
2009 return;
2011 EventStateManager::ConsumeInteractionData(aInteractions);
2014 already_AddRefed<Promise> ChromeUtils::CollectScrollingData(
2015 GlobalObject& aGlobal, ErrorResult& aRv) {
2016 // Creating a JS promise
2017 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
2018 MOZ_ASSERT(global);
2020 RefPtr<Promise> promise = Promise::Create(global, aRv);
2021 if (aRv.Failed()) {
2022 return nullptr;
2025 RefPtr<ScrollingMetrics::ScrollingMetricsPromise> extPromise =
2026 ScrollingMetrics::CollectScrollingMetrics();
2028 extPromise->Then(
2029 GetCurrentSerialEventTarget(), __func__,
2030 [promise](const std::tuple<uint32_t, uint32_t>& aResult) {
2031 InteractionData out = {};
2032 out.mInteractionTimeInMilliseconds = std::get<0>(aResult);
2033 out.mScrollingDistanceInPixels = std::get<1>(aResult);
2034 promise->MaybeResolve(out);
2036 [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
2038 return promise.forget();
2041 /* static */
2042 void ChromeUtils::GetFormAutofillConfidences(
2043 GlobalObject& aGlobal, const Sequence<OwningNonNull<Element>>& aElements,
2044 nsTArray<FormAutofillConfidences>& aResults, ErrorResult& aRv) {
2045 FormAutofillNative::GetFormAutofillConfidences(aGlobal, aElements, aResults,
2046 aRv);
2049 bool ChromeUtils::IsDarkBackground(GlobalObject&, Element& aElement) {
2050 nsIFrame* f = aElement.GetPrimaryFrame(FlushType::Frames);
2051 if (!f) {
2052 return false;
2054 return nsNativeTheme::IsDarkBackground(f);
2057 double ChromeUtils::DateNow(GlobalObject&) { return JS_Now() / 1000.0; }
2059 /* static */
2060 void ChromeUtils::EnsureJSOracleStarted(GlobalObject&) {
2061 if (StaticPrefs::browser_opaqueResponseBlocking_javascriptValidator()) {
2062 JSOracleParent::WithJSOracle([](JSOracleParent* aParent) {});
2066 /* static */
2067 unsigned ChromeUtils::AliveUtilityProcesses(const GlobalObject&) {
2068 const auto& utilityProcessManager =
2069 mozilla::ipc::UtilityProcessManager::GetIfExists();
2070 return utilityProcessManager ? utilityProcessManager->AliveProcesses() : 0;
2073 /* static */
2074 void ChromeUtils::GetAllPossibleUtilityActorNames(GlobalObject& aGlobal,
2075 nsTArray<nsCString>& aNames) {
2076 aNames.Clear();
2077 for (UtilityActorName idlName :
2078 MakeWebIDLEnumeratedRange<WebIDLUtilityActorName>()) {
2079 aNames.AppendElement(GetEnumString(idlName));
2083 /* static */
2084 bool ChromeUtils::ShouldResistFingerprinting(
2085 GlobalObject& aGlobal, JSRFPTarget aTarget,
2086 const Nullable<uint64_t>& aOverriddenFingerprintingSettings) {
2087 RFPTarget target;
2088 switch (aTarget) {
2089 case JSRFPTarget::RoundWindowSize:
2090 target = RFPTarget::RoundWindowSize;
2091 break;
2092 case JSRFPTarget::SiteSpecificZoom:
2093 target = RFPTarget::SiteSpecificZoom;
2094 break;
2095 default:
2096 MOZ_CRASH("Unhandled JSRFPTarget enum value");
2099 bool isPBM = false;
2100 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
2101 if (global) {
2102 nsPIDOMWindowInner* win = global->GetAsInnerWindow();
2103 if (win) {
2104 nsIDocShell* docshell = win->GetDocShell();
2105 if (docshell) {
2106 nsDocShell::Cast(docshell)->GetUsePrivateBrowsing(&isPBM);
2111 Maybe<RFPTarget> overriddenFingerprintingSettings;
2112 if (!aOverriddenFingerprintingSettings.IsNull()) {
2113 overriddenFingerprintingSettings.emplace(
2114 RFPTarget(aOverriddenFingerprintingSettings.Value()));
2117 // This global object appears to be the global window, not for individual
2118 // sites so to exempt individual sites (instead of just PBM/Not-PBM windows)
2119 // more work would be needed to get the correct context.
2120 return nsRFPService::IsRFPEnabledFor(isPBM, target,
2121 overriddenFingerprintingSettings);
2124 std::atomic<uint32_t> ChromeUtils::sDevToolsOpenedCount = 0;
2126 /* static */
2127 bool ChromeUtils::IsDevToolsOpened() {
2128 return ChromeUtils::sDevToolsOpenedCount > 0;
2131 /* static */
2132 bool ChromeUtils::IsDevToolsOpened(GlobalObject& aGlobal) {
2133 return ChromeUtils::IsDevToolsOpened();
2136 /* static */
2137 void ChromeUtils::NotifyDevToolsOpened(GlobalObject& aGlobal) {
2138 ChromeUtils::sDevToolsOpenedCount++;
2141 /* static */
2142 void ChromeUtils::NotifyDevToolsClosed(GlobalObject& aGlobal) {
2143 MOZ_ASSERT(ChromeUtils::sDevToolsOpenedCount >= 1);
2144 ChromeUtils::sDevToolsOpenedCount--;
2147 #ifdef MOZ_WMF_CDM
2148 /* static */
2149 already_AddRefed<Promise> ChromeUtils::GetWMFContentDecryptionModuleInformation(
2150 GlobalObject& aGlobal, ErrorResult& aRv) {
2151 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
2152 MOZ_ASSERT(global);
2153 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
2154 if (NS_WARN_IF(aRv.Failed())) {
2155 return nullptr;
2157 MOZ_ASSERT(domPromise);
2158 MFCDMService::GetAllKeySystemsCapabilities(domPromise);
2159 return domPromise.forget();
2161 #endif
2163 already_AddRefed<Promise> ChromeUtils::GetGMPContentDecryptionModuleInformation(
2164 GlobalObject& aGlobal, ErrorResult& aRv) {
2165 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
2166 MOZ_ASSERT(global);
2167 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
2168 if (NS_WARN_IF(aRv.Failed())) {
2169 return nullptr;
2171 MOZ_ASSERT(domPromise);
2172 KeySystemConfig::GetGMPKeySystemConfigs(domPromise);
2173 return domPromise.forget();
2176 } // namespace mozilla::dom