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/. */
8 #include "nsJSEnvironment.h"
9 #include "nsIScriptGlobalObject.h"
10 #include "nsIScriptObjectPrincipal.h"
11 #include "nsIDOMChromeWindow.h"
12 #include "nsPIDOMWindow.h"
13 #include "nsIScriptSecurityManager.h"
15 #include "nsIServiceManager.h"
16 #include "nsIXPConnect.h"
17 #include "nsIJSRuntimeService.h"
19 #include "nsISupportsPrimitives.h"
20 #include "nsReadableUtils.h"
21 #include "nsDOMJSUtils.h"
22 #include "nsJSUtils.h"
23 #include "nsIDocShell.h"
24 #include "nsIDocShellTreeItem.h"
25 #include "nsPresContext.h"
26 #include "nsIConsoleService.h"
27 #include "nsIScriptError.h"
28 #include "nsIInterfaceRequestor.h"
29 #include "nsIInterfaceRequestorUtils.h"
30 #include "nsIPrompt.h"
31 #include "nsIObserverService.h"
34 #include "nsContentUtils.h"
35 #include "mozilla/EventDispatcher.h"
36 #include "nsIContent.h"
37 #include "nsCycleCollector.h"
38 #include "nsNetUtil.h"
39 #include "nsXPCOMCIDInternal.h"
40 #include "nsIXULRuntime.h"
41 #include "nsTextFormatter.h"
42 #include "ScriptSettings.h"
44 #include "xpcpublic.h"
46 #include "js/OldDebugAPI.h"
47 #include "jswrapper.h"
49 #include "nsIObjectInputStream.h"
50 #include "nsIObjectOutputStream.h"
52 #include "WrapperFactory.h"
53 #include "nsGlobalWindow.h"
54 #include "nsScriptNameSpaceManager.h"
55 #include "StructuredCloneTags.h"
56 #include "mozilla/AutoRestore.h"
57 #include "mozilla/dom/CryptoKey.h"
58 #include "mozilla/dom/ErrorEvent.h"
59 #include "mozilla/dom/ImageDataBinding.h"
60 #include "mozilla/dom/ImageData.h"
61 #include "mozilla/dom/StructuredClone.h"
62 #include "mozilla/dom/SubtleCryptoBinding.h"
63 #include "mozilla/ipc/BackgroundUtils.h"
64 #include "mozilla/ipc/PBackgroundSharedTypes.h"
65 #include "nsAXPCNativeCallContext.h"
66 #include "mozilla/CycleCollectedJSRuntime.h"
68 #include "nsJSPrincipals.h"
71 // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
74 #include "AccessCheck.h"
77 // Force PR_LOGGING so we can get JS strict warnings even in release builds
78 #define FORCE_PR_LOG 1
83 #include "mozilla/Preferences.h"
84 #include "mozilla/Telemetry.h"
85 #include "mozilla/dom/BindingUtils.h"
86 #include "mozilla/Attributes.h"
87 #include "mozilla/dom/asmjscache/AsmJSCache.h"
88 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
89 #include "mozilla/CycleCollectedJSRuntime.h"
90 #include "mozilla/ContentEvents.h"
92 #include "nsCycleCollectionNoteRootCallback.h"
93 #include "GeckoProfiler.h"
95 using namespace mozilla
;
96 using namespace mozilla::dom
;
98 const size_t gStackSize
= 8192;
101 static PRLogModuleInfo
* gJSDiagnostics
;
104 // Thank you Microsoft!
109 #define NS_SHRINK_GC_BUFFERS_DELAY 4000 // ms
111 // The amount of time we wait from the first request to GC to actually
112 // doing the first GC.
113 #define NS_FIRST_GC_DELAY 10000 // ms
115 #define NS_FULL_GC_DELAY 60000 // ms
117 // Maximum amount of time that should elapse between incremental GC slices
118 #define NS_INTERSLICE_GC_DELAY 100 // ms
120 // If we haven't painted in 100ms, we allow for a longer GC budget
121 #define NS_INTERSLICE_GC_BUDGET 40 // ms
123 // The amount of time we wait between a request to CC (after GC ran)
124 // and doing the actual CC.
125 #define NS_CC_DELAY 6000 // ms
127 #define NS_CC_SKIPPABLE_DELAY 400 // ms
129 // Maximum amount of time that should elapse between incremental CC slices
130 static const int64_t kICCIntersliceDelay
= 32; // ms
132 // Time budget for an incremental CC slice
133 static const int64_t kICCSliceBudget
= 10; // ms
135 // Maximum total duration for an ICC
136 static const uint32_t kMaxICCDuration
= 2000; // ms
138 // Force a CC after this long if there's more than NS_CC_FORCED_PURPLE_LIMIT
139 // objects in the purple buffer.
140 #define NS_CC_FORCED (2 * 60 * PR_USEC_PER_SEC) // 2 min
141 #define NS_CC_FORCED_PURPLE_LIMIT 10
143 // Don't allow an incremental GC to lock out the CC for too long.
144 #define NS_MAX_CC_LOCKEDOUT_TIME (15 * PR_USEC_PER_SEC) // 15 seconds
146 // Trigger a CC if the purple buffer exceeds this size when we check it.
147 #define NS_CC_PURPLE_LIMIT 200
149 #define JAVASCRIPT nsIProgrammingLanguage::JAVASCRIPT
151 // Large value used to specify that a script should run essentially forever
152 #define NS_UNLIMITED_SCRIPT_RUNTIME (0x40000000LL << 32)
154 #define NS_MAJOR_FORGET_SKIPPABLE_CALLS 2
156 // if you add statics here, add them to the list in StartupJSEnvironment
158 static nsITimer
*sGCTimer
;
159 static nsITimer
*sShrinkGCBuffersTimer
;
160 static nsITimer
*sCCTimer
;
161 static nsITimer
*sICCTimer
;
162 static nsITimer
*sFullGCTimer
;
163 static nsITimer
*sInterSliceGCTimer
;
165 static TimeStamp sLastCCEndTime
;
167 static bool sCCLockedOut
;
168 static PRTime sCCLockedOutTime
;
170 static JS::GCSliceCallback sPrevGCSliceCallback
;
172 static bool sHasRunGC
;
174 // The number of currently pending document loads. This count isn't
175 // guaranteed to always reflect reality and can't easily as we don't
176 // have an easy place to know when a load ends or is interrupted in
177 // all cases. This counter also gets reset if we end up GC'ing while
178 // we're waiting for a slow page to load. IOW, this count may be 0
179 // even when there are pending loads.
180 static uint32_t sPendingLoadCount
;
181 static bool sLoadingInProgress
;
183 static uint32_t sCCollectedWaitingForGC
;
184 static uint32_t sLikelyShortLivingObjectsNeedingGC
;
185 static bool sPostGCEventsToConsole
;
186 static bool sPostGCEventsToObserver
;
187 static int32_t sCCTimerFireCount
= 0;
188 static uint32_t sMinForgetSkippableTime
= UINT32_MAX
;
189 static uint32_t sMaxForgetSkippableTime
= 0;
190 static uint32_t sTotalForgetSkippableTime
= 0;
191 static uint32_t sRemovedPurples
= 0;
192 static uint32_t sForgetSkippableBeforeCC
= 0;
193 static uint32_t sPreviousSuspectedCount
= 0;
194 static uint32_t sCleanupsSinceLastGC
= UINT32_MAX
;
195 static bool sNeedsFullCC
= false;
196 static bool sNeedsGCAfterCC
= false;
197 static bool sIncrementalCC
= false;
199 static nsScriptNameSpaceManager
*gNameSpaceManager
;
201 static nsIJSRuntimeService
*sRuntimeService
;
203 static const char kJSRuntimeServiceContractID
[] =
204 "@mozilla.org/js/xpc/RuntimeService;1";
206 static PRTime sFirstCollectionTime
;
208 static JSRuntime
*sRuntime
;
210 static bool sIsInitialized
;
211 static bool sDidShutdown
;
212 static bool sShuttingDown
;
213 static int32_t sContextCount
;
215 static nsIScriptSecurityManager
*sSecurityManager
;
217 // nsJSEnvironmentObserver observes the memory-pressure notifications
218 // and forces a garbage collection and cycle collection when it happens, if
219 // the appropriate pref is set.
221 static bool sGCOnMemoryPressure
;
223 // In testing, we call RunNextCollectorTimer() to ensure that the collectors are run more
224 // aggressively than they would be in regular browsing. sExpensiveCollectorPokes keeps
225 // us from triggering expensive full collections too frequently.
226 static int32_t sExpensiveCollectorPokes
= 0;
227 static const int32_t kPokesBetweenExpensiveCollectorTriggers
= 5;
230 GetCollectionTimeDelta()
232 PRTime now
= PR_Now();
233 if (sFirstCollectionTime
) {
234 return now
- sFirstCollectionTime
;
236 sFirstCollectionTime
= now
;
243 nsJSContext::KillGCTimer();
244 nsJSContext::KillShrinkGCBuffersTimer();
245 nsJSContext::KillCCTimer();
246 nsJSContext::KillICCTimer();
247 nsJSContext::KillFullGCTimer();
248 nsJSContext::KillInterSliceGCTimer();
251 // If we collected a substantial amount of cycles, poke the GC since more objects
252 // might be unreachable now.
256 return sCCollectedWaitingForGC
> 250 ||
257 sLikelyShortLivingObjectsNeedingGC
> 2500 ||
261 class nsJSEnvironmentObserver MOZ_FINAL
: public nsIObserver
263 ~nsJSEnvironmentObserver() {}
269 NS_IMPL_ISUPPORTS(nsJSEnvironmentObserver
, nsIObserver
)
272 nsJSEnvironmentObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
273 const char16_t
* aData
)
275 if (sGCOnMemoryPressure
&& !nsCRT::strcmp(aTopic
, "memory-pressure")) {
276 if(StringBeginsWith(nsDependentString(aData
),
277 NS_LITERAL_STRING("low-memory-ongoing"))) {
278 // Don't GC/CC if we are in an ongoing low-memory state since its very
279 // slow and it likely won't help us anyway.
282 nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE
,
283 nsJSContext::NonIncrementalGC
,
284 nsJSContext::ShrinkingGC
);
285 nsJSContext::CycleCollectNow();
286 if (NeedsGCAfterCC()) {
287 nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE
,
288 nsJSContext::NonIncrementalGC
,
289 nsJSContext::ShrinkingGC
);
291 } else if (!nsCRT::strcmp(aTopic
, "quit-application")) {
292 sShuttingDown
= true;
299 /****************************************************************
300 ************************** AutoFree ****************************
301 ****************************************************************/
305 explicit AutoFree(void* aPtr
) : mPtr(aPtr
) {
309 nsMemory::Free(mPtr
);
318 // A utility function for script languages to call. Although it looks small,
319 // the use of nsIDocShell and nsPresContext triggers a huge number of
320 // dependencies that most languages would not otherwise need.
321 // XXXmarkh - This function is mis-placed!
323 NS_HandleScriptError(nsIScriptGlobalObject
*aScriptGlobal
,
324 const ErrorEventInit
&aErrorEventInit
,
325 nsEventStatus
*aStatus
)
328 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(aScriptGlobal
));
329 nsIDocShell
*docShell
= win
? win
->GetDocShell() : nullptr;
331 nsRefPtr
<nsPresContext
> presContext
;
332 docShell
->GetPresContext(getter_AddRefs(presContext
));
334 static int32_t errorDepth
; // Recursion prevention
337 if (errorDepth
< 2) {
338 // Dispatch() must be synchronous for the recursion block
339 // (errorDepth) to work.
340 nsRefPtr
<ErrorEvent
> event
=
341 ErrorEvent::Constructor(static_cast<nsGlobalWindow
*>(win
.get()),
342 NS_LITERAL_STRING("error"),
344 event
->SetTrusted(true);
346 EventDispatcher::DispatchDOMEvent(win
, nullptr, event
, presContext
,
358 AsyncErrorReporter::AsyncErrorReporter(JSRuntime
* aRuntime
,
359 JSErrorReport
* aErrorReport
,
360 const char* aFallbackMessage
,
362 nsPIDOMWindow
* aWindow
)
363 : mSourceLine(static_cast<const char16_t
*>(aErrorReport
->uclinebuf
))
364 , mLineNumber(aErrorReport
->lineno
)
365 , mColumn(aErrorReport
->column
)
366 , mFlags(aErrorReport
->flags
)
368 if (!aErrorReport
->filename
) {
369 mFileName
.SetIsVoid(true);
371 mFileName
.AssignWithConversion(aErrorReport
->filename
);
374 const char16_t
* m
= static_cast<const char16_t
*>(aErrorReport
->ucmessage
);
376 JSFlatString
* name
= js::GetErrorTypeName(aRuntime
, aErrorReport
->exnType
);
378 AssignJSFlatString(mErrorMsg
, name
);
379 mErrorMsg
.AppendLiteral(": ");
384 if (mErrorMsg
.IsEmpty() && aFallbackMessage
) {
385 mErrorMsg
.AssignWithConversion(aFallbackMessage
);
388 mCategory
= aIsChromeError
? NS_LITERAL_CSTRING("chrome javascript") :
389 NS_LITERAL_CSTRING("content javascript");
393 MOZ_ASSERT(aWindow
->IsInnerWindow());
394 mInnerWindowID
= aWindow
->WindowID();
399 AsyncErrorReporter::ReportError()
401 nsCOMPtr
<nsIScriptError
> errorObject
=
402 do_CreateInstance("@mozilla.org/scripterror;1");
407 nsresult rv
= errorObject
->InitWithWindowID(mErrorMsg
, mFileName
,
408 mSourceLine
, mLineNumber
,
409 mColumn
, mFlags
, mCategory
,
415 nsCOMPtr
<nsIConsoleService
> consoleService
=
416 do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
417 if (!consoleService
) {
421 consoleService
->LogMessage(errorObject
);
426 } // namespace mozilla
428 class ScriptErrorEvent
: public AsyncErrorReporter
431 ScriptErrorEvent(JSRuntime
* aRuntime
,
432 JSErrorReport
* aErrorReport
,
433 const char* aFallbackMessage
,
434 nsIPrincipal
* aScriptOriginPrincipal
,
435 nsIPrincipal
* aGlobalPrincipal
,
436 nsPIDOMWindow
* aWindow
,
437 JS::Handle
<JS::Value
> aError
,
439 // Pass an empty category, then compute ours
440 : AsyncErrorReporter(aRuntime
, aErrorReport
, aFallbackMessage
,
441 nsContentUtils::IsSystemPrincipal(aGlobalPrincipal
),
443 , mOriginPrincipal(aScriptOriginPrincipal
)
444 , mDispatchEvent(aDispatchEvent
)
445 , mError(aRuntime
, aError
)
448 MOZ_ASSERT_IF(mWindow
, mWindow
->IsInnerWindow());
453 nsEventStatus status
= nsEventStatus_eIgnore
;
454 // First, notify the DOM that we have a script error, but only if
455 // our window is still the current inner, if we're associated with a window.
456 if (mDispatchEvent
&& (!mWindow
|| mWindow
->IsCurrentInnerWindow())) {
457 nsIDocShell
* docShell
= mWindow
? mWindow
->GetDocShell() : nullptr;
459 !JSREPORT_IS_WARNING(mFlags
) &&
460 !sHandlingScriptError
) {
461 AutoRestore
<bool> recursionGuard(sHandlingScriptError
);
462 sHandlingScriptError
= true;
464 nsRefPtr
<nsPresContext
> presContext
;
465 docShell
->GetPresContext(getter_AddRefs(presContext
));
467 ThreadsafeAutoJSContext cx
;
468 RootedDictionary
<ErrorEventInit
> init(cx
);
469 init
.mCancelable
= true;
470 init
.mFilename
= mFileName
;
471 init
.mBubbles
= true;
473 nsCOMPtr
<nsIScriptObjectPrincipal
> sop(do_QueryInterface(mWindow
));
474 NS_ENSURE_STATE(sop
);
475 nsIPrincipal
* p
= sop
->GetPrincipal();
478 bool sameOrigin
= !mOriginPrincipal
;
480 if (p
&& !sameOrigin
) {
481 if (NS_FAILED(p
->Subsumes(mOriginPrincipal
, &sameOrigin
))) {
486 NS_NAMED_LITERAL_STRING(xoriginMsg
, "Script error.");
488 init
.mMessage
= mErrorMsg
;
489 init
.mLineno
= mLineNumber
;
490 init
.mColno
= mColumn
;
491 init
.mError
= mError
;
493 NS_WARNING("Not same origin error!");
494 init
.mMessage
= xoriginMsg
;
498 nsRefPtr
<ErrorEvent
> event
=
499 ErrorEvent::Constructor(static_cast<nsGlobalWindow
*>(mWindow
.get()),
500 NS_LITERAL_STRING("error"), init
);
501 event
->SetTrusted(true);
503 EventDispatcher::DispatchDOMEvent(mWindow
, nullptr, event
, presContext
,
508 if (status
!= nsEventStatus_eConsumeNoDefault
) {
509 AsyncErrorReporter::ReportError();
516 nsCOMPtr
<nsIPrincipal
> mOriginPrincipal
;
518 JS::PersistentRootedValue mError
;
519 nsCOMPtr
<nsPIDOMWindow
> mWindow
;
521 static bool sHandlingScriptError
;
524 bool ScriptErrorEvent::sHandlingScriptError
= false;
526 // NOTE: This function could be refactored to use the above. The only reason
527 // it has not been done is that the code below only fills the error event
528 // after it has a good nsPresContext - whereas using the above function
529 // would involve always filling it. Is that a concern?
531 NS_ScriptErrorReporter(JSContext
*cx
,
533 JSErrorReport
*report
)
535 // We don't want to report exceptions too eagerly, but warnings in the
536 // absence of werror are swallowed whole, so report those now.
537 if (!JSREPORT_IS_WARNING(report
->flags
)) {
538 nsIXPConnect
* xpc
= nsContentUtils::XPConnect();
539 if (JS::DescribeScriptedCaller(cx
)) {
540 xpc
->MarkErrorUnreported(cx
);
545 nsAXPCNativeCallContext
*cc
= nullptr;
546 xpc
->GetCurrentNativeCallContext(&cc
);
548 nsAXPCNativeCallContext
*prev
= cc
;
549 while (NS_SUCCEEDED(prev
->GetPreviousCallContext(&prev
)) && prev
) {
551 if (NS_SUCCEEDED(prev
->GetLanguage(&lang
)) &&
552 lang
== nsAXPCNativeCallContext::LANG_JS
) {
553 xpc
->MarkErrorUnreported(cx
);
561 JS::Rooted
<JS::Value
> exception(cx
);
562 ::JS_GetPendingException(cx
, &exception
);
564 // Note: we must do this before running any more code on cx.
565 ::JS_ClearPendingException(cx
);
567 MOZ_ASSERT(cx
== nsContentUtils::GetCurrentJSContext());
568 nsCOMPtr
<nsIGlobalObject
> globalObject
;
569 if (nsIScriptContext
* scx
= GetScriptContextFromJSContext(cx
)) {
570 nsCOMPtr
<nsPIDOMWindow
> outer
= do_QueryInterface(scx
->GetGlobalObject());
572 globalObject
= static_cast<nsGlobalWindow
*>(outer
->GetCurrentInnerWindow());
577 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(globalObject
);
578 MOZ_ASSERT_IF(win
, win
->IsInnerWindow());
579 nsCOMPtr
<nsIScriptObjectPrincipal
> scriptPrincipal
=
580 do_QueryInterface(globalObject
);
581 NS_ASSERTION(scriptPrincipal
, "Global objects must implement "
582 "nsIScriptObjectPrincipal");
583 nsContentUtils::AddScriptRunner(
584 new ScriptErrorEvent(JS_GetRuntime(cx
),
587 nsJSPrincipals::get(report
->originPrincipals
),
588 scriptPrincipal
->GetPrincipal(),
591 /* We do not try to report Out Of Memory via a dom
592 * event because the dom event handler would
593 * encounter an OOM exception trying to process the
594 * event, and then we'd need to generate a new OOM
595 * event for that new OOM instance -- this isn't
598 report
->errorNumber
!= JSMSG_OUT_OF_MEMORY
));
601 if (nsContentUtils::DOMWindowDumpEnabled()) {
602 // Print it to stderr as well, for the benefit of those invoking
603 // mozilla with -console.
605 error
.AssignLiteral("JavaScript ");
606 if (JSREPORT_IS_STRICT(report
->flags
))
607 error
.AppendLiteral("strict ");
608 if (JSREPORT_IS_WARNING(report
->flags
))
609 error
.AppendLiteral("warning: ");
611 error
.AppendLiteral("error: ");
612 error
.Append(report
->filename
);
613 error
.AppendLiteral(", line ");
614 error
.AppendInt(report
->lineno
, 10);
615 error
.AppendLiteral(": ");
616 if (report
->ucmessage
) {
617 AppendUTF16toUTF8(reinterpret_cast<const char16_t
*>(report
->ucmessage
),
620 error
.Append(message
);
623 fprintf(stderr
, "%s\n", error
.get());
629 gJSDiagnostics
= PR_NewLogModule("JSDiagnostics");
631 if (gJSDiagnostics
) {
632 PR_LOG(gJSDiagnostics
,
633 JSREPORT_IS_WARNING(report
->flags
) ? PR_LOG_WARNING
: PR_LOG_ERROR
,
634 ("file %s, line %u: %s\n%s%s",
635 report
->filename
, report
->lineno
, message
,
636 report
->linebuf
? report
->linebuf
: "",
638 report
->linebuf
[strlen(report
->linebuf
)-1] != '\n')
646 // A couple of useful functions to call when you're debugging.
648 JSObject2Win(JSObject
*obj
)
650 return xpc::WindowOrNull(obj
);
654 PrintWinURI(nsGlobalWindow
*win
)
657 printf("No window passed in.\n");
661 nsCOMPtr
<nsIDocument
> doc
= win
->GetExtantDoc();
663 printf("No document in the window.\n");
667 nsIURI
*uri
= doc
->GetDocumentURI();
669 printf("Document doesn't have a URI.\n");
675 printf("%s\n", spec
.get());
679 PrintWinCodebase(nsGlobalWindow
*win
)
682 printf("No window passed in.\n");
686 nsIPrincipal
*prin
= win
->GetPrincipal();
688 printf("Window doesn't have principals.\n");
692 nsCOMPtr
<nsIURI
> uri
;
693 prin
->GetURI(getter_AddRefs(uri
));
695 printf("No URI, maybe the system principal.\n");
701 printf("%s\n", spec
.get());
705 DumpString(const nsAString
&str
)
707 printf("%s\n", NS_ConvertUTF16toUTF8(str
).get());
711 #define JS_OPTIONS_DOT_STR "javascript.options."
713 static const char js_options_dot_str
[] = JS_OPTIONS_DOT_STR
;
715 static const char js_zeal_option_str
[] = JS_OPTIONS_DOT_STR
"gczeal";
716 static const char js_zeal_frequency_str
[] = JS_OPTIONS_DOT_STR
"gczeal.frequency";
718 static const char js_memlog_option_str
[] = JS_OPTIONS_DOT_STR
"mem.log";
719 static const char js_memnotify_option_str
[] = JS_OPTIONS_DOT_STR
"mem.notify";
722 nsJSContext::JSOptionChangedCallback(const char *pref
, void *data
)
724 sPostGCEventsToConsole
= Preferences::GetBool(js_memlog_option_str
);
725 sPostGCEventsToObserver
= Preferences::GetBool(js_memnotify_option_str
);
728 nsJSContext
*context
= reinterpret_cast<nsJSContext
*>(data
);
729 int32_t zeal
= Preferences::GetInt(js_zeal_option_str
, -1);
730 int32_t frequency
= Preferences::GetInt(js_zeal_frequency_str
, JS_DEFAULT_ZEAL_FREQ
);
732 ::JS_SetGCZeal(context
->mContext
, (uint8_t)zeal
, frequency
);
736 nsJSContext::nsJSContext(bool aGCOnDestruction
,
737 nsIScriptGlobalObject
* aGlobalObject
)
738 : mWindowProxy(nullptr)
739 , mGCOnDestruction(aGCOnDestruction
)
740 , mGlobalObjectRef(aGlobalObject
)
746 mContext
= ::JS_NewContext(sRuntime
, gStackSize
);
748 ::JS_SetContextPrivate(mContext
, static_cast<nsIScriptContext
*>(this));
750 // Make sure the new context gets the default context options
751 JS::ContextOptionsRef(mContext
).setPrivateIsNSISupports(true);
753 // Watch for the JS boolean options
754 Preferences::RegisterCallback(JSOptionChangedCallback
,
755 js_options_dot_str
, this);
757 mIsInitialized
= false;
758 mProcessingScriptTag
= false;
762 nsJSContext::~nsJSContext()
764 mGlobalObjectRef
= nullptr;
770 if (!sContextCount
&& sDidShutdown
) {
771 // The last context is being deleted, and we're already in the
772 // process of shutting down, release the JS runtime service, and
773 // the security manager.
775 NS_IF_RELEASE(sRuntimeService
);
776 NS_IF_RELEASE(sSecurityManager
);
780 // This function is called either by the destructor or unlink, which means that
781 // it can never be called when there is an outstanding ref to the
782 // nsIScriptContext on the stack. Our stack-scoped cx pushers hold such a ref,
783 // so we can assume here that mContext is not on the stack (and therefore not
786 nsJSContext::DestroyJSContext()
792 // Clear our entry in the JSContext, bugzilla bug 66413
793 ::JS_SetContextPrivate(mContext
, nullptr);
795 // Unregister our "javascript.options.*" pref-changed callback.
796 Preferences::UnregisterCallback(JSOptionChangedCallback
,
797 js_options_dot_str
, this);
799 if (mGCOnDestruction
) {
800 PokeGC(JS::gcreason::NSJSCONTEXT_DESTROY
);
803 JS_DestroyContextNoGC(mContext
);
808 // QueryInterface implementation for nsJSContext
809 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSContext
)
811 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSContext
)
812 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mWindowProxy
)
813 NS_IMPL_CYCLE_COLLECTION_TRACE_END
815 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSContext
)
816 NS_ASSERTION(!tmp
->mContext
|| !js::ContextHasOutstandingRequests(tmp
->mContext
),
817 "Trying to unlink a context with outstanding requests.");
818 tmp
->mIsInitialized
= false;
819 tmp
->mGCOnDestruction
= false;
820 tmp
->mWindowProxy
= nullptr;
821 tmp
->DestroyJSContext();
822 NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobalObjectRef
)
823 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
824 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSContext
)
825 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSContext
, tmp
->GetCCRefcnt())
826 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobalObjectRef
)
827 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
828 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
830 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext
)
831 NS_INTERFACE_MAP_ENTRY(nsIScriptContext
)
832 NS_INTERFACE_MAP_ENTRY(nsISupports
)
836 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSContext
)
837 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSContext
)
840 nsJSContext::GetCCRefcnt()
842 nsrefcnt refcnt
= mRefCnt
.get();
844 // In the (abnormal) case of synchronous cycle-collection, the context may be
845 // actively running JS code in which case we must keep it alive by adding an
847 if (mContext
&& js::ContextHasOutstandingRequests(mContext
)) {
856 AtomIsEventHandlerName(nsIAtom
*aName
)
858 const char16_t
*name
= aName
->GetUTF16String();
862 for (cp
= name
; *cp
!= '\0'; ++cp
)
865 if ((c
< 'A' || c
> 'Z') && (c
< 'a' || c
> 'z'))
873 nsIScriptGlobalObject
*
874 nsJSContext::GetGlobalObject()
876 // Note: this could probably be simplified somewhat more; see bug 974327
882 MOZ_ASSERT(mGlobalObjectRef
);
883 return mGlobalObjectRef
;
887 nsJSContext::GetNativeContext()
893 nsJSContext::InitContext()
895 // Make sure callers of this use
896 // WillInitializeContext/DidInitializeContext around this call.
897 NS_ENSURE_TRUE(!mIsInitialized
, NS_ERROR_ALREADY_INITIALIZED
);
900 return NS_ERROR_OUT_OF_MEMORY
;
902 ::JS_SetErrorReporter(mContext
, NS_ScriptErrorReporter
);
904 JSOptionChangedCallback(js_options_dot_str
, this);
910 nsJSContext::SetProperty(JS::Handle
<JSObject
*> aTarget
, const char* aPropName
, nsISupports
* aArgs
)
913 if (NS_WARN_IF(!jsapi
.InitWithLegacyErrorReporting(GetGlobalObject()))) {
914 return NS_ERROR_FAILURE
;
916 MOZ_ASSERT(jsapi
.cx() == mContext
,
917 "AutoJSAPI should have found our own JSContext*");
919 JS::AutoValueVector
args(mContext
);
921 JS::Rooted
<JSObject
*> global(mContext
, GetWindowProxy());
923 ConvertSupportsTojsvals(aArgs
, global
, args
);
924 NS_ENSURE_SUCCESS(rv
, rv
);
926 // got the arguments, now attach them.
928 for (uint32_t i
= 0; i
< args
.length(); ++i
) {
929 if (!JS_WrapValue(mContext
, args
[i
])) {
930 return NS_ERROR_FAILURE
;
934 JS::Rooted
<JSObject
*> array(mContext
, ::JS_NewArrayObject(mContext
, args
));
936 return NS_ERROR_FAILURE
;
939 return JS_DefineProperty(mContext
, aTarget
, aPropName
, array
, 0) ? NS_OK
: NS_ERROR_FAILURE
;
943 nsJSContext::ConvertSupportsTojsvals(nsISupports
* aArgs
,
944 JS::Handle
<JSObject
*> aScope
,
945 JS::AutoValueVector
& aArgsOut
)
949 // If the array implements nsIJSArgArray, copy the contents and return.
950 nsCOMPtr
<nsIJSArgArray
> fastArray
= do_QueryInterface(aArgs
);
954 rv
= fastArray
->GetArgs(&argc
, reinterpret_cast<void **>(&argv
));
955 if (NS_SUCCEEDED(rv
) && !aArgsOut
.append(argv
, argc
)) {
956 rv
= NS_ERROR_OUT_OF_MEMORY
;
961 // Take the slower path converting each item.
962 // Handle only nsIArray and nsIVariant. nsIArray is only needed for
963 // SetProperty('arguments', ...);
965 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
966 NS_ENSURE_TRUE(xpc
, NS_ERROR_UNEXPECTED
);
972 // This general purpose function may need to convert an arg array
973 // (window.arguments, event-handler args) and a generic property.
974 nsCOMPtr
<nsIArray
> argsArray(do_QueryInterface(aArgs
));
977 rv
= argsArray
->GetLength(&argCount
);
978 NS_ENSURE_SUCCESS(rv
, rv
);
982 argCount
= 1; // the nsISupports which is not an array
985 // Use the caller's auto guards to release and unroot.
986 if (!aArgsOut
.resize(argCount
)) {
987 return NS_ERROR_OUT_OF_MEMORY
;
991 for (uint32_t argCtr
= 0; argCtr
< argCount
&& NS_SUCCEEDED(rv
); argCtr
++) {
992 nsCOMPtr
<nsISupports
> arg
;
993 JS::MutableHandle
<JS::Value
> thisVal
= aArgsOut
[argCtr
];
994 argsArray
->QueryElementAt(argCtr
, NS_GET_IID(nsISupports
),
995 getter_AddRefs(arg
));
1000 nsCOMPtr
<nsIVariant
> variant(do_QueryInterface(arg
));
1001 if (variant
!= nullptr) {
1002 rv
= xpc
->VariantToJS(cx
, aScope
, variant
, thisVal
);
1004 // And finally, support the nsISupportsPrimitives supplied
1005 // by the AppShell. It generally will pass only strings, but
1006 // as we have code for handling all, we may as well use it.
1007 rv
= AddSupportsPrimitiveTojsvals(arg
, thisVal
.address());
1008 if (rv
== NS_ERROR_NO_INTERFACE
) {
1009 // something else - probably an event object or similar -
1012 // but first, check its not another nsISupportsPrimitive, as
1013 // these are now deprecated for use with script contexts.
1014 nsCOMPtr
<nsISupportsPrimitive
> prim(do_QueryInterface(arg
));
1015 NS_ASSERTION(prim
== nullptr,
1016 "Don't pass nsISupportsPrimitives - use nsIVariant!");
1018 JSAutoCompartment
ac(cx
, aScope
);
1019 rv
= nsContentUtils::WrapNative(cx
, arg
, thisVal
);
1024 nsCOMPtr
<nsIVariant
> variant
= do_QueryInterface(aArgs
);
1026 rv
= xpc
->VariantToJS(cx
, aScope
, variant
, aArgsOut
[0]);
1028 NS_ERROR("Not an array, not an interface?");
1029 rv
= NS_ERROR_UNEXPECTED
;
1035 // This really should go into xpconnect somewhere...
1037 nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports
*aArg
, JS::Value
*aArgv
)
1039 NS_PRECONDITION(aArg
, "Empty arg");
1041 nsCOMPtr
<nsISupportsPrimitive
> argPrimitive(do_QueryInterface(aArg
));
1043 return NS_ERROR_NO_INTERFACE
;
1047 argPrimitive
->GetType(&type
);
1050 case nsISupportsPrimitive::TYPE_CSTRING
: {
1051 nsCOMPtr
<nsISupportsCString
> p(do_QueryInterface(argPrimitive
));
1052 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1059 JSString
*str
= ::JS_NewStringCopyN(cx
, data
.get(), data
.Length());
1060 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
1062 *aArgv
= STRING_TO_JSVAL(str
);
1066 case nsISupportsPrimitive::TYPE_STRING
: {
1067 nsCOMPtr
<nsISupportsString
> p(do_QueryInterface(argPrimitive
));
1068 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1074 // cast is probably safe since wchar_t and jschar are expected
1075 // to be equivalent; both unsigned 16-bit entities
1077 ::JS_NewUCStringCopyN(cx
, data
.get(), data
.Length());
1078 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
1080 *aArgv
= STRING_TO_JSVAL(str
);
1083 case nsISupportsPrimitive::TYPE_PRBOOL
: {
1084 nsCOMPtr
<nsISupportsPRBool
> p(do_QueryInterface(argPrimitive
));
1085 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1091 *aArgv
= BOOLEAN_TO_JSVAL(data
);
1095 case nsISupportsPrimitive::TYPE_PRUINT8
: {
1096 nsCOMPtr
<nsISupportsPRUint8
> p(do_QueryInterface(argPrimitive
));
1097 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1103 *aArgv
= INT_TO_JSVAL(data
);
1107 case nsISupportsPrimitive::TYPE_PRUINT16
: {
1108 nsCOMPtr
<nsISupportsPRUint16
> p(do_QueryInterface(argPrimitive
));
1109 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1115 *aArgv
= INT_TO_JSVAL(data
);
1119 case nsISupportsPrimitive::TYPE_PRUINT32
: {
1120 nsCOMPtr
<nsISupportsPRUint32
> p(do_QueryInterface(argPrimitive
));
1121 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1127 *aArgv
= INT_TO_JSVAL(data
);
1131 case nsISupportsPrimitive::TYPE_CHAR
: {
1132 nsCOMPtr
<nsISupportsChar
> p(do_QueryInterface(argPrimitive
));
1133 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1139 JSString
*str
= ::JS_NewStringCopyN(cx
, &data
, 1);
1140 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
1142 *aArgv
= STRING_TO_JSVAL(str
);
1146 case nsISupportsPrimitive::TYPE_PRINT16
: {
1147 nsCOMPtr
<nsISupportsPRInt16
> p(do_QueryInterface(argPrimitive
));
1148 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1154 *aArgv
= INT_TO_JSVAL(data
);
1158 case nsISupportsPrimitive::TYPE_PRINT32
: {
1159 nsCOMPtr
<nsISupportsPRInt32
> p(do_QueryInterface(argPrimitive
));
1160 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1166 *aArgv
= INT_TO_JSVAL(data
);
1170 case nsISupportsPrimitive::TYPE_FLOAT
: {
1171 nsCOMPtr
<nsISupportsFloat
> p(do_QueryInterface(argPrimitive
));
1172 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1178 *aArgv
= ::JS_NumberValue(data
);
1182 case nsISupportsPrimitive::TYPE_DOUBLE
: {
1183 nsCOMPtr
<nsISupportsDouble
> p(do_QueryInterface(argPrimitive
));
1184 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1190 *aArgv
= ::JS_NumberValue(data
);
1194 case nsISupportsPrimitive::TYPE_INTERFACE_POINTER
: {
1195 nsCOMPtr
<nsISupportsInterfacePointer
> p(do_QueryInterface(argPrimitive
));
1196 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1198 nsCOMPtr
<nsISupports
> data
;
1199 nsIID
*iid
= nullptr;
1201 p
->GetData(getter_AddRefs(data
));
1202 p
->GetDataIID(&iid
);
1203 NS_ENSURE_TRUE(iid
, NS_ERROR_UNEXPECTED
);
1205 AutoFree
iidGuard(iid
); // Free iid upon destruction.
1207 JS::Rooted
<JSObject
*> scope(cx
, GetWindowProxy());
1208 JS::Rooted
<JS::Value
> v(cx
);
1209 JSAutoCompartment
ac(cx
, scope
);
1210 nsresult rv
= nsContentUtils::WrapNative(cx
, data
, iid
, &v
);
1211 NS_ENSURE_SUCCESS(rv
, rv
);
1217 case nsISupportsPrimitive::TYPE_ID
:
1218 case nsISupportsPrimitive::TYPE_PRUINT64
:
1219 case nsISupportsPrimitive::TYPE_PRINT64
:
1220 case nsISupportsPrimitive::TYPE_PRTIME
:
1221 case nsISupportsPrimitive::TYPE_VOID
: {
1222 NS_WARNING("Unsupported primitive type used");
1223 *aArgv
= JSVAL_NULL
;
1227 NS_WARNING("Unknown primitive type used");
1228 *aArgv
= JSVAL_NULL
;
1235 #ifdef NS_TRACE_MALLOC
1237 #include <errno.h> // XXX assume Linux if NS_TRACE_MALLOC
1245 #include "nsTraceMalloc.h"
1248 CheckUniversalXPConnectForTraceMalloc(JSContext
*cx
)
1250 if (nsContentUtils::IsCallerChrome())
1252 JS_ReportError(cx
, "trace-malloc functions require UniversalXPConnect");
1257 TraceMallocDisable(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1259 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
1261 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1264 NS_TraceMallocDisable();
1265 args
.rval().setUndefined();
1270 TraceMallocEnable(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1272 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
1274 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1277 NS_TraceMallocEnable();
1278 args
.rval().setUndefined();
1283 TraceMallocOpenLogFile(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1285 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
1287 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1294 JSString
*str
= JS::ToString(cx
, args
[0]);
1297 JSAutoByteString
filename(cx
, str
);
1300 fd
= open(filename
.ptr(), O_CREAT
| O_WRONLY
| O_TRUNC
, 0644);
1302 JS_ReportError(cx
, "can't open %s: %s", filename
.ptr(), strerror(errno
));
1306 args
.rval().setInt32(fd
);
1311 TraceMallocChangeLogFD(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1313 JS::CallArgs args
= CallArgsFromVp(argc
, vp
);
1315 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1319 if (args
.length() == 0) {
1322 if (!JS::ToInt32(cx
, args
[0], &fd
))
1324 oldfd
= NS_TraceMallocChangeLogFD(fd
);
1326 JS_ReportOutOfMemory(cx
);
1330 args
.rval().setInt32(oldfd
);
1335 TraceMallocCloseLogFD(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1337 JS::CallArgs args
= CallArgsFromVp(argc
, vp
);
1339 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1343 if (args
.length() == 0) {
1344 args
.rval().setUndefined();
1347 if (!JS::ToInt32(cx
, args
[0], &fd
))
1349 NS_TraceMallocCloseLogFD((int) fd
);
1350 args
.rval().setInt32(fd
);
1355 TraceMallocLogTimestamp(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1357 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
1358 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1361 JSString
*str
= JS::ToString(cx
, args
.get(0));
1364 JSAutoByteString
caption(cx
, str
);
1367 NS_TraceMallocLogTimestamp(caption
.ptr());
1368 args
.rval().setUndefined();
1373 TraceMallocDumpAllocations(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1375 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
1376 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1379 JSString
*str
= JS::ToString(cx
, args
.get(0));
1382 JSAutoByteString
pathname(cx
, str
);
1385 if (NS_TraceMallocDumpAllocations(pathname
.ptr()) < 0) {
1386 JS_ReportError(cx
, "can't dump to %s: %s", pathname
.ptr(), strerror(errno
));
1389 args
.rval().setUndefined();
1393 static const JSFunctionSpec TraceMallocFunctions
[] = {
1394 JS_FS("TraceMallocDisable", TraceMallocDisable
, 0, 0),
1395 JS_FS("TraceMallocEnable", TraceMallocEnable
, 0, 0),
1396 JS_FS("TraceMallocOpenLogFile", TraceMallocOpenLogFile
, 1, 0),
1397 JS_FS("TraceMallocChangeLogFD", TraceMallocChangeLogFD
, 1, 0),
1398 JS_FS("TraceMallocCloseLogFD", TraceMallocCloseLogFD
, 1, 0),
1399 JS_FS("TraceMallocLogTimestamp", TraceMallocLogTimestamp
, 1, 0),
1400 JS_FS("TraceMallocDumpAllocations", TraceMallocDumpAllocations
, 1, 0),
1404 #endif /* NS_TRACE_MALLOC */
1413 // See https://wiki.mozilla.org/Performance/MemShrink/DMD for instructions on
1417 OpenDMDOutputFile(JSContext
*cx
, JS::CallArgs
&args
)
1419 JSString
*str
= JS::ToString(cx
, args
.get(0));
1422 JSAutoByteString
pathname(cx
, str
);
1426 FILE* fp
= fopen(pathname
.ptr(), "w");
1428 JS_ReportError(cx
, "DMD can't open %s: %s",
1429 pathname
.ptr(), strerror(errno
));
1436 AnalyzeReports(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1438 if (!dmd::IsRunning()) {
1439 JS_ReportError(cx
, "DMD is not running");
1443 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
1444 FILE *fp
= OpenDMDOutputFile(cx
, args
);
1449 dmd::ClearReports();
1450 dmd::RunReportersForThisProcess();
1451 dmd::Writer
writer(FpWrite
, fp
);
1452 dmd::AnalyzeReports(writer
);
1456 args
.rval().setUndefined();
1460 // This will be removed eventually.
1462 ReportAndDump(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1464 JS_ReportWarning(cx
, "DMDReportAndDump() is deprecated; "
1465 "please use DMDAnalyzeReports() instead");
1467 return AnalyzeReports(cx
, argc
, vp
);
1471 AnalyzeHeap(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1473 if (!dmd::IsRunning()) {
1474 JS_ReportError(cx
, "DMD is not running");
1478 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
1479 FILE *fp
= OpenDMDOutputFile(cx
, args
);
1484 dmd::Writer
writer(FpWrite
, fp
);
1485 dmd::AnalyzeHeap(writer
);
1489 args
.rval().setUndefined();
1494 } // namespace mozilla
1496 static const JSFunctionSpec DMDFunctions
[] = {
1497 JS_FS("DMDReportAndDump", dmd::ReportAndDump
, 1, 0),
1498 JS_FS("DMDAnalyzeReports", dmd::AnalyzeReports
, 1, 0),
1499 JS_FS("DMDAnalyzeHeap", dmd::AnalyzeHeap
, 1, 0),
1503 #endif // defined(MOZ_DMD)
1510 IsJProfAction(struct sigaction
*action
)
1512 return (action
->sa_sigaction
&&
1513 (action
->sa_flags
& (SA_RESTART
| SA_SIGINFO
)) == (SA_RESTART
| SA_SIGINFO
));
1516 void NS_JProfStartProfiling();
1517 void NS_JProfStopProfiling();
1518 void NS_JProfClearCircular();
1521 JProfStartProfilingJS(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1523 NS_JProfStartProfiling();
1527 void NS_JProfStartProfiling()
1529 // Figure out whether we're dealing with SIGPROF, SIGALRM, or
1530 // SIGPOLL profiling (SIGALRM for JP_REALTIME, SIGPOLL for
1532 struct sigaction action
;
1534 // Must check ALRM before PROF since both are enabled for real-time
1535 sigaction(SIGALRM
, nullptr, &action
);
1536 //printf("SIGALRM: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
1537 if (IsJProfAction(&action
)) {
1538 //printf("Beginning real-time jprof profiling.\n");
1543 sigaction(SIGPROF
, nullptr, &action
);
1544 //printf("SIGPROF: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
1545 if (IsJProfAction(&action
)) {
1546 //printf("Beginning process-time jprof profiling.\n");
1551 sigaction(SIGPOLL
, nullptr, &action
);
1552 //printf("SIGPOLL: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
1553 if (IsJProfAction(&action
)) {
1554 //printf("Beginning rtc-based jprof profiling.\n");
1559 printf("Could not start jprof-profiling since JPROF_FLAGS was not set.\n");
1563 JProfStopProfilingJS(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1565 NS_JProfStopProfiling();
1570 NS_JProfStopProfiling()
1573 //printf("Stopped jprof profiling.\n");
1577 JProfClearCircularJS(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1579 NS_JProfClearCircular();
1584 NS_JProfClearCircular()
1587 //printf("cleared jprof buffer\n");
1591 JProfSaveCircularJS(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1594 NS_JProfStopProfiling();
1595 NS_JProfStartProfiling();
1599 static const JSFunctionSpec JProfFunctions
[] = {
1600 JS_FS("JProfStartProfiling", JProfStartProfilingJS
, 0, 0),
1601 JS_FS("JProfStopProfiling", JProfStopProfilingJS
, 0, 0),
1602 JS_FS("JProfClearCircular", JProfClearCircularJS
, 0, 0),
1603 JS_FS("JProfSaveCircular", JProfSaveCircularJS
, 0, 0),
1607 #endif /* defined(MOZ_JPROF) */
1610 nsJSContext::InitClasses(JS::Handle
<JSObject
*> aGlobalObj
)
1612 JSOptionChangedCallback(js_options_dot_str
, this);
1615 JSContext
* cx
= jsapi
.cx();
1616 JSAutoCompartment
ac(cx
, aGlobalObj
);
1618 // Attempt to initialize profiling functions
1619 ::JS_DefineProfilingFunctions(cx
, aGlobalObj
);
1621 #ifdef NS_TRACE_MALLOC
1622 if (nsContentUtils::IsCallerChrome()) {
1623 // Attempt to initialize TraceMalloc functions
1624 ::JS_DefineFunctions(cx
, aGlobalObj
, TraceMallocFunctions
);
1629 if (nsContentUtils::IsCallerChrome()) {
1630 // Attempt to initialize DMD functions
1631 ::JS_DefineFunctions(cx
, aGlobalObj
, DMDFunctions
);
1636 // Attempt to initialize JProf functions
1637 ::JS_DefineFunctions(cx
, aGlobalObj
, JProfFunctions
);
1644 nsJSContext::WillInitializeContext()
1646 mIsInitialized
= false;
1650 nsJSContext::DidInitializeContext()
1652 mIsInitialized
= true;
1656 nsJSContext::IsContextInitialized()
1658 return mIsInitialized
;
1662 nsJSContext::GetProcessingScriptTag()
1664 return mProcessingScriptTag
;
1668 nsJSContext::SetProcessingScriptTag(bool aFlag
)
1670 mProcessingScriptTag
= aFlag
;
1674 FullGCTimerFired(nsITimer
* aTimer
, void* aClosure
)
1676 nsJSContext::KillFullGCTimer();
1677 uintptr_t reason
= reinterpret_cast<uintptr_t>(aClosure
);
1678 nsJSContext::GarbageCollectNow(static_cast<JS::gcreason::Reason
>(reason
),
1679 nsJSContext::IncrementalGC
);
1684 nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason
,
1685 IsIncremental aIncremental
,
1686 IsShrinking aShrinking
,
1687 int64_t aSliceMillis
)
1689 PROFILER_LABEL("nsJSContext", "GarbageCollectNow",
1690 js::ProfileEntry::Category::GC
);
1692 MOZ_ASSERT_IF(aSliceMillis
, aIncremental
== IncrementalGC
);
1695 KillShrinkGCBuffersTimer();
1697 // Reset sPendingLoadCount in case the timer that fired was a
1698 // timer we scheduled due to a normal GC timer firing while
1699 // documents were loading. If this happens we're waiting for a
1700 // document that is taking a long time to load, and we effectively
1701 // ignore the fact that the currently loading documents are still
1702 // loading and move on as if they weren't.
1703 sPendingLoadCount
= 0;
1704 sLoadingInProgress
= false;
1706 if (!nsContentUtils::XPConnect() || !sRuntime
) {
1710 if (sCCLockedOut
&& aIncremental
== IncrementalGC
) {
1711 // We're in the middle of incremental GC. Do another slice.
1712 JS::PrepareForIncrementalGC(sRuntime
);
1713 JS::IncrementalGC(sRuntime
, aReason
, aSliceMillis
);
1717 JS::PrepareForFullGC(sRuntime
);
1718 if (aIncremental
== IncrementalGC
) {
1719 MOZ_ASSERT(aShrinking
== NonShrinkingGC
);
1720 JS::IncrementalGC(sRuntime
, aReason
, aSliceMillis
);
1721 } else if (aShrinking
== ShrinkingGC
) {
1722 JS::ShrinkingGC(sRuntime
, aReason
);
1724 JS::GCForReason(sRuntime
, aReason
);
1730 nsJSContext::ShrinkGCBuffersNow()
1732 PROFILER_LABEL("nsJSContext", "ShrinkGCBuffersNow",
1733 js::ProfileEntry::Category::GC
);
1735 KillShrinkGCBuffersTimer();
1737 JS::ShrinkGCBuffers(sRuntime
);
1741 FinishAnyIncrementalGC()
1744 // We're in the middle of an incremental GC, so finish it.
1745 JS::PrepareForIncrementalGC(sRuntime
);
1746 JS::FinishIncrementalGC(sRuntime
, JS::gcreason::CC_FORCED
);
1751 FireForgetSkippable(uint32_t aSuspected
, bool aRemoveChildless
)
1753 PRTime startTime
= PR_Now();
1754 FinishAnyIncrementalGC();
1755 bool earlyForgetSkippable
=
1756 sCleanupsSinceLastGC
< NS_MAJOR_FORGET_SKIPPABLE_CALLS
;
1757 nsCycleCollector_forgetSkippable(aRemoveChildless
, earlyForgetSkippable
);
1758 sPreviousSuspectedCount
= nsCycleCollector_suspectedCount();
1759 ++sCleanupsSinceLastGC
;
1760 PRTime delta
= PR_Now() - startTime
;
1761 if (sMinForgetSkippableTime
> delta
) {
1762 sMinForgetSkippableTime
= delta
;
1764 if (sMaxForgetSkippableTime
< delta
) {
1765 sMaxForgetSkippableTime
= delta
;
1767 sTotalForgetSkippableTime
+= delta
;
1768 sRemovedPurples
+= (aSuspected
- sPreviousSuspectedCount
);
1769 ++sForgetSkippableBeforeCC
;
1774 TimeBetween(TimeStamp start
, TimeStamp end
)
1776 MOZ_ASSERT(end
>= start
);
1777 return (uint32_t) ((end
- start
).ToMilliseconds());
1781 TimeUntilNow(TimeStamp start
)
1783 if (start
.IsNull()) {
1786 return TimeBetween(start
, TimeStamp::Now());
1789 struct CycleCollectorStats
1794 mMaxSliceTimeSinceClear
= 0;
1799 mBeginSliceTime
= TimeStamp();
1800 mEndSliceTime
= TimeStamp();
1801 mBeginTime
= TimeStamp();
1803 mRanSyncForgetSkippable
= false;
1805 mMaxSkippableDuration
= 0;
1807 mTotalSliceTime
= 0;
1808 mAnyLockedOut
= false;
1809 mExtraForgetSkippableCalls
= 0;
1812 void PrepareForCycleCollectionSlice(int32_t aExtraForgetSkippableCalls
= 0);
1814 void FinishCycleCollectionSlice()
1816 if (mBeginSliceTime
.IsNull()) {
1817 // We already called this method from EndCycleCollectionCallback for this slice.
1821 mEndSliceTime
= TimeStamp::Now();
1822 uint32_t sliceTime
= TimeBetween(mBeginSliceTime
, mEndSliceTime
);
1823 mMaxSliceTime
= std::max(mMaxSliceTime
, sliceTime
);
1824 mMaxSliceTimeSinceClear
= std::max(mMaxSliceTimeSinceClear
, sliceTime
);
1825 mTotalSliceTime
+= sliceTime
;
1826 mBeginSliceTime
= TimeStamp();
1827 MOZ_ASSERT(mExtraForgetSkippableCalls
== 0, "Forget to reset extra forget skippable calls?");
1830 void RunForgetSkippable();
1832 // Time the current slice began, including any GC finishing.
1833 TimeStamp mBeginSliceTime
;
1835 // Time the previous slice of the current CC ended.
1836 TimeStamp mEndSliceTime
;
1838 // Time the current cycle collection began.
1839 TimeStamp mBeginTime
;
1841 // The longest GC finishing duration for any slice of the current CC.
1842 uint32_t mMaxGCDuration
;
1844 // True if we ran sync forget skippable in any slice of the current CC.
1845 bool mRanSyncForgetSkippable
;
1847 // Number of suspected objects at the start of the current CC.
1848 uint32_t mSuspected
;
1850 // The longest duration spent on sync forget skippable in any slice of the
1852 uint32_t mMaxSkippableDuration
;
1854 // The longest pause of any slice in the current CC.
1855 uint32_t mMaxSliceTime
;
1857 // The longest slice time since ClearMaxCCSliceTime() was called.
1858 uint32_t mMaxSliceTimeSinceClear
;
1860 // The total amount of time spent actually running the current CC.
1861 uint32_t mTotalSliceTime
;
1863 // True if we were locked out by the GC in any slice of the current CC.
1866 int32_t mExtraForgetSkippableCalls
;
1869 CycleCollectorStats gCCStats
;
1872 CycleCollectorStats::PrepareForCycleCollectionSlice(int32_t aExtraForgetSkippableCalls
)
1874 mBeginSliceTime
= TimeStamp::Now();
1876 // Before we begin the cycle collection, make sure there is no active GC.
1878 mAnyLockedOut
= true;
1879 FinishAnyIncrementalGC();
1880 uint32_t gcTime
= TimeBetween(mBeginSliceTime
, TimeStamp::Now());
1881 mMaxGCDuration
= std::max(mMaxGCDuration
, gcTime
);
1884 mExtraForgetSkippableCalls
= aExtraForgetSkippableCalls
;
1888 CycleCollectorStats::RunForgetSkippable()
1890 // Run forgetSkippable synchronously to reduce the size of the CC graph. This
1891 // is particularly useful if we recently finished a GC.
1892 if (mExtraForgetSkippableCalls
>= 0) {
1893 TimeStamp beginForgetSkippable
= TimeStamp::Now();
1894 bool ranSyncForgetSkippable
= false;
1895 while (sCleanupsSinceLastGC
< NS_MAJOR_FORGET_SKIPPABLE_CALLS
) {
1896 FireForgetSkippable(nsCycleCollector_suspectedCount(), false);
1897 ranSyncForgetSkippable
= true;
1900 for (int32_t i
= 0; i
< mExtraForgetSkippableCalls
; ++i
) {
1901 FireForgetSkippable(nsCycleCollector_suspectedCount(), false);
1902 ranSyncForgetSkippable
= true;
1905 if (ranSyncForgetSkippable
) {
1906 mMaxSkippableDuration
=
1907 std::max(mMaxSkippableDuration
, TimeUntilNow(beginForgetSkippable
));
1908 mRanSyncForgetSkippable
= true;
1912 mExtraForgetSkippableCalls
= 0;
1917 nsJSContext::CycleCollectNow(nsICycleCollectorListener
*aListener
,
1918 int32_t aExtraForgetSkippableCalls
)
1920 if (!NS_IsMainThread()) {
1924 PROFILER_LABEL("nsJSContext", "CycleCollectNow",
1925 js::ProfileEntry::Category::CC
);
1927 gCCStats
.PrepareForCycleCollectionSlice(aExtraForgetSkippableCalls
);
1928 nsCycleCollector_collect(aListener
);
1929 gCCStats
.FinishCycleCollectionSlice();
1934 nsJSContext::RunCycleCollectorSlice()
1936 if (!NS_IsMainThread()) {
1940 PROFILER_LABEL("nsJSContext", "RunCycleCollectorSlice",
1941 js::ProfileEntry::Category::CC
);
1943 gCCStats
.PrepareForCycleCollectionSlice();
1945 // Decide how long we want to budget for this slice. By default,
1946 // use an unlimited budget.
1947 int64_t sliceBudget
= -1;
1949 if (sIncrementalCC
) {
1950 if (gCCStats
.mBeginTime
.IsNull()) {
1951 // If no CC is in progress, use the standard slice time.
1952 sliceBudget
= kICCSliceBudget
;
1954 TimeStamp now
= TimeStamp::Now();
1956 // Only run a limited slice if we're within the max running time.
1957 if (TimeBetween(gCCStats
.mBeginTime
, now
) < kMaxICCDuration
) {
1958 float sliceMultiplier
= std::max(TimeBetween(gCCStats
.mEndSliceTime
, now
) / (float)kICCIntersliceDelay
, 1.0f
);
1959 sliceBudget
= kICCSliceBudget
* sliceMultiplier
;
1964 nsCycleCollector_collectSlice(sliceBudget
);
1966 gCCStats
.FinishCycleCollectionSlice();
1971 nsJSContext::RunCycleCollectorWorkSlice(int64_t aWorkBudget
)
1973 if (!NS_IsMainThread()) {
1977 PROFILER_LABEL("nsJSContext", "RunCycleCollectorWorkSlice",
1978 js::ProfileEntry::Category::CC
);
1980 gCCStats
.PrepareForCycleCollectionSlice();
1981 nsCycleCollector_collectSliceWork(aWorkBudget
);
1982 gCCStats
.FinishCycleCollectionSlice();
1986 nsJSContext::ClearMaxCCSliceTime()
1988 gCCStats
.mMaxSliceTimeSinceClear
= 0;
1992 nsJSContext::GetMaxCCSliceTimeSinceClear()
1994 return gCCStats
.mMaxSliceTimeSinceClear
;
1998 ICCTimerFired(nsITimer
* aTimer
, void* aClosure
)
2004 // Ignore ICC timer fires during IGC. Running ICC during an IGC will cause us
2005 // to synchronously finish the GC, which is bad.
2008 PRTime now
= PR_Now();
2009 if (sCCLockedOutTime
== 0) {
2010 sCCLockedOutTime
= now
;
2013 if (now
- sCCLockedOutTime
< NS_MAX_CC_LOCKEDOUT_TIME
) {
2018 nsJSContext::RunCycleCollectorSlice();
2023 nsJSContext::BeginCycleCollectionCallback()
2025 MOZ_ASSERT(NS_IsMainThread());
2027 gCCStats
.mBeginTime
= gCCStats
.mBeginSliceTime
.IsNull() ? TimeStamp::Now() : gCCStats
.mBeginSliceTime
;
2028 gCCStats
.mSuspected
= nsCycleCollector_suspectedCount();
2032 gCCStats
.RunForgetSkippable();
2034 MOZ_ASSERT(!sICCTimer
, "Tried to create a new ICC timer when one already existed.");
2036 if (!sIncrementalCC
) {
2040 CallCreateInstance("@mozilla.org/timer;1", &sICCTimer
);
2042 sICCTimer
->InitWithFuncCallback(ICCTimerFired
,
2044 kICCIntersliceDelay
,
2045 nsITimer::TYPE_REPEATING_SLACK
);
2049 static_assert(NS_GC_DELAY
> kMaxICCDuration
, "A max duration ICC shouldn't reduce GC delay to 0");
2053 nsJSContext::EndCycleCollectionCallback(CycleCollectorResults
&aResults
)
2055 MOZ_ASSERT(NS_IsMainThread());
2057 nsJSContext::KillICCTimer();
2059 // Update timing information for the current slice before we log it, if
2060 // we previously called PrepareForCycleCollectionSlice(). During shutdown
2061 // CCs, this won't happen.
2062 gCCStats
.FinishCycleCollectionSlice();
2064 sCCollectedWaitingForGC
+= aResults
.mFreedRefCounted
+ aResults
.mFreedGCed
;
2066 TimeStamp endCCTimeStamp
= TimeStamp::Now();
2067 uint32_t ccNowDuration
= TimeBetween(gCCStats
.mBeginTime
, endCCTimeStamp
);
2069 if (NeedsGCAfterCC()) {
2070 PokeGC(JS::gcreason::CC_WAITING
,
2071 NS_GC_DELAY
- std::min(ccNowDuration
, kMaxICCDuration
));
2075 if (sPostGCEventsToObserver
) {
2076 endCCTime
= PR_Now();
2079 // Log information about the CC via telemetry, JSON and the console.
2080 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC
, gCCStats
.mAnyLockedOut
);
2081 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE
, gCCStats
.mRanSyncForgetSkippable
);
2082 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FULL
, ccNowDuration
);
2083 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_MAX_PAUSE
, gCCStats
.mMaxSliceTime
);
2085 if (!sLastCCEndTime
.IsNull()) {
2086 // TimeBetween returns milliseconds, but we want to report seconds.
2087 uint32_t timeBetween
= TimeBetween(sLastCCEndTime
, gCCStats
.mBeginTime
) / 1000;
2088 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN
, timeBetween
);
2090 sLastCCEndTime
= endCCTimeStamp
;
2092 Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX
,
2093 sMaxForgetSkippableTime
/ PR_USEC_PER_MSEC
);
2095 PRTime delta
= GetCollectionTimeDelta();
2097 uint32_t cleanups
= sForgetSkippableBeforeCC
? sForgetSkippableBeforeCC
: 1;
2098 uint32_t minForgetSkippableTime
= (sMinForgetSkippableTime
== UINT32_MAX
)
2099 ? 0 : sMinForgetSkippableTime
;
2101 if (sPostGCEventsToConsole
) {
2103 if (aResults
.mMergedZones
) {
2104 mergeMsg
.AssignLiteral(" merged");
2108 if (aResults
.mForcedGC
) {
2109 gcMsg
.AssignLiteral(", forced a GC");
2112 NS_NAMED_MULTILINE_LITERAL_STRING(kFmt
,
2113 MOZ_UTF16("CC(T+%.1f) max pause: %lums, total time: %lums, slices: %lu, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu|%lu waiting for GC)%s\n")
2114 MOZ_UTF16("ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, max sync: %lu ms, removed: %lu"));
2116 msg
.Adopt(nsTextFormatter::smprintf(kFmt
.get(), double(delta
) / PR_USEC_PER_SEC
,
2117 gCCStats
.mMaxSliceTime
, gCCStats
.mTotalSliceTime
,
2118 aResults
.mNumSlices
, gCCStats
.mSuspected
,
2119 aResults
.mVisitedRefCounted
, aResults
.mVisitedGCed
, mergeMsg
.get(),
2120 aResults
.mFreedRefCounted
, aResults
.mFreedGCed
,
2121 sCCollectedWaitingForGC
, sLikelyShortLivingObjectsNeedingGC
,
2123 sForgetSkippableBeforeCC
,
2124 minForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2125 sMaxForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2126 (sTotalForgetSkippableTime
/ cleanups
) /
2128 sTotalForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2129 gCCStats
.mMaxSkippableDuration
, sRemovedPurples
));
2130 nsCOMPtr
<nsIConsoleService
> cs
=
2131 do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
2133 cs
->LogStringMessage(msg
.get());
2137 if (sPostGCEventsToObserver
) {
2138 NS_NAMED_MULTILINE_LITERAL_STRING(kJSONFmt
,
2139 MOZ_UTF16("{ \"timestamp\": %llu, ")
2140 MOZ_UTF16("\"duration\": %lu, ")
2141 MOZ_UTF16("\"max_slice_pause\": %lu, ")
2142 MOZ_UTF16("\"total_slice_pause\": %lu, ")
2143 MOZ_UTF16("\"max_finish_gc_duration\": %lu, ")
2144 MOZ_UTF16("\"max_sync_skippable_duration\": %lu, ")
2145 MOZ_UTF16("\"suspected\": %lu, ")
2146 MOZ_UTF16("\"visited\": { ")
2147 MOZ_UTF16("\"RCed\": %lu, ")
2148 MOZ_UTF16("\"GCed\": %lu }, ")
2149 MOZ_UTF16("\"collected\": { ")
2150 MOZ_UTF16("\"RCed\": %lu, ")
2151 MOZ_UTF16("\"GCed\": %lu }, ")
2152 MOZ_UTF16("\"waiting_for_gc\": %lu, ")
2153 MOZ_UTF16("\"short_living_objects_waiting_for_gc\": %lu, ")
2154 MOZ_UTF16("\"forced_gc\": %d, ")
2155 MOZ_UTF16("\"forget_skippable\": { ")
2156 MOZ_UTF16("\"times_before_cc\": %lu, ")
2157 MOZ_UTF16("\"min\": %lu, ")
2158 MOZ_UTF16("\"max\": %lu, ")
2159 MOZ_UTF16("\"avg\": %lu, ")
2160 MOZ_UTF16("\"total\": %lu, ")
2161 MOZ_UTF16("\"removed\": %lu } ")
2164 json
.Adopt(nsTextFormatter::smprintf(kJSONFmt
.get(), endCCTime
, ccNowDuration
,
2165 gCCStats
.mMaxSliceTime
,
2166 gCCStats
.mTotalSliceTime
,
2167 gCCStats
.mMaxGCDuration
,
2168 gCCStats
.mMaxSkippableDuration
,
2169 gCCStats
.mSuspected
,
2170 aResults
.mVisitedRefCounted
, aResults
.mVisitedGCed
,
2171 aResults
.mFreedRefCounted
, aResults
.mFreedGCed
,
2172 sCCollectedWaitingForGC
,
2173 sLikelyShortLivingObjectsNeedingGC
,
2175 sForgetSkippableBeforeCC
,
2176 minForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2177 sMaxForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2178 (sTotalForgetSkippableTime
/ cleanups
) /
2180 sTotalForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2182 nsCOMPtr
<nsIObserverService
> observerService
= mozilla::services::GetObserverService();
2183 if (observerService
) {
2184 observerService
->NotifyObservers(nullptr, "cycle-collection-statistics", json
.get());
2188 // Update global state to indicate we have just run a cycle collection.
2189 sMinForgetSkippableTime
= UINT32_MAX
;
2190 sMaxForgetSkippableTime
= 0;
2191 sTotalForgetSkippableTime
= 0;
2192 sRemovedPurples
= 0;
2193 sForgetSkippableBeforeCC
= 0;
2194 sNeedsFullCC
= false;
2195 sNeedsGCAfterCC
= false;
2201 InterSliceGCTimerFired(nsITimer
*aTimer
, void *aClosure
)
2203 nsJSContext::KillInterSliceGCTimer();
2204 nsJSContext::GarbageCollectNow(JS::gcreason::INTER_SLICE_GC
,
2205 nsJSContext::IncrementalGC
,
2206 nsJSContext::NonShrinkingGC
,
2207 NS_INTERSLICE_GC_BUDGET
);
2212 GCTimerFired(nsITimer
*aTimer
, void *aClosure
)
2214 nsJSContext::KillGCTimer();
2215 uintptr_t reason
= reinterpret_cast<uintptr_t>(aClosure
);
2216 nsJSContext::GarbageCollectNow(static_cast<JS::gcreason::Reason
>(reason
),
2217 nsJSContext::IncrementalGC
);
2221 ShrinkGCBuffersTimerFired(nsITimer
*aTimer
, void *aClosure
)
2223 nsJSContext::KillShrinkGCBuffersTimer();
2224 nsJSContext::ShrinkGCBuffersNow();
2228 ShouldTriggerCC(uint32_t aSuspected
)
2230 return sNeedsFullCC
||
2231 aSuspected
> NS_CC_PURPLE_LIMIT
||
2232 (aSuspected
> NS_CC_FORCED_PURPLE_LIMIT
&&
2233 TimeUntilNow(sLastCCEndTime
) > NS_CC_FORCED
);
2237 CCTimerFired(nsITimer
*aTimer
, void *aClosure
)
2243 static uint32_t ccDelay
= NS_CC_DELAY
;
2245 ccDelay
= NS_CC_DELAY
/ 3;
2247 PRTime now
= PR_Now();
2248 if (sCCLockedOutTime
== 0) {
2249 // Reset sCCTimerFireCount so that we run forgetSkippable
2250 // often enough before CC. Because of reduced ccDelay
2251 // forgetSkippable will be called just a few times.
2252 // NS_MAX_CC_LOCKEDOUT_TIME limit guarantees that we end up calling
2253 // forgetSkippable and CycleCollectNow eventually.
2254 sCCTimerFireCount
= 0;
2255 sCCLockedOutTime
= now
;
2258 if (now
- sCCLockedOutTime
< NS_MAX_CC_LOCKEDOUT_TIME
) {
2263 ++sCCTimerFireCount
;
2265 // During early timer fires, we only run forgetSkippable. During the first
2266 // late timer fire, we decide if we are going to have a second and final
2267 // late timer fire, where we may begin to run the CC. Should run at least one
2268 // early timer fire to allow cleanup before the CC.
2269 int32_t numEarlyTimerFires
= std::max((int32_t)ccDelay
/ NS_CC_SKIPPABLE_DELAY
- 2, 1);
2270 bool isLateTimerFire
= sCCTimerFireCount
> numEarlyTimerFires
;
2271 uint32_t suspected
= nsCycleCollector_suspectedCount();
2272 if (isLateTimerFire
&& ShouldTriggerCC(suspected
)) {
2273 if (sCCTimerFireCount
== numEarlyTimerFires
+ 1) {
2274 FireForgetSkippable(suspected
, true);
2275 if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
2276 // Our efforts to avoid a CC have failed, so we return to let the
2277 // timer fire once more to trigger a CC.
2281 // We are in the final timer fire and still meet the conditions for
2282 // triggering a CC. Let RunCycleCollectorSlice finish the current IGC, if
2283 // any because that will allow us to include the GC time in the CC pause.
2284 nsJSContext::RunCycleCollectorSlice();
2286 } else if ((sPreviousSuspectedCount
+ 100) <= suspected
) {
2287 // Only do a forget skippable if there are more than a few new objects.
2288 FireForgetSkippable(suspected
, false);
2291 if (isLateTimerFire
) {
2292 ccDelay
= NS_CC_DELAY
;
2294 // We have either just run the CC or decided we don't want to run the CC
2295 // next time, so kill the timer.
2296 sPreviousSuspectedCount
= 0;
2297 nsJSContext::KillCCTimer();
2303 nsJSContext::CleanupsSinceLastGC()
2305 return sCleanupsSinceLastGC
;
2310 nsJSContext::LoadStart()
2312 sLoadingInProgress
= true;
2313 ++sPendingLoadCount
;
2318 nsJSContext::LoadEnd()
2320 if (!sLoadingInProgress
)
2323 // sPendingLoadCount is not a well managed load counter (and doesn't
2324 // need to be), so make sure we don't make it wrap backwards here.
2325 if (sPendingLoadCount
> 0) {
2326 --sPendingLoadCount
;
2330 // Its probably a good idea to GC soon since we have finished loading.
2331 sLoadingInProgress
= false;
2332 PokeGC(JS::gcreason::LOAD_END
);
2335 // Only trigger expensive timers when they have been checked a number of times.
2337 ReadyToTriggerExpensiveCollectorTimer()
2339 bool ready
= kPokesBetweenExpensiveCollectorTriggers
< ++sExpensiveCollectorPokes
;
2341 sExpensiveCollectorPokes
= 0;
2347 // Check all of the various collector timers and see if they are waiting to fire.
2348 // For the synchronous collector timers, sGCTimer and sCCTimer, we only want to trigger
2349 // the collection occasionally, because they are expensive. The incremental collector
2350 // timers, sInterSliceGCTimer and sICCTimer, are fast and need to be run many times, so
2351 // always run their corresponding timer.
2353 // This does not check sFullGCTimer, as that's an even more expensive collector we run
2358 nsJSContext::RunNextCollectorTimer()
2360 if (sShuttingDown
) {
2365 if (ReadyToTriggerExpensiveCollectorTimer()) {
2366 GCTimerFired(nullptr, reinterpret_cast<void *>(JS::gcreason::DOM_WINDOW_UTILS
));
2371 if (sInterSliceGCTimer
) {
2372 InterSliceGCTimerFired(nullptr, nullptr);
2376 // Check the CC timers after the GC timers, because the CC timers won't do
2377 // anything if a GC is in progress.
2378 MOZ_ASSERT(!sCCLockedOut
, "Don't check the CC timers if the CC is locked out.");
2381 if (ReadyToTriggerExpensiveCollectorTimer()) {
2382 CCTimerFired(nullptr, nullptr);
2388 ICCTimerFired(nullptr, nullptr);
2395 nsJSContext::PokeGC(JS::gcreason::Reason aReason
, int aDelay
)
2397 if (sGCTimer
|| sInterSliceGCTimer
|| sShuttingDown
) {
2398 // There's already a timer for GC'ing, just return
2403 // Make sure CC is called...
2404 sNeedsFullCC
= true;
2406 sNeedsGCAfterCC
= true;
2411 // Make sure GC is called after the current CC completes.
2412 // No need to set sNeedsFullCC because we are currently running a CC.
2413 sNeedsGCAfterCC
= true;
2417 CallCreateInstance("@mozilla.org/timer;1", &sGCTimer
);
2420 // Failed to create timer (probably because we're in XPCOM shutdown)
2424 static bool first
= true;
2426 sGCTimer
->InitWithFuncCallback(GCTimerFired
, reinterpret_cast<void *>(aReason
),
2432 nsITimer::TYPE_ONE_SHOT
);
2439 nsJSContext::PokeShrinkGCBuffers()
2441 if (sShrinkGCBuffersTimer
|| sShuttingDown
) {
2445 CallCreateInstance("@mozilla.org/timer;1", &sShrinkGCBuffersTimer
);
2447 if (!sShrinkGCBuffersTimer
) {
2448 // Failed to create timer (probably because we're in XPCOM shutdown)
2452 sShrinkGCBuffersTimer
->InitWithFuncCallback(ShrinkGCBuffersTimerFired
, nullptr,
2453 NS_SHRINK_GC_BUFFERS_DELAY
,
2454 nsITimer::TYPE_ONE_SHOT
);
2459 nsJSContext::MaybePokeCC()
2461 if (sCCTimer
|| sICCTimer
|| sShuttingDown
|| !sHasRunGC
) {
2465 if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
2466 sCCTimerFireCount
= 0;
2467 CallCreateInstance("@mozilla.org/timer;1", &sCCTimer
);
2471 // We can kill some objects before running forgetSkippable.
2472 nsCycleCollector_dispatchDeferredDeletion();
2474 sCCTimer
->InitWithFuncCallback(CCTimerFired
, nullptr,
2475 NS_CC_SKIPPABLE_DELAY
,
2476 nsITimer::TYPE_REPEATING_SLACK
);
2482 nsJSContext::KillGCTimer()
2486 NS_RELEASE(sGCTimer
);
2491 nsJSContext::KillFullGCTimer()
2494 sFullGCTimer
->Cancel();
2495 NS_RELEASE(sFullGCTimer
);
2500 nsJSContext::KillInterSliceGCTimer()
2502 if (sInterSliceGCTimer
) {
2503 sInterSliceGCTimer
->Cancel();
2504 NS_RELEASE(sInterSliceGCTimer
);
2510 nsJSContext::KillShrinkGCBuffersTimer()
2512 if (sShrinkGCBuffersTimer
) {
2513 sShrinkGCBuffersTimer
->Cancel();
2514 NS_RELEASE(sShrinkGCBuffersTimer
);
2520 nsJSContext::KillCCTimer()
2522 sCCLockedOutTime
= 0;
2525 NS_RELEASE(sCCTimer
);
2531 nsJSContext::KillICCTimer()
2533 sCCLockedOutTime
= 0;
2536 sICCTimer
->Cancel();
2537 NS_RELEASE(sICCTimer
);
2542 nsJSContext::GC(JS::gcreason::Reason aReason
)
2547 class NotifyGCEndRunnable
: public nsRunnable
2552 explicit NotifyGCEndRunnable(const nsString
& aMessage
) : mMessage(aMessage
) {}
2558 NotifyGCEndRunnable::Run()
2560 MOZ_ASSERT(NS_IsMainThread());
2562 nsCOMPtr
<nsIObserverService
> observerService
= mozilla::services::GetObserverService();
2563 if (!observerService
) {
2567 const jschar oomMsg
[3] = { '{', '}', 0 };
2568 const jschar
*toSend
= mMessage
.get() ? mMessage
.get() : oomMsg
;
2569 observerService
->NotifyObservers(nullptr, "garbage-collection-statistics", toSend
);
2575 DOMGCSliceCallback(JSRuntime
*aRt
, JS::GCProgress aProgress
, const JS::GCDescription
&aDesc
)
2577 NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread");
2579 if (aProgress
== JS::GC_CYCLE_END
) {
2580 PRTime delta
= GetCollectionTimeDelta();
2582 if (sPostGCEventsToConsole
) {
2583 NS_NAMED_LITERAL_STRING(kFmt
, "GC(T+%.1f) ");
2584 nsString prefix
, gcstats
;
2585 gcstats
.Adopt(aDesc
.formatMessage(aRt
));
2586 prefix
.Adopt(nsTextFormatter::smprintf(kFmt
.get(),
2587 double(delta
) / PR_USEC_PER_SEC
));
2588 nsString msg
= prefix
+ gcstats
;
2589 nsCOMPtr
<nsIConsoleService
> cs
= do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
2591 cs
->LogStringMessage(msg
.get());
2595 if (sPostGCEventsToObserver
) {
2597 json
.Adopt(aDesc
.formatJSON(aRt
, PR_Now()));
2598 nsRefPtr
<NotifyGCEndRunnable
> notify
= new NotifyGCEndRunnable(json
);
2599 NS_DispatchToMainThread(notify
);
2603 // Prevent cycle collections and shrinking during incremental GC.
2604 if (aProgress
== JS::GC_CYCLE_BEGIN
) {
2605 sCCLockedOut
= true;
2606 nsJSContext::KillShrinkGCBuffersTimer();
2607 } else if (aProgress
== JS::GC_CYCLE_END
) {
2608 sCCLockedOut
= false;
2611 // The GC has more work to do, so schedule another GC slice.
2612 if (aProgress
== JS::GC_SLICE_END
) {
2613 nsJSContext::KillInterSliceGCTimer();
2614 if (!sShuttingDown
) {
2615 CallCreateInstance("@mozilla.org/timer;1", &sInterSliceGCTimer
);
2616 sInterSliceGCTimer
->InitWithFuncCallback(InterSliceGCTimerFired
,
2618 NS_INTERSLICE_GC_DELAY
,
2619 nsITimer::TYPE_ONE_SHOT
);
2623 if (aProgress
== JS::GC_CYCLE_END
) {
2624 // May need to kill the inter-slice GC timer
2625 nsJSContext::KillInterSliceGCTimer();
2627 sCCollectedWaitingForGC
= 0;
2628 sLikelyShortLivingObjectsNeedingGC
= 0;
2629 sCleanupsSinceLastGC
= 0;
2630 sNeedsFullCC
= true;
2632 nsJSContext::MaybePokeCC();
2634 if (aDesc
.isCompartment_
) {
2635 if (!sFullGCTimer
&& !sShuttingDown
) {
2636 CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer
);
2637 JS::gcreason::Reason reason
= JS::gcreason::FULL_GC_TIMER
;
2638 sFullGCTimer
->InitWithFuncCallback(FullGCTimerFired
,
2639 reinterpret_cast<void *>(reason
),
2641 nsITimer::TYPE_ONE_SHOT
);
2644 nsJSContext::KillFullGCTimer();
2646 // Avoid shrinking during heavy activity, which is suggested by
2648 nsJSContext::PokeShrinkGCBuffers();
2652 if ((aProgress
== JS::GC_SLICE_END
|| aProgress
== JS::GC_CYCLE_END
) &&
2653 ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
2654 nsCycleCollector_dispatchDeferredDeletion();
2657 if (sPrevGCSliceCallback
)
2658 (*sPrevGCSliceCallback
)(aRt
, aProgress
, aDesc
);
2662 nsJSContext::ReportPendingException()
2664 if (mIsInitialized
) {
2665 nsJSUtils::ReportPendingException(mContext
);
2670 nsJSContext::SetWindowProxy(JS::Handle
<JSObject
*> aWindowProxy
)
2672 mWindowProxy
= aWindowProxy
;
2676 nsJSContext::GetWindowProxy()
2678 JSObject
* windowProxy
= GetWindowProxyPreserveColor();
2680 JS::ExposeObjectToActiveJS(windowProxy
);
2687 nsJSContext::GetWindowProxyPreserveColor()
2689 return mWindowProxy
;
2693 nsJSContext::LikelyShortLivingObjectCreated()
2695 ++sLikelyShortLivingObjectsNeedingGC
;
2699 mozilla::dom::StartupJSEnvironment()
2701 // initialize all our statics, so that we can restart XPCOM
2702 sGCTimer
= sFullGCTimer
= sCCTimer
= sICCTimer
= nullptr;
2703 sCCLockedOut
= false;
2704 sCCLockedOutTime
= 0;
2705 sLastCCEndTime
= TimeStamp();
2707 sPendingLoadCount
= 0;
2708 sLoadingInProgress
= false;
2709 sCCollectedWaitingForGC
= 0;
2710 sLikelyShortLivingObjectsNeedingGC
= 0;
2711 sPostGCEventsToConsole
= false;
2712 sNeedsFullCC
= false;
2713 sNeedsGCAfterCC
= false;
2714 gNameSpaceManager
= nullptr;
2715 sRuntimeService
= nullptr;
2717 sIsInitialized
= false;
2718 sDidShutdown
= false;
2719 sShuttingDown
= false;
2721 sSecurityManager
= nullptr;
2723 sExpensiveCollectorPokes
= 0;
2727 ReportAllJSExceptionsPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2729 bool reportAll
= Preferences::GetBool(aPrefName
, false);
2730 nsContentUtils::XPConnect()->SetReportAllJSExceptions(reportAll
);
2734 SetMemoryHighWaterMarkPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2736 int32_t highwatermark
= Preferences::GetInt(aPrefName
, 128);
2738 JS_SetGCParameter(sRuntime
, JSGC_MAX_MALLOC_BYTES
,
2739 highwatermark
* 1024L * 1024L);
2743 SetMemoryMaxPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2745 int32_t pref
= Preferences::GetInt(aPrefName
, -1);
2746 // handle overflow and negative pref values
2747 uint32_t max
= (pref
<= 0 || pref
>= 0x1000) ? -1 : (uint32_t)pref
* 1024 * 1024;
2748 JS_SetGCParameter(sRuntime
, JSGC_MAX_BYTES
, max
);
2752 SetMemoryGCModePrefChangedCallback(const char* aPrefName
, void* aClosure
)
2754 bool enableCompartmentGC
= Preferences::GetBool("javascript.options.mem.gc_per_compartment");
2755 bool enableIncrementalGC
= Preferences::GetBool("javascript.options.mem.gc_incremental");
2757 if (enableIncrementalGC
) {
2758 mode
= JSGC_MODE_INCREMENTAL
;
2759 } else if (enableCompartmentGC
) {
2760 mode
= JSGC_MODE_COMPARTMENT
;
2762 mode
= JSGC_MODE_GLOBAL
;
2764 JS_SetGCParameter(sRuntime
, JSGC_MODE
, mode
);
2768 SetMemoryGCSliceTimePrefChangedCallback(const char* aPrefName
, void* aClosure
)
2770 int32_t pref
= Preferences::GetInt(aPrefName
, -1);
2771 // handle overflow and negative pref values
2772 if (pref
> 0 && pref
< 100000)
2773 JS_SetGCParameter(sRuntime
, JSGC_SLICE_TIME_BUDGET
, pref
);
2777 SetMemoryGCPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2779 int32_t pref
= Preferences::GetInt(aPrefName
, -1);
2780 // handle overflow and negative pref values
2781 if (pref
>= 0 && pref
< 10000)
2782 JS_SetGCParameter(sRuntime
, (JSGCParamKey
)(intptr_t)aClosure
, pref
);
2786 SetMemoryGCDynamicHeapGrowthPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2788 bool pref
= Preferences::GetBool(aPrefName
);
2789 JS_SetGCParameter(sRuntime
, JSGC_DYNAMIC_HEAP_GROWTH
, pref
);
2793 SetMemoryGCDynamicMarkSlicePrefChangedCallback(const char* aPrefName
, void* aClosure
)
2795 bool pref
= Preferences::GetBool(aPrefName
);
2796 JS_SetGCParameter(sRuntime
, JSGC_DYNAMIC_MARK_SLICE
, pref
);
2800 SetIncrementalCCPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2802 bool pref
= Preferences::GetBool(aPrefName
);
2803 sIncrementalCC
= pref
;
2807 NS_DOMReadStructuredClone(JSContext
* cx
,
2808 JSStructuredCloneReader
* reader
,
2813 if (tag
== SCTAG_DOM_IMAGEDATA
) {
2814 return ReadStructuredCloneImageData(cx
, reader
);
2815 } else if (tag
== SCTAG_DOM_WEBCRYPTO_KEY
) {
2816 nsIGlobalObject
*global
= xpc::GetNativeForGlobal(JS::CurrentGlobalOrNull(cx
));
2821 // Prevent the return value from being trashed by a GC during ~nsRefPtr.
2822 JS::Rooted
<JSObject
*> result(cx
);
2824 nsRefPtr
<CryptoKey
> key
= new CryptoKey(global
);
2825 if (!key
->ReadStructuredClone(reader
)) {
2828 result
= key
->WrapObject(cx
);
2832 } else if (tag
== SCTAG_DOM_NULL_PRINCIPAL
||
2833 tag
== SCTAG_DOM_SYSTEM_PRINCIPAL
||
2834 tag
== SCTAG_DOM_CONTENT_PRINCIPAL
) {
2835 mozilla::ipc::PrincipalInfo info
;
2836 if (tag
== SCTAG_DOM_SYSTEM_PRINCIPAL
) {
2837 info
= mozilla::ipc::SystemPrincipalInfo();
2838 } else if (tag
== SCTAG_DOM_NULL_PRINCIPAL
) {
2839 info
= mozilla::ipc::NullPrincipalInfo();
2841 uint32_t appId
= data
;
2843 uint32_t isInBrowserElement
, specLength
;
2844 if (!JS_ReadUint32Pair(reader
, &isInBrowserElement
, &specLength
)) {
2849 spec
.SetLength(specLength
);
2850 if (!JS_ReadBytes(reader
, spec
.BeginWriting(), specLength
)) {
2854 info
= mozilla::ipc::ContentPrincipalInfo(appId
, isInBrowserElement
, spec
);
2858 nsCOMPtr
<nsIPrincipal
> principal
= PrincipalInfoToPrincipal(info
, &rv
);
2859 if (NS_WARN_IF(NS_FAILED(rv
))) {
2860 xpc::Throw(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
2864 JS::RootedValue
result(cx
);
2865 rv
= nsContentUtils::WrapNative(cx
, principal
, &NS_GET_IID(nsIPrincipal
), &result
);
2866 if (NS_FAILED(rv
)) {
2867 xpc::Throw(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
2871 return result
.toObjectOrNull();
2874 // Don't know what this is. Bail.
2875 xpc::Throw(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
2880 NS_DOMWriteStructuredClone(JSContext
* cx
,
2881 JSStructuredCloneWriter
* writer
,
2882 JS::Handle
<JSObject
*> obj
,
2885 // Handle ImageData cloning
2886 ImageData
* imageData
;
2887 if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData
, obj
, imageData
))) {
2888 return WriteStructuredCloneImageData(cx
, writer
, imageData
);
2891 // Handle Key cloning
2893 if (NS_SUCCEEDED(UNWRAP_OBJECT(CryptoKey
, obj
, key
))) {
2894 return JS_WriteUint32Pair(writer
, SCTAG_DOM_WEBCRYPTO_KEY
, 0) &&
2895 key
->WriteStructuredClone(writer
);
2898 if (xpc::IsReflector(obj
)) {
2899 nsCOMPtr
<nsISupports
> base
= xpc::UnwrapReflectorToISupports(obj
);
2900 nsCOMPtr
<nsIPrincipal
> principal
= do_QueryInterface(base
);
2902 mozilla::ipc::PrincipalInfo info
;
2903 if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(principal
, &info
)))) {
2904 xpc::Throw(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
2908 if (info
.type() == mozilla::ipc::PrincipalInfo::TNullPrincipalInfo
) {
2909 return JS_WriteUint32Pair(writer
, SCTAG_DOM_NULL_PRINCIPAL
, 0);
2911 if (info
.type() == mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo
) {
2912 return JS_WriteUint32Pair(writer
, SCTAG_DOM_SYSTEM_PRINCIPAL
, 0);
2915 MOZ_ASSERT(info
.type() == mozilla::ipc::PrincipalInfo::TContentPrincipalInfo
);
2916 const mozilla::ipc::ContentPrincipalInfo
& cInfo
= info
;
2917 return JS_WriteUint32Pair(writer
, SCTAG_DOM_CONTENT_PRINCIPAL
, cInfo
.appId()) &&
2918 JS_WriteUint32Pair(writer
, cInfo
.isInBrowserElement(), cInfo
.spec().Length()) &&
2919 JS_WriteBytes(writer
, cInfo
.spec().get(), cInfo
.spec().Length());
2923 // Don't know what this is
2924 xpc::Throw(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
2929 NS_DOMStructuredCloneError(JSContext
* cx
,
2932 // We don't currently support any extensions to structured cloning.
2933 xpc::Throw(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
2937 AsmJSCacheOpenEntryForRead(JS::Handle
<JSObject
*> aGlobal
,
2938 const jschar
* aBegin
,
2939 const jschar
* aLimit
,
2941 const uint8_t** aMemory
,
2944 nsIPrincipal
* principal
=
2945 nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aGlobal
)));
2946 return asmjscache::OpenEntryForRead(principal
, aBegin
, aLimit
, aSize
, aMemory
,
2951 AsmJSCacheOpenEntryForWrite(JS::Handle
<JSObject
*> aGlobal
,
2953 const jschar
* aBegin
,
2959 nsIPrincipal
* principal
=
2960 nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aGlobal
)));
2961 return asmjscache::OpenEntryForWrite(principal
, aInstalled
, aBegin
, aEnd
,
2962 aSize
, aMemory
, aHandle
);
2965 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID
, NS_DOM_SCRIPT_OBJECT_FACTORY_CID
);
2968 nsJSContext::EnsureStatics()
2970 if (sIsInitialized
) {
2971 if (!nsContentUtils::XPConnect()) {
2977 nsresult rv
= CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
,
2979 if (NS_FAILED(rv
)) {
2983 rv
= CallGetService(kJSRuntimeServiceContractID
, &sRuntimeService
);
2984 if (NS_FAILED(rv
)) {
2988 rv
= sRuntimeService
->GetRuntime(&sRuntime
);
2989 if (NS_FAILED(rv
)) {
2993 // Let's make sure that our main thread is the same as the xpcom main thread.
2994 MOZ_ASSERT(NS_IsMainThread());
2996 sPrevGCSliceCallback
= JS::SetGCSliceCallback(sRuntime
, DOMGCSliceCallback
);
2998 // Set up the structured clone callbacks.
2999 static JSStructuredCloneCallbacks cloneCallbacks
= {
3000 NS_DOMReadStructuredClone
,
3001 NS_DOMWriteStructuredClone
,
3002 NS_DOMStructuredCloneError
,
3007 JS_SetStructuredCloneCallbacks(sRuntime
, &cloneCallbacks
);
3009 // Set up the asm.js cache callbacks
3010 static JS::AsmJSCacheOps asmJSCacheOps
= {
3011 AsmJSCacheOpenEntryForRead
,
3012 asmjscache::CloseEntryForRead
,
3013 AsmJSCacheOpenEntryForWrite
,
3014 asmjscache::CloseEntryForWrite
,
3015 asmjscache::GetBuildId
3017 JS::SetAsmJSCacheOps(sRuntime
, &asmJSCacheOps
);
3019 // Set these global xpconnect options...
3020 Preferences::RegisterCallbackAndCall(ReportAllJSExceptionsPrefChangedCallback
,
3021 "dom.report_all_js_exceptions");
3023 Preferences::RegisterCallbackAndCall(SetMemoryHighWaterMarkPrefChangedCallback
,
3024 "javascript.options.mem.high_water_mark");
3026 Preferences::RegisterCallbackAndCall(SetMemoryMaxPrefChangedCallback
,
3027 "javascript.options.mem.max");
3029 Preferences::RegisterCallbackAndCall(SetMemoryGCModePrefChangedCallback
,
3030 "javascript.options.mem.gc_per_compartment");
3032 Preferences::RegisterCallbackAndCall(SetMemoryGCModePrefChangedCallback
,
3033 "javascript.options.mem.gc_incremental");
3035 Preferences::RegisterCallbackAndCall(SetMemoryGCSliceTimePrefChangedCallback
,
3036 "javascript.options.mem.gc_incremental_slice_ms");
3038 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
3039 "javascript.options.mem.gc_high_frequency_time_limit_ms",
3040 (void *)JSGC_HIGH_FREQUENCY_TIME_LIMIT
);
3042 Preferences::RegisterCallbackAndCall(SetMemoryGCDynamicMarkSlicePrefChangedCallback
,
3043 "javascript.options.mem.gc_dynamic_mark_slice");
3045 Preferences::RegisterCallbackAndCall(SetMemoryGCDynamicHeapGrowthPrefChangedCallback
,
3046 "javascript.options.mem.gc_dynamic_heap_growth");
3048 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
3049 "javascript.options.mem.gc_low_frequency_heap_growth",
3050 (void *)JSGC_LOW_FREQUENCY_HEAP_GROWTH
);
3052 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
3053 "javascript.options.mem.gc_high_frequency_heap_growth_min",
3054 (void *)JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN
);
3056 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
3057 "javascript.options.mem.gc_high_frequency_heap_growth_max",
3058 (void *)JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX
);
3060 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
3061 "javascript.options.mem.gc_high_frequency_low_limit_mb",
3062 (void *)JSGC_HIGH_FREQUENCY_LOW_LIMIT
);
3064 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
3065 "javascript.options.mem.gc_high_frequency_high_limit_mb",
3066 (void *)JSGC_HIGH_FREQUENCY_HIGH_LIMIT
);
3068 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
3069 "javascript.options.mem.gc_allocation_threshold_mb",
3070 (void *)JSGC_ALLOCATION_THRESHOLD
);
3072 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
3073 "javascript.options.mem.gc_decommit_threshold_mb",
3074 (void *)JSGC_DECOMMIT_THRESHOLD
);
3076 Preferences::RegisterCallbackAndCall(SetIncrementalCCPrefChangedCallback
,
3077 "dom.cycle_collector.incremental");
3079 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
3080 "javascript.options.mem.gc_min_empty_chunk_count",
3081 (void *)JSGC_MIN_EMPTY_CHUNK_COUNT
);
3083 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
3084 "javascript.options.mem.gc_max_empty_chunk_count",
3085 (void *)JSGC_MAX_EMPTY_CHUNK_COUNT
);
3087 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
3092 Preferences::AddBoolVarCache(&sGCOnMemoryPressure
,
3093 "javascript.options.gc_on_memory_pressure",
3096 nsIObserver
* observer
= new nsJSEnvironmentObserver();
3097 obs
->AddObserver(observer
, "memory-pressure", false);
3098 obs
->AddObserver(observer
, "quit-application", false);
3100 // Bug 907848 - We need to explicitly get the nsIDOMScriptObjectFactory
3101 // service in order to force its constructor to run, which registers a
3102 // shutdown observer. It would be nice to make this more explicit and less
3104 nsCOMPtr
<nsIDOMScriptObjectFactory
> factory
= do_GetService(kDOMScriptObjectFactoryCID
);
3109 sIsInitialized
= true;
3112 nsScriptNameSpaceManager
*
3113 mozilla::dom::GetNameSpaceManager()
3118 if (!gNameSpaceManager
) {
3119 gNameSpaceManager
= new nsScriptNameSpaceManager
;
3120 NS_ADDREF(gNameSpaceManager
);
3122 nsresult rv
= gNameSpaceManager
->Init();
3123 NS_ENSURE_SUCCESS(rv
, nullptr);
3126 return gNameSpaceManager
;
3130 mozilla::dom::ShutdownJSEnvironment()
3134 NS_IF_RELEASE(gNameSpaceManager
);
3136 if (!sContextCount
) {
3137 // We're being shutdown, and there are no more contexts
3138 // alive, release the JS runtime service and the security manager.
3140 NS_IF_RELEASE(sRuntimeService
);
3141 NS_IF_RELEASE(sSecurityManager
);
3144 sShuttingDown
= true;
3145 sDidShutdown
= true;
3148 // A fast-array class for JS. This class supports both nsIJSScriptArray and
3149 // nsIArray. If it is JS itself providing and consuming this class, all work
3150 // can be done via nsIJSScriptArray, and avoid the conversion of elements
3151 // to/from nsISupports.
3152 // When consumed by non-JS (eg, another script language), conversion is done
3154 class nsJSArgArray MOZ_FINAL
: public nsIJSArgArray
{
3156 nsJSArgArray(JSContext
*aContext
, uint32_t argc
, JS::Value
*argv
,
3160 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
3161 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray
,
3168 nsresult
GetArgs(uint32_t *argc
, void **argv
);
3170 void ReleaseJSObjects();
3174 JSContext
*mContext
;
3175 JS::Heap
<JS::Value
> *mArgv
;
3179 nsJSArgArray::nsJSArgArray(JSContext
*aContext
, uint32_t argc
, JS::Value
*argv
,
3185 // copy the array - we don't know its lifetime, and ours is tied to xpcom
3188 static const fallible_t fallible
= fallible_t();
3189 mArgv
= new (fallible
) JS::Heap
<JS::Value
>[argc
];
3191 *prv
= NS_ERROR_OUT_OF_MEMORY
;
3196 // Callers are allowed to pass in a null argv even for argc > 0. They can
3197 // then use GetArgs to initialize the values.
3199 for (uint32_t i
= 0; i
< argc
; ++i
)
3204 mozilla::HoldJSObjects(this);
3210 nsJSArgArray::~nsJSArgArray()
3216 nsJSArgArray::ReleaseJSObjects()
3223 mozilla::DropJSObjects(this);
3227 // QueryInterface implementation for nsJSArgArray
3228 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSArgArray
)
3230 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSArgArray
)
3231 tmp
->ReleaseJSObjects();
3232 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
3233 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray
)
3234 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
3235 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
3237 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray
)
3239 for (uint32_t i
= 0; i
< tmp
->mArgc
; ++i
) {
3240 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mArgv
[i
])
3243 NS_IMPL_CYCLE_COLLECTION_TRACE_END
3245 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSArgArray
)
3246 NS_INTERFACE_MAP_ENTRY(nsIArray
)
3247 NS_INTERFACE_MAP_ENTRY(nsIJSArgArray
)
3248 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIJSArgArray
)
3249 NS_INTERFACE_MAP_END
3251 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSArgArray
)
3252 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSArgArray
)
3255 nsJSArgArray::GetArgs(uint32_t *argc
, void **argv
)
3257 *argv
= (void *)mArgv
;
3263 NS_IMETHODIMP
nsJSArgArray::GetLength(uint32_t *aLength
)
3269 /* void queryElementAt (in unsigned long index, in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
3270 NS_IMETHODIMP
nsJSArgArray::QueryElementAt(uint32_t index
, const nsIID
& uuid
, void * *result
)
3274 return NS_ERROR_INVALID_ARG
;
3276 if (uuid
.Equals(NS_GET_IID(nsIVariant
)) || uuid
.Equals(NS_GET_IID(nsISupports
))) {
3277 // Have to copy a Heap into a Rooted to work with it.
3278 JS::Rooted
<JS::Value
> val(mContext
, mArgv
[index
]);
3279 return nsContentUtils::XPConnect()->JSToVariant(mContext
, val
,
3280 (nsIVariant
**)result
);
3282 NS_WARNING("nsJSArgArray only handles nsIVariant");
3283 return NS_ERROR_NO_INTERFACE
;
3286 /* unsigned long indexOf (in unsigned long startIndex, in nsISupports element); */
3287 NS_IMETHODIMP
nsJSArgArray::IndexOf(uint32_t startIndex
, nsISupports
*element
, uint32_t *_retval
)
3289 return NS_ERROR_NOT_IMPLEMENTED
;
3292 /* nsISimpleEnumerator enumerate (); */
3293 NS_IMETHODIMP
nsJSArgArray::Enumerate(nsISimpleEnumerator
**_retval
)
3295 return NS_ERROR_NOT_IMPLEMENTED
;
3298 // The factory function
3299 nsresult
NS_CreateJSArgv(JSContext
*aContext
, uint32_t argc
, void *argv
,
3300 nsIJSArgArray
**aArray
)
3303 nsCOMPtr
<nsIJSArgArray
> ret
= new nsJSArgArray(aContext
, argc
,
3304 static_cast<JS::Value
*>(argv
), &rv
);
3305 if (NS_FAILED(rv
)) {