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 "nsJSUtils.h"
22 #include "nsIDocShell.h"
23 #include "nsIDocShellTreeItem.h"
24 #include "nsPresContext.h"
25 #include "nsIConsoleService.h"
26 #include "nsIScriptError.h"
27 #include "nsIInterfaceRequestor.h"
28 #include "nsIInterfaceRequestorUtils.h"
29 #include "nsIPrompt.h"
30 #include "nsIObserverService.h"
33 #include "nsContentUtils.h"
34 #include "nsCxPusher.h"
35 #include "nsEventDispatcher.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"
43 #include "xpcpublic.h"
45 #include "js/OldDebugAPI.h"
46 #include "jswrapper.h"
48 #include "nsIObjectInputStream.h"
49 #include "nsIObjectOutputStream.h"
51 #include "WrapperFactory.h"
52 #include "nsGlobalWindow.h"
53 #include "nsScriptNameSpaceManager.h"
54 #include "StructuredCloneTags.h"
55 #include "mozilla/dom/ImageData.h"
56 #include "mozilla/dom/ImageDataBinding.h"
57 #include "nsAXPCNativeCallContext.h"
58 #include "mozilla/CycleCollectedJSRuntime.h"
60 #include "nsJSPrincipals.h"
63 // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
66 #include "AccessCheck.h"
69 #include "jsdIDebuggerService.h"
72 // Force PR_LOGGING so we can get JS strict warnings even in release builds
73 #define FORCE_PR_LOG 1
78 #include "mozilla/Preferences.h"
79 #include "mozilla/Telemetry.h"
80 #include "mozilla/dom/BindingUtils.h"
81 #include "mozilla/Attributes.h"
82 #include "mozilla/dom/asmjscache/AsmJSCache.h"
83 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
84 #include "mozilla/CycleCollectedJSRuntime.h"
85 #include "mozilla/ContentEvents.h"
87 #include "nsCycleCollectionNoteRootCallback.h"
88 #include "GeckoProfiler.h"
90 using namespace mozilla
;
91 using namespace mozilla::dom
;
93 const size_t gStackSize
= 8192;
96 static PRLogModuleInfo
* gJSDiagnostics
;
99 // Thank you Microsoft!
104 #define NS_SHRINK_GC_BUFFERS_DELAY 4000 // ms
106 // The amount of time we wait from the first request to GC to actually
107 // doing the first GC.
108 #define NS_FIRST_GC_DELAY 10000 // ms
110 #define NS_FULL_GC_DELAY 60000 // ms
112 // Maximum amount of time that should elapse between incremental GC slices
113 #define NS_INTERSLICE_GC_DELAY 100 // ms
115 // If we haven't painted in 100ms, we allow for a longer GC budget
116 #define NS_INTERSLICE_GC_BUDGET 40 // ms
118 // The amount of time we wait between a request to CC (after GC ran)
119 // and doing the actual CC.
120 #define NS_CC_DELAY 6000 // ms
122 #define NS_CC_SKIPPABLE_DELAY 400 // ms
124 // Force a CC after this long if there's more than NS_CC_FORCED_PURPLE_LIMIT
125 // objects in the purple buffer.
126 #define NS_CC_FORCED (2 * 60 * PR_USEC_PER_SEC) // 2 min
127 #define NS_CC_FORCED_PURPLE_LIMIT 10
129 // Don't allow an incremental GC to lock out the CC for too long.
130 #define NS_MAX_CC_LOCKEDOUT_TIME (15 * PR_USEC_PER_SEC) // 15 seconds
132 // Trigger a CC if the purple buffer exceeds this size when we check it.
133 #define NS_CC_PURPLE_LIMIT 200
135 #define JAVASCRIPT nsIProgrammingLanguage::JAVASCRIPT
137 // Large value used to specify that a script should run essentially forever
138 #define NS_UNLIMITED_SCRIPT_RUNTIME (0x40000000LL << 32)
140 #define NS_MAJOR_FORGET_SKIPPABLE_CALLS 2
142 // if you add statics here, add them to the list in StartupJSEnvironment
144 static nsITimer
*sGCTimer
;
145 static nsITimer
*sShrinkGCBuffersTimer
;
146 static nsITimer
*sCCTimer
;
147 static nsITimer
*sFullGCTimer
;
148 static nsITimer
*sInterSliceGCTimer
;
150 static PRTime sLastCCEndTime
;
152 static bool sCCLockedOut
;
153 static PRTime sCCLockedOutTime
;
155 static JS::GCSliceCallback sPrevGCSliceCallback
;
157 static bool sHasRunGC
;
159 // The number of currently pending document loads. This count isn't
160 // guaranteed to always reflect reality and can't easily as we don't
161 // have an easy place to know when a load ends or is interrupted in
162 // all cases. This counter also gets reset if we end up GC'ing while
163 // we're waiting for a slow page to load. IOW, this count may be 0
164 // even when there are pending loads.
165 static uint32_t sPendingLoadCount
;
166 static bool sLoadingInProgress
;
168 static uint32_t sCCollectedWaitingForGC
;
169 static uint32_t sLikelyShortLivingObjectsNeedingGC
;
170 static bool sPostGCEventsToConsole
;
171 static bool sPostGCEventsToObserver
;
172 static uint32_t sCCTimerFireCount
= 0;
173 static uint32_t sMinForgetSkippableTime
= UINT32_MAX
;
174 static uint32_t sMaxForgetSkippableTime
= 0;
175 static uint32_t sTotalForgetSkippableTime
= 0;
176 static uint32_t sRemovedPurples
= 0;
177 static uint32_t sForgetSkippableBeforeCC
= 0;
178 static uint32_t sPreviousSuspectedCount
= 0;
179 static uint32_t sCleanupsSinceLastGC
= UINT32_MAX
;
180 static bool sNeedsFullCC
= false;
181 static bool sNeedsGCAfterCC
= false;
182 static nsJSContext
*sContextList
= nullptr;
184 static nsScriptNameSpaceManager
*gNameSpaceManager
;
186 static nsIJSRuntimeService
*sRuntimeService
;
188 static const char kJSRuntimeServiceContractID
[] =
189 "@mozilla.org/js/xpc/RuntimeService;1";
191 static PRTime sFirstCollectionTime
;
193 static JSRuntime
*sRuntime
;
195 static bool sIsInitialized
;
196 static bool sDidShutdown
;
197 static bool sShuttingDown
;
198 static int32_t sContextCount
;
200 static nsIScriptSecurityManager
*sSecurityManager
;
202 // nsJSEnvironmentObserver observes the memory-pressure notifications
203 // and forces a garbage collection and cycle collection when it happens, if
204 // the appropriate pref is set.
206 static bool sGCOnMemoryPressure
;
209 GetCollectionTimeDelta()
211 PRTime now
= PR_Now();
212 if (sFirstCollectionTime
) {
213 return now
- sFirstCollectionTime
;
215 sFirstCollectionTime
= now
;
222 nsJSContext::KillGCTimer();
223 nsJSContext::KillShrinkGCBuffersTimer();
224 nsJSContext::KillCCTimer();
225 nsJSContext::KillFullGCTimer();
226 nsJSContext::KillInterSliceGCTimer();
229 class nsJSEnvironmentObserver MOZ_FINAL
: public nsIObserver
236 NS_IMPL_ISUPPORTS1(nsJSEnvironmentObserver
, nsIObserver
)
239 nsJSEnvironmentObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
240 const PRUnichar
* aData
)
242 if (sGCOnMemoryPressure
&& !nsCRT::strcmp(aTopic
, "memory-pressure")) {
243 if(StringBeginsWith(nsDependentString(aData
),
244 NS_LITERAL_STRING("low-memory-ongoing"))) {
245 // Don't GC/CC if we are in an ongoing low-memory state since its very
246 // slow and it likely won't help us anyway.
249 nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE
,
250 nsJSContext::NonIncrementalGC
,
251 nsJSContext::NonCompartmentGC
,
252 nsJSContext::ShrinkingGC
);
253 nsJSContext::CycleCollectNow();
254 } else if (!nsCRT::strcmp(aTopic
, "quit-application")) {
255 sShuttingDown
= true;
262 class nsRootedJSValueArray
{
264 explicit nsRootedJSValueArray(JSContext
*cx
) : avr(cx
, vals
.Length(), vals
.Elements()) {}
266 void SetCapacity(JSContext
*cx
, size_t capacity
) {
267 vals
.SetCapacity(capacity
);
268 // Values must be safe for the GC to inspect (they must not contain garbage).
269 memset(vals
.Elements(), 0, vals
.Capacity() * sizeof(JS::Value
));
273 JS::Value
*Elements() {
274 return vals
.Elements();
278 void resetRooter(JSContext
*cx
) {
279 avr
.changeArray(vals
.Elements(), vals
.Length());
282 nsAutoTArray
<JS::Value
, 16> vals
;
283 JS::AutoArrayRooter avr
;
286 /****************************************************************
287 ************************** AutoFree ****************************
288 ****************************************************************/
292 AutoFree(void *aPtr
) : mPtr(aPtr
) {
296 nsMemory::Free(mPtr
);
305 // A utility function for script languages to call. Although it looks small,
306 // the use of nsIDocShell and nsPresContext triggers a huge number of
307 // dependencies that most languages would not otherwise need.
308 // XXXmarkh - This function is mis-placed!
310 NS_HandleScriptError(nsIScriptGlobalObject
*aScriptGlobal
,
311 InternalScriptErrorEvent
*aErrorEvent
,
312 nsEventStatus
*aStatus
)
315 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(aScriptGlobal
));
316 nsIDocShell
*docShell
= win
? win
->GetDocShell() : nullptr;
318 nsRefPtr
<nsPresContext
> presContext
;
319 docShell
->GetPresContext(getter_AddRefs(presContext
));
321 static int32_t errorDepth
; // Recursion prevention
324 if (presContext
&& errorDepth
< 2) {
325 // Dispatch() must be synchronous for the recursion block
326 // (errorDepth) to work.
327 nsEventDispatcher::Dispatch(win
, presContext
, aErrorEvent
, nullptr,
339 AsyncErrorReporter::AsyncErrorReporter(JSRuntime
* aRuntime
,
340 JSErrorReport
* aErrorReport
,
341 const char* aFallbackMessage
,
343 nsPIDOMWindow
* aWindow
)
344 : mSourceLine(static_cast<const PRUnichar
*>(aErrorReport
->uclinebuf
))
345 , mLineNumber(aErrorReport
->lineno
)
346 , mColumn(aErrorReport
->uctokenptr
- aErrorReport
->uclinebuf
)
347 , mFlags(aErrorReport
->flags
)
349 if (!aErrorReport
->filename
) {
350 mFileName
.SetIsVoid(true);
352 mFileName
.AssignWithConversion(aErrorReport
->filename
);
355 const PRUnichar
* m
= static_cast<const PRUnichar
*>(aErrorReport
->ucmessage
);
357 const PRUnichar
* n
= static_cast<const PRUnichar
*>
358 (js::GetErrorTypeName(aRuntime
, aErrorReport
->exnType
));
361 mErrorMsg
.AppendLiteral(": ");
366 if (mErrorMsg
.IsEmpty() && aFallbackMessage
) {
367 mErrorMsg
.AssignWithConversion(aFallbackMessage
);
370 mCategory
= aIsChromeError
? NS_LITERAL_CSTRING("chrome javascript") :
371 NS_LITERAL_CSTRING("content javascript");
374 if (aWindow
&& aWindow
->IsOuterWindow()) {
375 aWindow
= aWindow
->GetCurrentInnerWindow();
378 mInnerWindowID
= aWindow
->WindowID();
383 AsyncErrorReporter::ReportError()
385 nsCOMPtr
<nsIScriptError
> errorObject
=
386 do_CreateInstance("@mozilla.org/scripterror;1");
391 nsresult rv
= errorObject
->InitWithWindowID(mErrorMsg
, mFileName
,
392 mSourceLine
, mLineNumber
,
393 mColumn
, mFlags
, mCategory
,
399 nsCOMPtr
<nsIConsoleService
> consoleService
=
400 do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
401 if (!consoleService
) {
405 consoleService
->LogMessage(errorObject
);
410 } // namespace mozilla
412 class ScriptErrorEvent
: public AsyncErrorReporter
415 ScriptErrorEvent(nsIScriptGlobalObject
* aScriptGlobal
,
417 JSErrorReport
* aErrorReport
,
418 const char* aFallbackMessage
,
419 nsIPrincipal
* aScriptOriginPrincipal
,
420 nsIPrincipal
* aGlobalPrincipal
,
421 nsPIDOMWindow
* aWindow
,
423 // Pass an empty category, then compute ours
424 : AsyncErrorReporter(aRuntime
, aErrorReport
, aFallbackMessage
,
425 nsContentUtils::IsSystemPrincipal(aGlobalPrincipal
),
427 , mScriptGlobal(aScriptGlobal
)
428 , mOriginPrincipal(aScriptOriginPrincipal
)
429 , mDispatchEvent(aDispatchEvent
)
435 nsEventStatus status
= nsEventStatus_eIgnore
;
436 // First, notify the DOM that we have a script error.
437 if (mDispatchEvent
) {
438 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
439 nsIDocShell
* docShell
= win
? win
->GetDocShell() : nullptr;
441 !JSREPORT_IS_WARNING(mFlags
) &&
442 !sHandlingScriptError
) {
443 sHandlingScriptError
= true; // Recursion prevention
445 nsRefPtr
<nsPresContext
> presContext
;
446 docShell
->GetPresContext(getter_AddRefs(presContext
));
449 InternalScriptErrorEvent
errorevent(true, NS_LOAD_ERROR
);
451 errorevent
.fileName
= mFileName
.get();
453 nsCOMPtr
<nsIScriptObjectPrincipal
> sop(do_QueryInterface(win
));
454 NS_ENSURE_STATE(sop
);
455 nsIPrincipal
* p
= sop
->GetPrincipal();
458 bool sameOrigin
= !mOriginPrincipal
;
460 if (p
&& !sameOrigin
) {
461 if (NS_FAILED(p
->Subsumes(mOriginPrincipal
, &sameOrigin
))) {
466 NS_NAMED_LITERAL_STRING(xoriginMsg
, "Script error.");
468 errorevent
.errorMsg
= mErrorMsg
.get();
469 errorevent
.lineNr
= mLineNumber
;
471 NS_WARNING("Not same origin error!");
472 errorevent
.errorMsg
= xoriginMsg
.get();
473 errorevent
.lineNr
= 0;
476 nsEventDispatcher::Dispatch(win
, presContext
, &errorevent
, nullptr,
480 sHandlingScriptError
= false;
484 if (status
!= nsEventStatus_eConsumeNoDefault
) {
485 AsyncErrorReporter::ReportError();
492 nsCOMPtr
<nsIScriptGlobalObject
> mScriptGlobal
;
493 nsCOMPtr
<nsIPrincipal
> mOriginPrincipal
;
496 static bool sHandlingScriptError
;
499 bool ScriptErrorEvent::sHandlingScriptError
= false;
501 // NOTE: This function could be refactored to use the above. The only reason
502 // it has not been done is that the code below only fills the error event
503 // after it has a good nsPresContext - whereas using the above function
504 // would involve always filling it. Is that a concern?
506 NS_ScriptErrorReporter(JSContext
*cx
,
508 JSErrorReport
*report
)
510 // We don't want to report exceptions too eagerly, but warnings in the
511 // absence of werror are swallowed whole, so report those now.
512 if (!JSREPORT_IS_WARNING(report
->flags
)) {
513 nsIXPConnect
* xpc
= nsContentUtils::XPConnect();
514 JS::Rooted
<JSScript
*> script(cx
);
515 if (JS_DescribeScriptedCaller(cx
, &script
, nullptr)) {
516 xpc
->MarkErrorUnreported(cx
);
521 nsAXPCNativeCallContext
*cc
= nullptr;
522 xpc
->GetCurrentNativeCallContext(&cc
);
524 nsAXPCNativeCallContext
*prev
= cc
;
525 while (NS_SUCCEEDED(prev
->GetPreviousCallContext(&prev
)) && prev
) {
527 if (NS_SUCCEEDED(prev
->GetLanguage(&lang
)) &&
528 lang
== nsAXPCNativeCallContext::LANG_JS
) {
529 xpc
->MarkErrorUnreported(cx
);
537 // XXX this means we are not going to get error reports on non DOM contexts
538 nsIScriptContext
*context
= nsJSUtils::GetDynamicScriptContext(cx
);
540 // Note: we must do this before running any more code on cx (if cx is the
541 // dynamic script context).
542 ::JS_ClearPendingException(cx
);
545 nsIScriptGlobalObject
*globalObject
= context
->GetGlobalObject();
549 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(globalObject
);
550 nsCOMPtr
<nsIScriptObjectPrincipal
> scriptPrincipal
=
551 do_QueryInterface(globalObject
);
552 NS_ASSERTION(scriptPrincipal
, "Global objects must implement "
553 "nsIScriptObjectPrincipal");
554 nsContentUtils::AddScriptRunner(
555 new ScriptErrorEvent(globalObject
,
559 nsJSPrincipals::get(report
->originPrincipals
),
560 scriptPrincipal
->GetPrincipal(),
562 /* We do not try to report Out Of Memory via a dom
563 * event because the dom event handler would
564 * encounter an OOM exception trying to process the
565 * event, and then we'd need to generate a new OOM
566 * event for that new OOM instance -- this isn't
569 report
->errorNumber
!= JSMSG_OUT_OF_MEMORY
));
573 if (nsContentUtils::DOMWindowDumpEnabled()) {
574 // Print it to stderr as well, for the benefit of those invoking
575 // mozilla with -console.
577 error
.Assign("JavaScript ");
578 if (JSREPORT_IS_STRICT(report
->flags
))
579 error
.Append("strict ");
580 if (JSREPORT_IS_WARNING(report
->flags
))
581 error
.Append("warning: ");
583 error
.Append("error: ");
584 error
.Append(report
->filename
);
585 error
.Append(", line ");
586 error
.AppendInt(report
->lineno
, 10);
588 if (report
->ucmessage
) {
589 AppendUTF16toUTF8(reinterpret_cast<const PRUnichar
*>(report
->ucmessage
),
592 error
.Append(message
);
595 fprintf(stderr
, "%s\n", error
.get());
601 gJSDiagnostics
= PR_NewLogModule("JSDiagnostics");
603 if (gJSDiagnostics
) {
604 PR_LOG(gJSDiagnostics
,
605 JSREPORT_IS_WARNING(report
->flags
) ? PR_LOG_WARNING
: PR_LOG_ERROR
,
606 ("file %s, line %u: %s\n%s%s",
607 report
->filename
, report
->lineno
, message
,
608 report
->linebuf
? report
->linebuf
: "",
610 report
->linebuf
[strlen(report
->linebuf
)-1] != '\n')
618 // A couple of useful functions to call when you're debugging.
620 JSObject2Win(JSContext
*cx
, JSObject
*obj
)
622 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
627 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapper
;
628 xpc
->GetWrappedNativeOfJSObject(cx
, obj
, getter_AddRefs(wrapper
));
630 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryWrappedNative(wrapper
);
632 return static_cast<nsGlobalWindow
*>
633 (static_cast<nsPIDOMWindow
*>(win
));
641 PrintWinURI(nsGlobalWindow
*win
)
644 printf("No window passed in.\n");
648 nsCOMPtr
<nsIDocument
> doc
= win
->GetExtantDoc();
650 printf("No document in the window.\n");
654 nsIURI
*uri
= doc
->GetDocumentURI();
656 printf("Document doesn't have a URI.\n");
662 printf("%s\n", spec
.get());
666 PrintWinCodebase(nsGlobalWindow
*win
)
669 printf("No window passed in.\n");
673 nsIPrincipal
*prin
= win
->GetPrincipal();
675 printf("Window doesn't have principals.\n");
679 nsCOMPtr
<nsIURI
> uri
;
680 prin
->GetURI(getter_AddRefs(uri
));
682 printf("No URI, maybe the system principal.\n");
688 printf("%s\n", spec
.get());
692 DumpString(const nsAString
&str
)
694 printf("%s\n", NS_ConvertUTF16toUTF8(str
).get());
698 #define JS_OPTIONS_DOT_STR "javascript.options."
700 static const char js_options_dot_str
[] = JS_OPTIONS_DOT_STR
;
701 static const char js_strict_option_str
[] = JS_OPTIONS_DOT_STR
"strict";
703 static const char js_strict_debug_option_str
[] = JS_OPTIONS_DOT_STR
"strict.debug";
705 static const char js_werror_option_str
[] = JS_OPTIONS_DOT_STR
"werror";
707 static const char js_zeal_option_str
[] = JS_OPTIONS_DOT_STR
"gczeal";
708 static const char js_zeal_frequency_str
[] = JS_OPTIONS_DOT_STR
"gczeal.frequency";
710 static const char js_typeinfer_content_str
[] = JS_OPTIONS_DOT_STR
"typeinference.content";
711 static const char js_typeinfer_chrome_str
[] = JS_OPTIONS_DOT_STR
"typeinference.chrome";
712 static const char js_jit_hardening_str
[] = JS_OPTIONS_DOT_STR
"jit_hardening";
713 static const char js_memlog_option_str
[] = JS_OPTIONS_DOT_STR
"mem.log";
714 static const char js_memnotify_option_str
[] = JS_OPTIONS_DOT_STR
"mem.notify";
715 static const char js_asmjs_content_str
[] = JS_OPTIONS_DOT_STR
"asmjs";
716 static const char js_baselinejit_content_str
[] = JS_OPTIONS_DOT_STR
"baselinejit.content";
717 static const char js_baselinejit_chrome_str
[] = JS_OPTIONS_DOT_STR
"baselinejit.chrome";
718 static const char js_baselinejit_eager_str
[] = JS_OPTIONS_DOT_STR
"baselinejit.unsafe_eager_compilation";
719 static const char js_ion_content_str
[] = JS_OPTIONS_DOT_STR
"ion.content";
720 static const char js_ion_chrome_str
[] = JS_OPTIONS_DOT_STR
"ion.chrome";
721 static const char js_ion_eager_str
[] = JS_OPTIONS_DOT_STR
"ion.unsafe_eager_compilation";
722 static const char js_parallel_parsing_str
[] = JS_OPTIONS_DOT_STR
"parallel_parsing";
723 static const char js_ion_parallel_compilation_str
[] = JS_OPTIONS_DOT_STR
"ion.parallel_compilation";
726 nsJSContext::JSOptionChangedCallback(const char *pref
, void *data
)
728 nsJSContext
*context
= reinterpret_cast<nsJSContext
*>(data
);
729 JSContext
*cx
= context
->mContext
;
731 sPostGCEventsToConsole
= Preferences::GetBool(js_memlog_option_str
);
732 sPostGCEventsToObserver
= Preferences::GetBool(js_memnotify_option_str
);
734 JS::ContextOptionsRef(cx
).setExtraWarnings(Preferences::GetBool(js_strict_option_str
));
736 // The vanilla GetGlobalObject returns null if a global isn't set up on
737 // the context yet. We can sometimes be call midway through context init,
738 // So ask for the member directly instead.
739 nsIScriptGlobalObject
*global
= context
->GetGlobalObjectRef();
741 // XXX should we check for sysprin instead of a chrome window, to make
742 // XXX components be covered by the chrome pref instead of the content one?
743 nsCOMPtr
<nsIDOMWindow
> contentWindow(do_QueryInterface(global
));
744 nsCOMPtr
<nsIDOMChromeWindow
> chromeWindow(do_QueryInterface(global
));
746 bool useTypeInference
= Preferences::GetBool((chromeWindow
|| !contentWindow
) ?
747 js_typeinfer_chrome_str
:
748 js_typeinfer_content_str
);
749 bool useHardening
= Preferences::GetBool(js_jit_hardening_str
);
750 bool useBaselineJIT
= Preferences::GetBool((chromeWindow
|| !contentWindow
) ?
751 js_baselinejit_chrome_str
:
752 js_baselinejit_content_str
);
753 bool useBaselineJITEager
= Preferences::GetBool(js_baselinejit_eager_str
);
754 bool useIon
= Preferences::GetBool((chromeWindow
|| !contentWindow
) ?
757 bool useIonEager
= Preferences::GetBool(js_ion_eager_str
);
758 bool useAsmJS
= Preferences::GetBool(js_asmjs_content_str
);
759 bool parallelParsing
= Preferences::GetBool(js_parallel_parsing_str
);
760 bool parallelIonCompilation
= Preferences::GetBool(js_ion_parallel_compilation_str
);
761 nsCOMPtr
<nsIXULRuntime
> xr
= do_GetService(XULRUNTIME_SERVICE_CONTRACTID
);
763 bool safeMode
= false;
764 xr
->GetInSafeMode(&safeMode
);
766 useTypeInference
= false;
767 useHardening
= false;
768 useBaselineJIT
= false;
769 useBaselineJITEager
= false;
776 JS::ContextOptionsRef(cx
).setTypeInference(useTypeInference
)
777 .setBaseline(useBaselineJIT
)
782 // In debug builds, warnings are enabled in chrome context if
783 // javascript.options.strict.debug is true
784 if (Preferences::GetBool(js_strict_debug_option_str
) &&
785 (chromeWindow
|| !contentWindow
)) {
786 JS::ContextOptionsRef(cx
).setExtraWarnings(true);
790 JS::ContextOptionsRef(cx
).setWerror(Preferences::GetBool(js_werror_option_str
));
792 ::JS_SetParallelParsingEnabled(context
->mContext
, parallelParsing
);
793 ::JS_SetParallelIonCompilationEnabled(context
->mContext
, parallelIonCompilation
);
795 ::JS_SetGlobalJitCompilerOption(context
->mContext
, JSJITCOMPILER_BASELINE_USECOUNT_TRIGGER
,
796 (useBaselineJITEager
? 0 : -1));
798 ::JS_SetGlobalJitCompilerOption(context
->mContext
, JSJITCOMPILER_ION_USECOUNT_TRIGGER
,
799 (useIonEager
? 0 : -1));
801 JSRuntime
*rt
= JS_GetRuntime(context
->mContext
);
802 JS_SetJitHardening(rt
, useHardening
);
805 int32_t zeal
= Preferences::GetInt(js_zeal_option_str
, -1);
806 int32_t frequency
= Preferences::GetInt(js_zeal_frequency_str
, JS_DEFAULT_ZEAL_FREQ
);
808 ::JS_SetGCZeal(context
->mContext
, (uint8_t)zeal
, frequency
);
814 nsJSContext::nsJSContext(bool aGCOnDestruction
,
815 nsIScriptGlobalObject
* aGlobalObject
)
816 : mWindowProxy(nullptr)
817 , mGCOnDestruction(aGCOnDestruction
)
818 , mGlobalObjectRef(aGlobalObject
)
822 mNext
= sContextList
;
823 mPrev
= &sContextList
;
825 sContextList
->mPrev
= &mNext
;
831 mContext
= ::JS_NewContext(sRuntime
, gStackSize
);
833 ::JS_SetContextPrivate(mContext
, static_cast<nsIScriptContext
*>(this));
835 // Make sure the new context gets the default context options
836 JS::ContextOptionsRef(mContext
).setPrivateIsNSISupports(true)
837 .setNoDefaultCompartmentObject(true);
839 // Watch for the JS boolean options
840 Preferences::RegisterCallback(JSOptionChangedCallback
,
841 js_options_dot_str
, this);
843 mIsInitialized
= false;
844 mProcessingScriptTag
= false;
848 nsJSContext::~nsJSContext()
852 mNext
->mPrev
= mPrev
;
855 mGlobalObjectRef
= nullptr;
861 if (!sContextCount
&& sDidShutdown
) {
862 // The last context is being deleted, and we're already in the
863 // process of shutting down, release the JS runtime service, and
864 // the security manager.
866 NS_IF_RELEASE(sRuntimeService
);
867 NS_IF_RELEASE(sSecurityManager
);
871 // This function is called either by the destructor or unlink, which means that
872 // it can never be called when there is an outstanding ref to the
873 // nsIScriptContext on the stack. Our stack-scoped cx pushers hold such a ref,
874 // so we can assume here that mContext is not on the stack (and therefore not
877 nsJSContext::DestroyJSContext()
883 // Clear our entry in the JSContext, bugzilla bug 66413
884 ::JS_SetContextPrivate(mContext
, nullptr);
886 // Unregister our "javascript.options.*" pref-changed callback.
887 Preferences::UnregisterCallback(JSOptionChangedCallback
,
888 js_options_dot_str
, this);
890 if (mGCOnDestruction
) {
891 PokeGC(JS::gcreason::NSJSCONTEXT_DESTROY
);
894 JS_DestroyContextNoGC(mContext
);
899 // QueryInterface implementation for nsJSContext
900 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSContext
)
902 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSContext
)
903 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mWindowProxy
)
904 NS_IMPL_CYCLE_COLLECTION_TRACE_END
906 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSContext
)
907 NS_ASSERTION(!tmp
->mContext
|| !js::ContextHasOutstandingRequests(tmp
->mContext
),
908 "Trying to unlink a context with outstanding requests.");
909 tmp
->mIsInitialized
= false;
910 tmp
->mGCOnDestruction
= false;
911 tmp
->mWindowProxy
= nullptr;
912 tmp
->DestroyJSContext();
913 NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobalObjectRef
)
914 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
915 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSContext
)
916 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSContext
, tmp
->GetCCRefcnt())
917 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobalObjectRef
)
918 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
919 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
921 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext
)
922 NS_INTERFACE_MAP_ENTRY(nsIScriptContext
)
923 NS_INTERFACE_MAP_ENTRY(nsISupports
)
927 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSContext
)
928 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSContext
)
931 nsJSContext::GetCCRefcnt()
933 nsrefcnt refcnt
= mRefCnt
.get();
935 // In the (abnormal) case of synchronous cycle-collection, the context may be
936 // actively running JS code in which case we must keep it alive by adding an
938 if (mContext
&& js::ContextHasOutstandingRequests(mContext
)) {
946 nsJSContext::EvaluateString(const nsAString
& aScript
,
947 JS::Handle
<JSObject
*> aScopeObject
,
948 JS::CompileOptions
& aCompileOptions
,
949 bool aCoerceToString
,
950 JS::Value
* aRetValue
,
951 void **aOffThreadToken
)
953 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
954 AutoCxPusher
pusher(mContext
);
955 nsJSUtils::EvaluateOptions evalOptions
;
956 evalOptions
.setCoerceToString(aCoerceToString
);
957 return nsJSUtils::EvaluateString(mContext
, aScript
, aScopeObject
,
958 aCompileOptions
, evalOptions
, aRetValue
,
964 AtomIsEventHandlerName(nsIAtom
*aName
)
966 const PRUnichar
*name
= aName
->GetUTF16String();
970 for (cp
= name
; *cp
!= '\0'; ++cp
)
973 if ((c
< 'A' || c
> 'Z') && (c
< 'a' || c
> 'z'))
981 // Helper function to find the JSObject associated with a (presumably DOM)
984 nsJSContext::JSObjectFromInterface(nsISupports
* aTarget
,
985 JS::Handle
<JSObject
*> aScope
,
988 // It is legal to specify a null target.
996 // Get the jsobject associated with this target
997 // We don't wrap here because we trust the JS engine to wrap the target
999 JS::Rooted
<JS::Value
> v(cx
);
1000 nsresult rv
= nsContentUtils::WrapNative(cx
, aScope
, aTarget
, &v
);
1001 NS_ENSURE_SUCCESS(rv
, rv
);
1003 JSObject
* obj
= v
.toObjectOrNull();
1005 JS::ExposeObjectToActiveJS(obj
);
1009 JS::Rooted
<JSObject
*> rootedObj(cx
, obj
);
1010 nsCOMPtr
<nsISupports
> targetSupp
= do_QueryInterface(aTarget
);
1011 nsCOMPtr
<nsISupports
> native
=
1012 nsContentUtils::XPConnect()->GetNativeOfWrapper(cx
, rootedObj
);
1013 NS_ASSERTION(native
== targetSupp
, "Native should be the target!");
1022 nsJSContext::BindCompiledEventHandler(nsISupports
* aTarget
,
1023 JS::Handle
<JSObject
*> aScope
,
1024 JS::Handle
<JSObject
*> aHandler
,
1025 JS::MutableHandle
<JSObject
*> aBoundHandler
)
1027 NS_ENSURE_ARG(aHandler
);
1028 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1029 NS_PRECONDITION(!aBoundHandler
, "Shouldn't already have a bound handler!");
1032 JS::ExposeObjectToActiveJS(aScope
);
1034 JS::ExposeObjectToActiveJS(aHandler
);
1035 AutoPushJSContext
cx(mContext
);
1037 // Get the jsobject associated with this target
1038 JS::Rooted
<JSObject
*> target(cx
);
1039 JS::Rooted
<JSObject
*> scope(cx
, aScope
);
1040 nsresult rv
= JSObjectFromInterface(aTarget
, scope
, target
.address());
1041 NS_ENSURE_SUCCESS(rv
, rv
);
1045 JSAutoCompartment
ac(cx
, aHandler
);
1046 NS_ASSERTION(JS_TypeOfValue(cx
,
1047 OBJECT_TO_JSVAL(aHandler
)) == JSTYPE_FUNCTION
,
1048 "Event handler object not a function");
1052 JSAutoCompartment
ac(cx
, target
);
1055 // Make sure the handler function is parented by its event target object
1057 funobj
= JS_CloneFunctionObject(cx
, aHandler
, target
);
1059 rv
= NS_ERROR_OUT_OF_MEMORY
;
1065 aBoundHandler
.set(funobj
);
1070 nsIScriptGlobalObject
*
1071 nsJSContext::GetGlobalObject()
1074 JS::Rooted
<JSObject
*> global(mContext
, GetWindowProxy());
1079 if (mGlobalObjectRef
)
1080 return mGlobalObjectRef
;
1084 JSObject
*inner
= JS_ObjectToInnerObject(cx
, global
);
1086 // If this assertion hits then it means that we have a window object as
1087 // our global, but we never called CreateOuterObject.
1088 NS_ASSERTION(inner
== global
, "Shouldn't be able to innerize here");
1092 const JSClass
*c
= JS_GetClass(global
);
1094 // Whenever we end up with globals that are JSCLASS_IS_DOMJSCLASS
1095 // and have an nsISupports DOM object, we will need to modify this
1097 MOZ_ASSERT(!(c
->flags
& JSCLASS_IS_DOMJSCLASS
));
1098 if ((~c
->flags
) & (JSCLASS_HAS_PRIVATE
|
1099 JSCLASS_PRIVATE_IS_NSISUPPORTS
)) {
1103 nsISupports
*priv
= static_cast<nsISupports
*>(js::GetObjectPrivate(global
));
1105 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapped_native
=
1106 do_QueryInterface(priv
);
1108 nsCOMPtr
<nsIScriptGlobalObject
> sgo
;
1109 if (wrapped_native
) {
1110 // The global object is a XPConnect wrapped native, the native in
1111 // the wrapper might be the nsIScriptGlobalObject
1113 sgo
= do_QueryWrappedNative(wrapped_native
);
1115 sgo
= do_QueryInterface(priv
);
1118 // This'll return a pointer to something we're about to release, but
1119 // that's ok, the JS object will hold it alive long enough.
1124 nsJSContext::GetNativeContext()
1130 nsJSContext::InitContext()
1132 // Make sure callers of this use
1133 // WillInitializeContext/DidInitializeContext around this call.
1134 NS_ENSURE_TRUE(!mIsInitialized
, NS_ERROR_ALREADY_INITIALIZED
);
1137 return NS_ERROR_OUT_OF_MEMORY
;
1139 ::JS_SetErrorReporter(mContext
, NS_ScriptErrorReporter
);
1141 JSOptionChangedCallback(js_options_dot_str
, this);
1147 nsJSContext::InitializeExternalClasses()
1149 nsScriptNameSpaceManager
*nameSpaceManager
= GetNameSpaceManager();
1150 NS_ENSURE_TRUE(nameSpaceManager
, NS_ERROR_NOT_INITIALIZED
);
1152 return nameSpaceManager
->InitForContext(this);
1156 nsJSContext::SetProperty(JS::Handle
<JSObject
*> aTarget
, const char* aPropName
, nsISupports
* aArgs
)
1159 JS::Value
*argv
= nullptr;
1162 pusher
.Push(mContext
);
1164 Maybe
<nsRootedJSValueArray
> tempStorage
;
1166 JS::Rooted
<JSObject
*> global(mContext
, GetWindowProxy());
1168 ConvertSupportsTojsvals(aArgs
, global
, &argc
, &argv
, tempStorage
);
1169 NS_ENSURE_SUCCESS(rv
, rv
);
1171 JS::AutoArrayRooter
array(mContext
, argc
, argv
);
1173 // got the arguments, now attach them.
1175 for (uint32_t i
= 0; i
< argc
; ++i
) {
1176 if (!JS_WrapValue(mContext
, array
.handleAt(i
))) {
1177 return NS_ERROR_FAILURE
;
1181 JSObject
*args
= ::JS_NewArrayObject(mContext
, argc
, array
.array
);
1183 return NS_ERROR_FAILURE
;
1185 JS::Value vargs
= OBJECT_TO_JSVAL(args
);
1187 return JS_DefineProperty(mContext
, aTarget
, aPropName
, vargs
,
1188 nullptr, nullptr, 0) ? NS_OK
: NS_ERROR_FAILURE
;
1192 nsJSContext::ConvertSupportsTojsvals(nsISupports
*aArgs
,
1193 JS::Handle
<JSObject
*> aScope
,
1196 Maybe
<nsRootedJSValueArray
> &aTempStorage
)
1198 nsresult rv
= NS_OK
;
1200 // If the array implements nsIJSArgArray, just grab the values directly.
1201 nsCOMPtr
<nsIJSArgArray
> fastArray
= do_QueryInterface(aArgs
);
1202 if (fastArray
!= nullptr)
1203 return fastArray
->GetArgs(aArgc
, reinterpret_cast<void **>(aArgv
));
1205 // Take the slower path converting each item.
1206 // Handle only nsIArray and nsIVariant. nsIArray is only needed for
1207 // SetProperty('arguments', ...);
1212 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
1213 NS_ENSURE_TRUE(xpc
, NS_ERROR_UNEXPECTED
);
1219 // This general purpose function may need to convert an arg array
1220 // (window.arguments, event-handler args) and a generic property.
1221 nsCOMPtr
<nsIArray
> argsArray(do_QueryInterface(aArgs
));
1224 rv
= argsArray
->GetLength(&argCount
);
1225 NS_ENSURE_SUCCESS(rv
, rv
);
1229 argCount
= 1; // the nsISupports which is not an array
1232 // Use the caller's auto guards to release and unroot.
1233 aTempStorage
.construct((JSContext
*)cx
);
1234 aTempStorage
.ref().SetCapacity(cx
, argCount
);
1235 JS::Value
*argv
= aTempStorage
.ref().Elements();
1238 for (uint32_t argCtr
= 0; argCtr
< argCount
&& NS_SUCCEEDED(rv
); argCtr
++) {
1239 nsCOMPtr
<nsISupports
> arg
;
1240 JS::Value
*thisval
= argv
+ argCtr
;
1241 argsArray
->QueryElementAt(argCtr
, NS_GET_IID(nsISupports
),
1242 getter_AddRefs(arg
));
1244 *thisval
= JSVAL_NULL
;
1247 nsCOMPtr
<nsIVariant
> variant(do_QueryInterface(arg
));
1248 if (variant
!= nullptr) {
1249 rv
= xpc
->VariantToJS(cx
, aScope
, variant
, thisval
);
1251 // And finally, support the nsISupportsPrimitives supplied
1252 // by the AppShell. It generally will pass only strings, but
1253 // as we have code for handling all, we may as well use it.
1254 rv
= AddSupportsPrimitiveTojsvals(arg
, thisval
);
1255 if (rv
== NS_ERROR_NO_INTERFACE
) {
1256 // something else - probably an event object or similar -
1259 // but first, check its not another nsISupportsPrimitive, as
1260 // these are now deprecated for use with script contexts.
1261 nsCOMPtr
<nsISupportsPrimitive
> prim(do_QueryInterface(arg
));
1262 NS_ASSERTION(prim
== nullptr,
1263 "Don't pass nsISupportsPrimitives - use nsIVariant!");
1265 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
1266 JS::Rooted
<JS::Value
> v(cx
);
1267 rv
= nsContentUtils::WrapNative(cx
, aScope
, arg
, &v
,
1268 getter_AddRefs(wrapper
));
1269 if (NS_SUCCEEDED(rv
)) {
1276 nsCOMPtr
<nsIVariant
> variant
= do_QueryInterface(aArgs
);
1278 rv
= xpc
->VariantToJS(cx
, aScope
, variant
, argv
);
1280 NS_ERROR("Not an array, not an interface?");
1281 rv
= NS_ERROR_UNEXPECTED
;
1291 // This really should go into xpconnect somewhere...
1293 nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports
*aArg
, JS::Value
*aArgv
)
1295 NS_PRECONDITION(aArg
, "Empty arg");
1297 nsCOMPtr
<nsISupportsPrimitive
> argPrimitive(do_QueryInterface(aArg
));
1299 return NS_ERROR_NO_INTERFACE
;
1303 argPrimitive
->GetType(&type
);
1306 case nsISupportsPrimitive::TYPE_CSTRING
: {
1307 nsCOMPtr
<nsISupportsCString
> p(do_QueryInterface(argPrimitive
));
1308 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1315 JSString
*str
= ::JS_NewStringCopyN(cx
, data
.get(), data
.Length());
1316 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
1318 *aArgv
= STRING_TO_JSVAL(str
);
1322 case nsISupportsPrimitive::TYPE_STRING
: {
1323 nsCOMPtr
<nsISupportsString
> p(do_QueryInterface(argPrimitive
));
1324 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1330 // cast is probably safe since wchar_t and jschar are expected
1331 // to be equivalent; both unsigned 16-bit entities
1333 ::JS_NewUCStringCopyN(cx
, data
.get(), data
.Length());
1334 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
1336 *aArgv
= STRING_TO_JSVAL(str
);
1339 case nsISupportsPrimitive::TYPE_PRBOOL
: {
1340 nsCOMPtr
<nsISupportsPRBool
> p(do_QueryInterface(argPrimitive
));
1341 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1347 *aArgv
= BOOLEAN_TO_JSVAL(data
);
1351 case nsISupportsPrimitive::TYPE_PRUINT8
: {
1352 nsCOMPtr
<nsISupportsPRUint8
> p(do_QueryInterface(argPrimitive
));
1353 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1359 *aArgv
= INT_TO_JSVAL(data
);
1363 case nsISupportsPrimitive::TYPE_PRUINT16
: {
1364 nsCOMPtr
<nsISupportsPRUint16
> p(do_QueryInterface(argPrimitive
));
1365 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1371 *aArgv
= INT_TO_JSVAL(data
);
1375 case nsISupportsPrimitive::TYPE_PRUINT32
: {
1376 nsCOMPtr
<nsISupportsPRUint32
> p(do_QueryInterface(argPrimitive
));
1377 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1383 *aArgv
= INT_TO_JSVAL(data
);
1387 case nsISupportsPrimitive::TYPE_CHAR
: {
1388 nsCOMPtr
<nsISupportsChar
> p(do_QueryInterface(argPrimitive
));
1389 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1395 JSString
*str
= ::JS_NewStringCopyN(cx
, &data
, 1);
1396 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
1398 *aArgv
= STRING_TO_JSVAL(str
);
1402 case nsISupportsPrimitive::TYPE_PRINT16
: {
1403 nsCOMPtr
<nsISupportsPRInt16
> p(do_QueryInterface(argPrimitive
));
1404 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1410 *aArgv
= INT_TO_JSVAL(data
);
1414 case nsISupportsPrimitive::TYPE_PRINT32
: {
1415 nsCOMPtr
<nsISupportsPRInt32
> p(do_QueryInterface(argPrimitive
));
1416 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1422 *aArgv
= INT_TO_JSVAL(data
);
1426 case nsISupportsPrimitive::TYPE_FLOAT
: {
1427 nsCOMPtr
<nsISupportsFloat
> p(do_QueryInterface(argPrimitive
));
1428 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1434 *aArgv
= ::JS_NumberValue(data
);
1438 case nsISupportsPrimitive::TYPE_DOUBLE
: {
1439 nsCOMPtr
<nsISupportsDouble
> p(do_QueryInterface(argPrimitive
));
1440 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1446 *aArgv
= ::JS_NumberValue(data
);
1450 case nsISupportsPrimitive::TYPE_INTERFACE_POINTER
: {
1451 nsCOMPtr
<nsISupportsInterfacePointer
> p(do_QueryInterface(argPrimitive
));
1452 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1454 nsCOMPtr
<nsISupports
> data
;
1455 nsIID
*iid
= nullptr;
1457 p
->GetData(getter_AddRefs(data
));
1458 p
->GetDataIID(&iid
);
1459 NS_ENSURE_TRUE(iid
, NS_ERROR_UNEXPECTED
);
1461 AutoFree
iidGuard(iid
); // Free iid upon destruction.
1463 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
1464 JS::Rooted
<JSObject
*> global(cx
, GetWindowProxy());
1465 JS::Rooted
<JS::Value
> v(cx
);
1466 nsresult rv
= nsContentUtils::WrapNative(cx
, global
,
1468 getter_AddRefs(wrapper
));
1469 NS_ENSURE_SUCCESS(rv
, rv
);
1475 case nsISupportsPrimitive::TYPE_ID
:
1476 case nsISupportsPrimitive::TYPE_PRUINT64
:
1477 case nsISupportsPrimitive::TYPE_PRINT64
:
1478 case nsISupportsPrimitive::TYPE_PRTIME
:
1479 case nsISupportsPrimitive::TYPE_VOID
: {
1480 NS_WARNING("Unsupported primitive type used");
1481 *aArgv
= JSVAL_NULL
;
1485 NS_WARNING("Unknown primitive type used");
1486 *aArgv
= JSVAL_NULL
;
1493 #ifdef NS_TRACE_MALLOC
1495 #include <errno.h> // XXX assume Linux if NS_TRACE_MALLOC
1503 #include "nsTraceMalloc.h"
1506 CheckUniversalXPConnectForTraceMalloc(JSContext
*cx
)
1508 if (nsContentUtils::IsCallerChrome())
1510 JS_ReportError(cx
, "trace-malloc functions require UniversalXPConnect");
1515 TraceMallocDisable(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1517 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1520 NS_TraceMallocDisable();
1521 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1526 TraceMallocEnable(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1528 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1531 NS_TraceMallocEnable();
1532 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1537 TraceMallocOpenLogFile(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1539 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
1541 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1548 JSString
*str
= JS::ToString(cx
, args
[0]);
1551 JSAutoByteString
filename(cx
, str
);
1554 fd
= open(filename
.ptr(), O_CREAT
| O_WRONLY
| O_TRUNC
, 0644);
1556 JS_ReportError(cx
, "can't open %s: %s", filename
.ptr(), strerror(errno
));
1560 args
.rval().setInt32(fd
);
1565 TraceMallocChangeLogFD(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1567 JS::CallArgs args
= CallArgsFromVp(argc
, vp
);
1569 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1573 if (args
.length() == 0) {
1576 if (!JS::ToInt32(cx
, args
[0], &fd
))
1578 oldfd
= NS_TraceMallocChangeLogFD(fd
);
1580 JS_ReportOutOfMemory(cx
);
1584 args
.rval().setInt32(oldfd
);
1589 TraceMallocCloseLogFD(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1591 JS::CallArgs args
= CallArgsFromVp(argc
, vp
);
1593 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1597 if (args
.length() == 0) {
1598 args
.rval().setUndefined();
1601 if (!JS::ToInt32(cx
, args
[0], &fd
))
1603 NS_TraceMallocCloseLogFD((int) fd
);
1604 args
.rval().setInt32(fd
);
1609 TraceMallocLogTimestamp(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1611 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
1612 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1615 JSString
*str
= JS::ToString(cx
, args
.get(0));
1618 JSAutoByteString
caption(cx
, str
);
1621 NS_TraceMallocLogTimestamp(caption
.ptr());
1622 args
.rval().setUndefined();
1627 TraceMallocDumpAllocations(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1629 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
1630 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1633 JSString
*str
= JS::ToString(cx
, args
.get(0));
1636 JSAutoByteString
pathname(cx
, str
);
1639 if (NS_TraceMallocDumpAllocations(pathname
.ptr()) < 0) {
1640 JS_ReportError(cx
, "can't dump to %s: %s", pathname
.ptr(), strerror(errno
));
1643 args
.rval().setUndefined();
1647 static const JSFunctionSpec TraceMallocFunctions
[] = {
1648 JS_FS("TraceMallocDisable", TraceMallocDisable
, 0, 0),
1649 JS_FS("TraceMallocEnable", TraceMallocEnable
, 0, 0),
1650 JS_FS("TraceMallocOpenLogFile", TraceMallocOpenLogFile
, 1, 0),
1651 JS_FS("TraceMallocChangeLogFD", TraceMallocChangeLogFD
, 1, 0),
1652 JS_FS("TraceMallocCloseLogFD", TraceMallocCloseLogFD
, 1, 0),
1653 JS_FS("TraceMallocLogTimestamp", TraceMallocLogTimestamp
, 1, 0),
1654 JS_FS("TraceMallocDumpAllocations", TraceMallocDumpAllocations
, 1, 0),
1658 #endif /* NS_TRACE_MALLOC */
1667 // See https://wiki.mozilla.org/Performance/MemShrink/DMD for instructions on
1671 ReportAndDump(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1673 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
1674 JSString
*str
= JS::ToString(cx
, args
.get(0));
1677 JSAutoByteString
pathname(cx
, str
);
1681 FILE* fp
= fopen(pathname
.ptr(), "w");
1683 JS_ReportError(cx
, "DMD can't open %s: %s",
1684 pathname
.ptr(), strerror(errno
));
1688 dmd::ClearReports();
1689 fprintf(stderr
, "DMD: running reporters...\n");
1690 dmd::RunReporters();
1691 dmd::Writer
writer(FpWrite
, fp
);
1696 args
.rval().setUndefined();
1701 } // namespace mozilla
1703 static const JSFunctionSpec DMDFunctions
[] = {
1704 JS_FS("DMDReportAndDump", dmd::ReportAndDump
, 1, 0),
1708 #endif // defined(MOZ_DMD)
1715 IsJProfAction(struct sigaction
*action
)
1717 return (action
->sa_sigaction
&&
1718 (action
->sa_flags
& (SA_RESTART
| SA_SIGINFO
)) == (SA_RESTART
| SA_SIGINFO
));
1721 void NS_JProfStartProfiling();
1722 void NS_JProfStopProfiling();
1723 void NS_JProfClearCircular();
1726 JProfStartProfilingJS(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1728 NS_JProfStartProfiling();
1732 void NS_JProfStartProfiling()
1734 // Figure out whether we're dealing with SIGPROF, SIGALRM, or
1735 // SIGPOLL profiling (SIGALRM for JP_REALTIME, SIGPOLL for
1737 struct sigaction action
;
1739 // Must check ALRM before PROF since both are enabled for real-time
1740 sigaction(SIGALRM
, nullptr, &action
);
1741 //printf("SIGALRM: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
1742 if (IsJProfAction(&action
)) {
1743 //printf("Beginning real-time jprof profiling.\n");
1748 sigaction(SIGPROF
, nullptr, &action
);
1749 //printf("SIGPROF: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
1750 if (IsJProfAction(&action
)) {
1751 //printf("Beginning process-time jprof profiling.\n");
1756 sigaction(SIGPOLL
, nullptr, &action
);
1757 //printf("SIGPOLL: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
1758 if (IsJProfAction(&action
)) {
1759 //printf("Beginning rtc-based jprof profiling.\n");
1764 printf("Could not start jprof-profiling since JPROF_FLAGS was not set.\n");
1768 JProfStopProfilingJS(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1770 NS_JProfStopProfiling();
1775 NS_JProfStopProfiling()
1778 //printf("Stopped jprof profiling.\n");
1782 JProfClearCircularJS(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1784 NS_JProfClearCircular();
1789 NS_JProfClearCircular()
1792 //printf("cleared jprof buffer\n");
1796 JProfSaveCircularJS(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1799 NS_JProfStopProfiling();
1800 NS_JProfStartProfiling();
1804 static const JSFunctionSpec JProfFunctions
[] = {
1805 JS_FS("JProfStartProfiling", JProfStartProfilingJS
, 0, 0),
1806 JS_FS("JProfStopProfiling", JProfStopProfilingJS
, 0, 0),
1807 JS_FS("JProfClearCircular", JProfClearCircularJS
, 0, 0),
1808 JS_FS("JProfSaveCircular", JProfSaveCircularJS
, 0, 0),
1812 #endif /* defined(MOZ_JPROF) */
1815 nsJSContext::InitClasses(JS::Handle
<JSObject
*> aGlobalObj
)
1817 nsresult rv
= InitializeExternalClasses();
1818 NS_ENSURE_SUCCESS(rv
, rv
);
1820 JSOptionChangedCallback(js_options_dot_str
, this);
1821 AutoPushJSContext
cx(mContext
);
1823 // Attempt to initialize profiling functions
1824 ::JS_DefineProfilingFunctions(cx
, aGlobalObj
);
1826 #ifdef NS_TRACE_MALLOC
1827 if (nsContentUtils::IsCallerChrome()) {
1828 // Attempt to initialize TraceMalloc functions
1829 ::JS_DefineFunctions(cx
, aGlobalObj
, TraceMallocFunctions
);
1834 // Attempt to initialize DMD functions
1835 ::JS_DefineFunctions(cx
, aGlobalObj
, DMDFunctions
);
1839 // Attempt to initialize JProf functions
1840 ::JS_DefineFunctions(cx
, aGlobalObj
, JProfFunctions
);
1847 nsJSContext::WillInitializeContext()
1849 mIsInitialized
= false;
1853 nsJSContext::DidInitializeContext()
1855 mIsInitialized
= true;
1859 nsJSContext::IsContextInitialized()
1861 return mIsInitialized
;
1865 nsJSContext::GetProcessingScriptTag()
1867 return mProcessingScriptTag
;
1871 nsJSContext::SetProcessingScriptTag(bool aFlag
)
1873 mProcessingScriptTag
= aFlag
;
1877 FullGCTimerFired(nsITimer
* aTimer
, void* aClosure
)
1879 NS_RELEASE(sFullGCTimer
);
1881 uintptr_t reason
= reinterpret_cast<uintptr_t>(aClosure
);
1882 nsJSContext::GarbageCollectNow(static_cast<JS::gcreason::Reason
>(reason
),
1883 nsJSContext::IncrementalGC
);
1888 nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason
,
1889 IsIncremental aIncremental
,
1890 IsCompartment aCompartment
,
1891 IsShrinking aShrinking
,
1892 int64_t aSliceMillis
)
1894 PROFILER_LABEL("GC", "GarbageCollectNow");
1896 MOZ_ASSERT_IF(aSliceMillis
, aIncremental
== IncrementalGC
);
1899 KillShrinkGCBuffersTimer();
1901 // Reset sPendingLoadCount in case the timer that fired was a
1902 // timer we scheduled due to a normal GC timer firing while
1903 // documents were loading. If this happens we're waiting for a
1904 // document that is taking a long time to load, and we effectively
1905 // ignore the fact that the currently loading documents are still
1906 // loading and move on as if they weren't.
1907 sPendingLoadCount
= 0;
1908 sLoadingInProgress
= false;
1910 if (!nsContentUtils::XPConnect() || !sRuntime
) {
1914 if (sCCLockedOut
&& aIncremental
== IncrementalGC
) {
1915 // We're in the middle of incremental GC. Do another slice.
1916 JS::PrepareForIncrementalGC(sRuntime
);
1917 JS::IncrementalGC(sRuntime
, aReason
, aSliceMillis
);
1921 JS::PrepareForFullGC(sRuntime
);
1922 if (aIncremental
== IncrementalGC
) {
1923 JS::IncrementalGC(sRuntime
, aReason
, aSliceMillis
);
1925 JS::GCForReason(sRuntime
, aReason
);
1931 nsJSContext::ShrinkGCBuffersNow()
1933 PROFILER_LABEL("GC", "ShrinkGCBuffersNow");
1935 KillShrinkGCBuffersTimer();
1937 JS::ShrinkGCBuffers(sRuntime
);
1941 FinishAnyIncrementalGC()
1944 // We're in the middle of an incremental GC, so finish it.
1945 JS::PrepareForIncrementalGC(sRuntime
);
1946 JS::FinishIncrementalGC(sRuntime
, JS::gcreason::CC_FORCED
);
1951 FireForgetSkippable(uint32_t aSuspected
, bool aRemoveChildless
)
1953 PRTime startTime
= PR_Now();
1954 FinishAnyIncrementalGC();
1955 bool earlyForgetSkippable
=
1956 sCleanupsSinceLastGC
< NS_MAJOR_FORGET_SKIPPABLE_CALLS
;
1957 nsCycleCollector_forgetSkippable(aRemoveChildless
, earlyForgetSkippable
);
1958 sPreviousSuspectedCount
= nsCycleCollector_suspectedCount();
1959 ++sCleanupsSinceLastGC
;
1960 PRTime delta
= PR_Now() - startTime
;
1961 if (sMinForgetSkippableTime
> delta
) {
1962 sMinForgetSkippableTime
= delta
;
1964 if (sMaxForgetSkippableTime
< delta
) {
1965 sMaxForgetSkippableTime
= delta
;
1967 sTotalForgetSkippableTime
+= delta
;
1968 sRemovedPurples
+= (aSuspected
- sPreviousSuspectedCount
);
1969 ++sForgetSkippableBeforeCC
;
1974 TimeBetween(PRTime start
, PRTime end
)
1976 MOZ_ASSERT(end
>= start
);
1977 return (uint32_t)(end
- start
) / PR_USEC_PER_MSEC
;
1980 struct CycleCollectorStats
1984 mBeginSliceTime
= 0;
1987 mRanSyncForgetSkippable
= false;
1989 mMaxSkippableDuration
= 0;
1990 mAnyLockedOut
= false;
1993 // Time the current slice began, including any GC finishing.
1994 PRTime mBeginSliceTime
;
1996 // Time the current cycle collection began.
1999 // The longest GC finishing duration for any slice of the current CC.
2000 uint32_t mMaxGCDuration
;
2002 // True if we ran sync forget skippable in any slice of the current CC.
2003 bool mRanSyncForgetSkippable
;
2005 // Number of suspected objects at the start of the current CC.
2006 uint32_t mSuspected
;
2008 // The longest duration spent on sync forget skippable in any slice of the
2010 uint32_t mMaxSkippableDuration
;
2012 // True if we were locked out by the GC in any slice of the current CC.
2016 CycleCollectorStats gCCStats
;
2020 PrepareForCycleCollection(int32_t aExtraForgetSkippableCalls
= 0)
2022 gCCStats
.mBeginSliceTime
= PR_Now();
2024 // Before we begin the cycle collection, make sure there is no active GC.
2027 gCCStats
.mAnyLockedOut
= true;
2028 FinishAnyIncrementalGC();
2029 endGCTime
= PR_Now();
2030 uint32_t gcTime
= TimeBetween(gCCStats
.mBeginSliceTime
, endGCTime
);
2031 gCCStats
.mMaxGCDuration
= std::max(gCCStats
.mMaxGCDuration
, gcTime
);
2033 endGCTime
= gCCStats
.mBeginSliceTime
;
2036 // Run forgetSkippable synchronously to reduce the size of the CC graph. This
2037 // is particularly useful if we recently finished a GC.
2038 if (aExtraForgetSkippableCalls
>= 0) {
2039 bool ranSyncForgetSkippable
= false;
2040 while (sCleanupsSinceLastGC
< NS_MAJOR_FORGET_SKIPPABLE_CALLS
) {
2041 FireForgetSkippable(nsCycleCollector_suspectedCount(), false);
2042 ranSyncForgetSkippable
= true;
2045 for (int32_t i
= 0; i
< aExtraForgetSkippableCalls
; ++i
) {
2046 FireForgetSkippable(nsCycleCollector_suspectedCount(), false);
2047 ranSyncForgetSkippable
= true;
2050 if (ranSyncForgetSkippable
) {
2051 gCCStats
.mMaxSkippableDuration
=
2052 std::max(gCCStats
.mMaxSkippableDuration
, TimeBetween(endGCTime
, PR_Now()));
2053 gCCStats
.mRanSyncForgetSkippable
= true;
2061 nsJSContext::CycleCollectNow(nsICycleCollectorListener
*aListener
,
2062 int32_t aExtraForgetSkippableCalls
)
2064 if (!NS_IsMainThread()) {
2068 PROFILER_LABEL("CC", "CycleCollectNow");
2069 PrepareForCycleCollection(aExtraForgetSkippableCalls
);
2070 nsCycleCollector_collect(aListener
);
2075 nsJSContext::ScheduledCycleCollectNow()
2077 if (!NS_IsMainThread()) {
2081 PROFILER_LABEL("CC", "ScheduledCycleCollectNow");
2082 PrepareForCycleCollection();
2083 nsCycleCollector_scheduledCollect();
2088 nsJSContext::BeginCycleCollectionCallback()
2090 MOZ_ASSERT(NS_IsMainThread());
2092 gCCStats
.mBeginTime
= gCCStats
.mBeginSliceTime
? gCCStats
.mBeginSliceTime
: PR_Now();
2093 gCCStats
.mSuspected
= nsCycleCollector_suspectedCount();
2100 nsJSContext::EndCycleCollectionCallback(CycleCollectorResults
&aResults
)
2102 MOZ_ASSERT(NS_IsMainThread());
2104 sCCollectedWaitingForGC
+= aResults
.mFreedRefCounted
+ aResults
.mFreedGCed
;
2106 // If we collected a substantial amount of cycles, poke the GC since more objects
2107 // might be unreachable now.
2108 if (sCCollectedWaitingForGC
> 250 ||
2109 sLikelyShortLivingObjectsNeedingGC
> 2500 ||
2111 PokeGC(JS::gcreason::CC_WAITING
);
2114 PRTime endCCTime
= PR_Now();
2116 // Log information about the CC via telemetry, JSON and the console.
2117 uint32_t ccNowDuration
= TimeBetween(gCCStats
.mBeginTime
, endCCTime
);
2118 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC
, gCCStats
.mAnyLockedOut
);
2119 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE
, gCCStats
.mRanSyncForgetSkippable
);
2120 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FULL
, ccNowDuration
);
2122 if (sLastCCEndTime
) {
2123 uint32_t timeBetween
= TimeBetween(sLastCCEndTime
, gCCStats
.mBeginTime
);
2124 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN
, timeBetween
);
2126 sLastCCEndTime
= endCCTime
;
2128 Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX
,
2129 sMaxForgetSkippableTime
/ PR_USEC_PER_MSEC
);
2131 PRTime delta
= GetCollectionTimeDelta();
2133 uint32_t cleanups
= sForgetSkippableBeforeCC
? sForgetSkippableBeforeCC
: 1;
2134 uint32_t minForgetSkippableTime
= (sMinForgetSkippableTime
== UINT32_MAX
)
2135 ? 0 : sMinForgetSkippableTime
;
2137 if (sPostGCEventsToConsole
) {
2139 if (aResults
.mMergedZones
) {
2140 mergeMsg
.AssignLiteral(" merged");
2144 if (aResults
.mForcedGC
) {
2145 gcMsg
.AssignLiteral(", forced a GC");
2148 NS_NAMED_MULTILINE_LITERAL_STRING(kFmt
,
2149 MOZ_UTF16("CC(T+%.1f) duration: %lums, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu|%lu waiting for GC)%s\n")
2150 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"));
2152 msg
.Adopt(nsTextFormatter::smprintf(kFmt
.get(), double(delta
) / PR_USEC_PER_SEC
,
2153 ccNowDuration
, gCCStats
.mSuspected
,
2154 aResults
.mVisitedRefCounted
, aResults
.mVisitedGCed
, mergeMsg
.get(),
2155 aResults
.mFreedRefCounted
, aResults
.mFreedGCed
,
2156 sCCollectedWaitingForGC
, sLikelyShortLivingObjectsNeedingGC
,
2158 sForgetSkippableBeforeCC
,
2159 minForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2160 sMaxForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2161 (sTotalForgetSkippableTime
/ cleanups
) /
2163 sTotalForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2164 gCCStats
.mMaxSkippableDuration
, sRemovedPurples
));
2165 nsCOMPtr
<nsIConsoleService
> cs
=
2166 do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
2168 cs
->LogStringMessage(msg
.get());
2172 if (sPostGCEventsToObserver
) {
2173 NS_NAMED_MULTILINE_LITERAL_STRING(kJSONFmt
,
2174 MOZ_UTF16("{ \"timestamp\": %llu, ")
2175 MOZ_UTF16("\"duration\": %llu, ")
2176 MOZ_UTF16("\"max_finish_gc_duration\": %llu, ")
2177 MOZ_UTF16("\"max_sync_skippable_duration\": %llu, ")
2178 MOZ_UTF16("\"suspected\": %lu, ")
2179 MOZ_UTF16("\"visited\": { ")
2180 MOZ_UTF16("\"RCed\": %lu, ")
2181 MOZ_UTF16("\"GCed\": %lu }, ")
2182 MOZ_UTF16("\"collected\": { ")
2183 MOZ_UTF16("\"RCed\": %lu, ")
2184 MOZ_UTF16("\"GCed\": %lu }, ")
2185 MOZ_UTF16("\"waiting_for_gc\": %lu, ")
2186 MOZ_UTF16("\"short_living_objects_waiting_for_gc\": %lu, ")
2187 MOZ_UTF16("\"forced_gc\": %d, ")
2188 MOZ_UTF16("\"forget_skippable\": { ")
2189 MOZ_UTF16("\"times_before_cc\": %lu, ")
2190 MOZ_UTF16("\"min\": %lu, ")
2191 MOZ_UTF16("\"max\": %lu, ")
2192 MOZ_UTF16("\"avg\": %lu, ")
2193 MOZ_UTF16("\"total\": %lu, ")
2194 MOZ_UTF16("\"removed\": %lu } ")
2197 json
.Adopt(nsTextFormatter::smprintf(kJSONFmt
.get(), endCCTime
,
2198 ccNowDuration
, gCCStats
.mMaxGCDuration
,
2199 gCCStats
.mMaxSkippableDuration
,
2200 gCCStats
.mSuspected
,
2201 aResults
.mVisitedRefCounted
, aResults
.mVisitedGCed
,
2202 aResults
.mFreedRefCounted
, aResults
.mFreedGCed
,
2203 sCCollectedWaitingForGC
,
2204 sLikelyShortLivingObjectsNeedingGC
,
2206 sForgetSkippableBeforeCC
,
2207 minForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2208 sMaxForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2209 (sTotalForgetSkippableTime
/ cleanups
) /
2211 sTotalForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2213 nsCOMPtr
<nsIObserverService
> observerService
= mozilla::services::GetObserverService();
2214 if (observerService
) {
2215 observerService
->NotifyObservers(nullptr, "cycle-collection-statistics", json
.get());
2219 // Update global state to indicate we have just run a cycle collection.
2220 sMinForgetSkippableTime
= UINT32_MAX
;
2221 sMaxForgetSkippableTime
= 0;
2222 sTotalForgetSkippableTime
= 0;
2223 sRemovedPurples
= 0;
2224 sForgetSkippableBeforeCC
= 0;
2225 sNeedsFullCC
= false;
2226 sNeedsGCAfterCC
= false;
2232 InterSliceGCTimerFired(nsITimer
*aTimer
, void *aClosure
)
2234 NS_RELEASE(sInterSliceGCTimer
);
2235 nsJSContext::GarbageCollectNow(JS::gcreason::INTER_SLICE_GC
,
2236 nsJSContext::IncrementalGC
,
2237 nsJSContext::CompartmentGC
,
2238 nsJSContext::NonShrinkingGC
,
2239 NS_INTERSLICE_GC_BUDGET
);
2244 GCTimerFired(nsITimer
*aTimer
, void *aClosure
)
2246 NS_RELEASE(sGCTimer
);
2248 uintptr_t reason
= reinterpret_cast<uintptr_t>(aClosure
);
2249 nsJSContext::GarbageCollectNow(static_cast<JS::gcreason::Reason
>(reason
),
2250 nsJSContext::IncrementalGC
,
2251 nsJSContext::CompartmentGC
);
2255 ShrinkGCBuffersTimerFired(nsITimer
*aTimer
, void *aClosure
)
2257 NS_RELEASE(sShrinkGCBuffersTimer
);
2259 nsJSContext::ShrinkGCBuffersNow();
2263 ShouldTriggerCC(uint32_t aSuspected
)
2265 return sNeedsFullCC
||
2266 aSuspected
> NS_CC_PURPLE_LIMIT
||
2267 (aSuspected
> NS_CC_FORCED_PURPLE_LIMIT
&&
2268 sLastCCEndTime
+ NS_CC_FORCED
< PR_Now());
2272 CCTimerFired(nsITimer
*aTimer
, void *aClosure
)
2278 static uint32_t ccDelay
= NS_CC_DELAY
;
2280 ccDelay
= NS_CC_DELAY
/ 3;
2282 PRTime now
= PR_Now();
2283 if (sCCLockedOutTime
== 0) {
2284 // Reset sCCTimerFireCount so that we run forgetSkippable
2285 // often enough before CC. Because of reduced ccDelay
2286 // forgetSkippable will be called just a few times.
2287 // NS_MAX_CC_LOCKEDOUT_TIME limit guarantees that we end up calling
2288 // forgetSkippable and CycleCollectNow eventually.
2289 sCCTimerFireCount
= 0;
2290 sCCLockedOutTime
= now
;
2293 if (now
- sCCLockedOutTime
< NS_MAX_CC_LOCKEDOUT_TIME
) {
2298 ++sCCTimerFireCount
;
2300 // During early timer fires, we only run forgetSkippable. During the first
2301 // late timer fire, we decide if we are going to have a second and final
2302 // late timer fire, where we may run the CC.
2303 const uint32_t numEarlyTimerFires
= ccDelay
/ NS_CC_SKIPPABLE_DELAY
- 2;
2304 bool isLateTimerFire
= sCCTimerFireCount
> numEarlyTimerFires
;
2305 uint32_t suspected
= nsCycleCollector_suspectedCount();
2306 if (isLateTimerFire
&& ShouldTriggerCC(suspected
)) {
2307 if (sCCTimerFireCount
== numEarlyTimerFires
+ 1) {
2308 FireForgetSkippable(suspected
, true);
2309 if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
2310 // Our efforts to avoid a CC have failed, so we return to let the
2311 // timer fire once more to trigger a CC.
2315 // We are in the final timer fire and still meet the conditions for
2316 // triggering a CC. Let CycleCollectNow finish the current IGC, if any,
2317 // because that will allow us to include the GC time in the CC pause.
2318 nsJSContext::ScheduledCycleCollectNow();
2320 } else if ((sPreviousSuspectedCount
+ 100) <= suspected
) {
2321 // Only do a forget skippable if there are more than a few new objects.
2322 FireForgetSkippable(suspected
, false);
2325 if (isLateTimerFire
) {
2326 ccDelay
= NS_CC_DELAY
;
2328 // We have either just run the CC or decided we don't want to run the CC
2329 // next time, so kill the timer.
2330 sPreviousSuspectedCount
= 0;
2331 nsJSContext::KillCCTimer();
2337 nsJSContext::CleanupsSinceLastGC()
2339 return sCleanupsSinceLastGC
;
2344 nsJSContext::LoadStart()
2346 sLoadingInProgress
= true;
2347 ++sPendingLoadCount
;
2352 nsJSContext::LoadEnd()
2354 if (!sLoadingInProgress
)
2357 // sPendingLoadCount is not a well managed load counter (and doesn't
2358 // need to be), so make sure we don't make it wrap backwards here.
2359 if (sPendingLoadCount
> 0) {
2360 --sPendingLoadCount
;
2364 // Its probably a good idea to GC soon since we have finished loading.
2365 sLoadingInProgress
= false;
2366 PokeGC(JS::gcreason::LOAD_END
);
2371 nsJSContext::PokeGC(JS::gcreason::Reason aReason
, int aDelay
)
2373 if (sGCTimer
|| sInterSliceGCTimer
|| sShuttingDown
) {
2374 // There's already a timer for GC'ing, just return
2379 // Make sure CC is called...
2380 sNeedsFullCC
= true;
2382 sNeedsGCAfterCC
= true;
2386 CallCreateInstance("@mozilla.org/timer;1", &sGCTimer
);
2389 // Failed to create timer (probably because we're in XPCOM shutdown)
2393 static bool first
= true;
2395 sGCTimer
->InitWithFuncCallback(GCTimerFired
, reinterpret_cast<void *>(aReason
),
2401 nsITimer::TYPE_ONE_SHOT
);
2408 nsJSContext::PokeShrinkGCBuffers()
2410 if (sShrinkGCBuffersTimer
|| sShuttingDown
) {
2414 CallCreateInstance("@mozilla.org/timer;1", &sShrinkGCBuffersTimer
);
2416 if (!sShrinkGCBuffersTimer
) {
2417 // Failed to create timer (probably because we're in XPCOM shutdown)
2421 sShrinkGCBuffersTimer
->InitWithFuncCallback(ShrinkGCBuffersTimerFired
, nullptr,
2422 NS_SHRINK_GC_BUFFERS_DELAY
,
2423 nsITimer::TYPE_ONE_SHOT
);
2428 nsJSContext::MaybePokeCC()
2430 if (sCCTimer
|| sShuttingDown
|| !sHasRunGC
) {
2434 if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
2435 sCCTimerFireCount
= 0;
2436 CallCreateInstance("@mozilla.org/timer;1", &sCCTimer
);
2440 // We can kill some objects before running forgetSkippable.
2441 nsCycleCollector_dispatchDeferredDeletion();
2443 sCCTimer
->InitWithFuncCallback(CCTimerFired
, nullptr,
2444 NS_CC_SKIPPABLE_DELAY
,
2445 nsITimer::TYPE_REPEATING_SLACK
);
2451 nsJSContext::KillGCTimer()
2456 NS_RELEASE(sGCTimer
);
2461 nsJSContext::KillFullGCTimer()
2464 sFullGCTimer
->Cancel();
2465 NS_RELEASE(sFullGCTimer
);
2470 nsJSContext::KillInterSliceGCTimer()
2472 if (sInterSliceGCTimer
) {
2473 sInterSliceGCTimer
->Cancel();
2474 NS_RELEASE(sInterSliceGCTimer
);
2480 nsJSContext::KillShrinkGCBuffersTimer()
2482 if (sShrinkGCBuffersTimer
) {
2483 sShrinkGCBuffersTimer
->Cancel();
2485 NS_RELEASE(sShrinkGCBuffersTimer
);
2491 nsJSContext::KillCCTimer()
2493 sCCLockedOutTime
= 0;
2498 NS_RELEASE(sCCTimer
);
2503 nsJSContext::GC(JS::gcreason::Reason aReason
)
2508 class NotifyGCEndRunnable
: public nsRunnable
2513 NotifyGCEndRunnable(const nsString
& aMessage
) : mMessage(aMessage
) {}
2519 NotifyGCEndRunnable::Run()
2521 MOZ_ASSERT(NS_IsMainThread());
2523 nsCOMPtr
<nsIObserverService
> observerService
= mozilla::services::GetObserverService();
2524 if (!observerService
) {
2528 const jschar oomMsg
[3] = { '{', '}', 0 };
2529 const jschar
*toSend
= mMessage
.get() ? mMessage
.get() : oomMsg
;
2530 observerService
->NotifyObservers(nullptr, "garbage-collection-statistics", toSend
);
2536 DOMGCSliceCallback(JSRuntime
*aRt
, JS::GCProgress aProgress
, const JS::GCDescription
&aDesc
)
2538 NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread");
2540 if (aProgress
== JS::GC_CYCLE_END
) {
2541 PRTime delta
= GetCollectionTimeDelta();
2543 if (sPostGCEventsToConsole
) {
2544 NS_NAMED_LITERAL_STRING(kFmt
, "GC(T+%.1f) ");
2545 nsString prefix
, gcstats
;
2546 gcstats
.Adopt(aDesc
.formatMessage(aRt
));
2547 prefix
.Adopt(nsTextFormatter::smprintf(kFmt
.get(),
2548 double(delta
) / PR_USEC_PER_SEC
));
2549 nsString msg
= prefix
+ gcstats
;
2550 nsCOMPtr
<nsIConsoleService
> cs
= do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
2552 cs
->LogStringMessage(msg
.get());
2556 if (sPostGCEventsToObserver
) {
2558 json
.Adopt(aDesc
.formatJSON(aRt
, PR_Now()));
2559 nsRefPtr
<NotifyGCEndRunnable
> notify
= new NotifyGCEndRunnable(json
);
2560 NS_DispatchToMainThread(notify
);
2564 // Prevent cycle collections and shrinking during incremental GC.
2565 if (aProgress
== JS::GC_CYCLE_BEGIN
) {
2566 sCCLockedOut
= true;
2567 nsJSContext::KillShrinkGCBuffersTimer();
2568 } else if (aProgress
== JS::GC_CYCLE_END
) {
2569 sCCLockedOut
= false;
2572 // The GC has more work to do, so schedule another GC slice.
2573 if (aProgress
== JS::GC_SLICE_END
) {
2574 nsJSContext::KillInterSliceGCTimer();
2575 if (!sShuttingDown
) {
2576 CallCreateInstance("@mozilla.org/timer;1", &sInterSliceGCTimer
);
2577 sInterSliceGCTimer
->InitWithFuncCallback(InterSliceGCTimerFired
,
2579 NS_INTERSLICE_GC_DELAY
,
2580 nsITimer::TYPE_ONE_SHOT
);
2584 if (aProgress
== JS::GC_CYCLE_END
) {
2585 // May need to kill the inter-slice GC timer
2586 nsJSContext::KillInterSliceGCTimer();
2588 sCCollectedWaitingForGC
= 0;
2589 sLikelyShortLivingObjectsNeedingGC
= 0;
2590 sCleanupsSinceLastGC
= 0;
2591 sNeedsFullCC
= true;
2593 nsJSContext::MaybePokeCC();
2595 if (aDesc
.isCompartment_
) {
2596 if (!sFullGCTimer
&& !sShuttingDown
) {
2597 CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer
);
2598 JS::gcreason::Reason reason
= JS::gcreason::FULL_GC_TIMER
;
2599 sFullGCTimer
->InitWithFuncCallback(FullGCTimerFired
,
2600 reinterpret_cast<void *>(reason
),
2602 nsITimer::TYPE_ONE_SHOT
);
2605 nsJSContext::KillFullGCTimer();
2607 // Avoid shrinking during heavy activity, which is suggested by
2609 nsJSContext::PokeShrinkGCBuffers();
2613 if ((aProgress
== JS::GC_SLICE_END
|| aProgress
== JS::GC_CYCLE_END
) &&
2614 ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
2615 nsCycleCollector_dispatchDeferredDeletion();
2618 if (sPrevGCSliceCallback
)
2619 (*sPrevGCSliceCallback
)(aRt
, aProgress
, aDesc
);
2623 nsJSContext::ReportPendingException()
2625 if (mIsInitialized
) {
2626 nsJSUtils::ReportPendingException(mContext
);
2631 nsJSContext::SetWindowProxy(JS::Handle
<JSObject
*> aWindowProxy
)
2633 mWindowProxy
= aWindowProxy
;
2637 nsJSContext::GetWindowProxy()
2639 JSObject
* windowProxy
= GetWindowProxyPreserveColor();
2641 JS::ExposeObjectToActiveJS(windowProxy
);
2648 nsJSContext::GetWindowProxyPreserveColor()
2650 return mWindowProxy
;
2654 nsJSContext::LikelyShortLivingObjectCreated()
2656 ++sLikelyShortLivingObjectsNeedingGC
;
2660 mozilla::dom::StartupJSEnvironment()
2662 // initialize all our statics, so that we can restart XPCOM
2663 sGCTimer
= sFullGCTimer
= sCCTimer
= nullptr;
2664 sCCLockedOut
= false;
2665 sCCLockedOutTime
= 0;
2668 sPendingLoadCount
= 0;
2669 sLoadingInProgress
= false;
2670 sCCollectedWaitingForGC
= 0;
2671 sLikelyShortLivingObjectsNeedingGC
= 0;
2672 sPostGCEventsToConsole
= false;
2673 sNeedsFullCC
= false;
2674 sNeedsGCAfterCC
= false;
2675 gNameSpaceManager
= nullptr;
2676 sRuntimeService
= nullptr;
2678 sIsInitialized
= false;
2679 sDidShutdown
= false;
2680 sShuttingDown
= false;
2682 sSecurityManager
= nullptr;
2687 ReportAllJSExceptionsPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2689 bool reportAll
= Preferences::GetBool(aPrefName
, false);
2690 nsContentUtils::XPConnect()->SetReportAllJSExceptions(reportAll
);
2695 SetMemoryHighWaterMarkPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2697 int32_t highwatermark
= Preferences::GetInt(aPrefName
, 128);
2699 JS_SetGCParameter(sRuntime
, JSGC_MAX_MALLOC_BYTES
,
2700 highwatermark
* 1024L * 1024L);
2705 SetMemoryMaxPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2707 int32_t pref
= Preferences::GetInt(aPrefName
, -1);
2708 // handle overflow and negative pref values
2709 uint32_t max
= (pref
<= 0 || pref
>= 0x1000) ? -1 : (uint32_t)pref
* 1024 * 1024;
2710 JS_SetGCParameter(sRuntime
, JSGC_MAX_BYTES
, max
);
2715 SetMemoryGCModePrefChangedCallback(const char* aPrefName
, void* aClosure
)
2717 bool enableCompartmentGC
= Preferences::GetBool("javascript.options.mem.gc_per_compartment");
2718 bool enableIncrementalGC
= Preferences::GetBool("javascript.options.mem.gc_incremental");
2720 if (enableIncrementalGC
) {
2721 mode
= JSGC_MODE_INCREMENTAL
;
2722 } else if (enableCompartmentGC
) {
2723 mode
= JSGC_MODE_COMPARTMENT
;
2725 mode
= JSGC_MODE_GLOBAL
;
2727 JS_SetGCParameter(sRuntime
, JSGC_MODE
, mode
);
2732 SetMemoryGCSliceTimePrefChangedCallback(const char* aPrefName
, void* aClosure
)
2734 int32_t pref
= Preferences::GetInt(aPrefName
, -1);
2735 // handle overflow and negative pref values
2736 if (pref
> 0 && pref
< 100000)
2737 JS_SetGCParameter(sRuntime
, JSGC_SLICE_TIME_BUDGET
, pref
);
2742 SetMemoryGCPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2744 int32_t pref
= Preferences::GetInt(aPrefName
, -1);
2745 // handle overflow and negative pref values
2746 if (pref
>= 0 && pref
< 10000)
2747 JS_SetGCParameter(sRuntime
, (JSGCParamKey
)(intptr_t)aClosure
, pref
);
2752 SetMemoryGCDynamicHeapGrowthPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2754 bool pref
= Preferences::GetBool(aPrefName
);
2755 JS_SetGCParameter(sRuntime
, JSGC_DYNAMIC_HEAP_GROWTH
, pref
);
2760 SetMemoryGCDynamicMarkSlicePrefChangedCallback(const char* aPrefName
, void* aClosure
)
2762 bool pref
= Preferences::GetBool(aPrefName
);
2763 JS_SetGCParameter(sRuntime
, JSGC_DYNAMIC_MARK_SLICE
, pref
);
2768 NS_DOMReadStructuredClone(JSContext
* cx
,
2769 JSStructuredCloneReader
* reader
,
2774 if (tag
== SCTAG_DOM_IMAGEDATA
) {
2775 // Read the information out of the stream.
2776 uint32_t width
, height
;
2777 JS::Rooted
<JS::Value
> dataArray(cx
);
2778 if (!JS_ReadUint32Pair(reader
, &width
, &height
) ||
2779 !JS_ReadTypedArray(reader
, dataArray
.address())) {
2782 MOZ_ASSERT(dataArray
.isObject());
2784 // Construct the ImageData.
2785 nsRefPtr
<ImageData
> imageData
= new ImageData(width
, height
,
2786 dataArray
.toObject());
2787 // Wrap it in a JS::Value.
2788 JS::Rooted
<JSObject
*> global(cx
, JS::CurrentGlobalOrNull(cx
));
2792 return imageData
->WrapObject(cx
, global
);
2795 // Don't know what this is. Bail.
2796 xpc::Throw(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
2801 NS_DOMWriteStructuredClone(JSContext
* cx
,
2802 JSStructuredCloneWriter
* writer
,
2803 JS::Handle
<JSObject
*> obj
,
2806 ImageData
* imageData
;
2807 nsresult rv
= UNWRAP_OBJECT(ImageData
, obj
, imageData
);
2808 if (NS_FAILED(rv
)) {
2809 // Don't know what this is. Bail.
2810 xpc::Throw(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
2814 // Prepare the ImageData internals.
2815 uint32_t width
= imageData
->Width();
2816 uint32_t height
= imageData
->Height();
2817 JS::Rooted
<JSObject
*> dataArray(cx
, imageData
->GetDataObject());
2819 // Write the internals to the stream.
2820 JSAutoCompartment
ac(cx
, dataArray
);
2821 return JS_WriteUint32Pair(writer
, SCTAG_DOM_IMAGEDATA
, 0) &&
2822 JS_WriteUint32Pair(writer
, width
, height
) &&
2823 JS_WriteTypedArray(writer
, JS::ObjectValue(*dataArray
));
2827 NS_DOMStructuredCloneError(JSContext
* cx
,
2830 // We don't currently support any extensions to structured cloning.
2831 xpc::Throw(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
2834 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID
, NS_DOM_SCRIPT_OBJECT_FACTORY_CID
);
2837 nsJSContext::EnsureStatics()
2839 if (sIsInitialized
) {
2840 if (!nsContentUtils::XPConnect()) {
2846 nsresult rv
= CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
,
2848 if (NS_FAILED(rv
)) {
2852 rv
= CallGetService(kJSRuntimeServiceContractID
, &sRuntimeService
);
2853 if (NS_FAILED(rv
)) {
2857 rv
= sRuntimeService
->GetRuntime(&sRuntime
);
2858 if (NS_FAILED(rv
)) {
2862 // Let's make sure that our main thread is the same as the xpcom main thread.
2863 MOZ_ASSERT(NS_IsMainThread());
2865 sPrevGCSliceCallback
= JS::SetGCSliceCallback(sRuntime
, DOMGCSliceCallback
);
2867 // Set up the structured clone callbacks.
2868 static JSStructuredCloneCallbacks cloneCallbacks
= {
2869 NS_DOMReadStructuredClone
,
2870 NS_DOMWriteStructuredClone
,
2871 NS_DOMStructuredCloneError
2873 JS_SetStructuredCloneCallbacks(sRuntime
, &cloneCallbacks
);
2875 static js::DOMCallbacks DOMcallbacks
= {
2876 InstanceClassHasProtoAtDepth
2878 SetDOMCallbacks(sRuntime
, &DOMcallbacks
);
2880 // Set up the asm.js cache callbacks
2881 static JS::AsmJSCacheOps asmJSCacheOps
= {
2882 asmjscache::OpenEntryForRead
,
2883 asmjscache::CloseEntryForRead
,
2884 asmjscache::OpenEntryForWrite
,
2885 asmjscache::CloseEntryForWrite
,
2886 asmjscache::GetBuildId
2888 JS::SetAsmJSCacheOps(sRuntime
, &asmJSCacheOps
);
2890 // Set these global xpconnect options...
2891 Preferences::RegisterCallbackAndCall(ReportAllJSExceptionsPrefChangedCallback
,
2892 "dom.report_all_js_exceptions");
2894 Preferences::RegisterCallbackAndCall(SetMemoryHighWaterMarkPrefChangedCallback
,
2895 "javascript.options.mem.high_water_mark");
2897 Preferences::RegisterCallbackAndCall(SetMemoryMaxPrefChangedCallback
,
2898 "javascript.options.mem.max");
2900 Preferences::RegisterCallbackAndCall(SetMemoryGCModePrefChangedCallback
,
2901 "javascript.options.mem.gc_per_compartment");
2903 Preferences::RegisterCallbackAndCall(SetMemoryGCModePrefChangedCallback
,
2904 "javascript.options.mem.gc_incremental");
2906 Preferences::RegisterCallbackAndCall(SetMemoryGCSliceTimePrefChangedCallback
,
2907 "javascript.options.mem.gc_incremental_slice_ms");
2909 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2910 "javascript.options.mem.gc_high_frequency_time_limit_ms",
2911 (void *)JSGC_HIGH_FREQUENCY_TIME_LIMIT
);
2913 Preferences::RegisterCallbackAndCall(SetMemoryGCDynamicMarkSlicePrefChangedCallback
,
2914 "javascript.options.mem.gc_dynamic_mark_slice");
2916 Preferences::RegisterCallbackAndCall(SetMemoryGCDynamicHeapGrowthPrefChangedCallback
,
2917 "javascript.options.mem.gc_dynamic_heap_growth");
2919 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2920 "javascript.options.mem.gc_low_frequency_heap_growth",
2921 (void *)JSGC_LOW_FREQUENCY_HEAP_GROWTH
);
2923 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2924 "javascript.options.mem.gc_high_frequency_heap_growth_min",
2925 (void *)JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN
);
2927 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2928 "javascript.options.mem.gc_high_frequency_heap_growth_max",
2929 (void *)JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX
);
2931 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2932 "javascript.options.mem.gc_high_frequency_low_limit_mb",
2933 (void *)JSGC_HIGH_FREQUENCY_LOW_LIMIT
);
2935 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2936 "javascript.options.mem.gc_high_frequency_high_limit_mb",
2937 (void *)JSGC_HIGH_FREQUENCY_HIGH_LIMIT
);
2939 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2940 "javascript.options.mem.gc_allocation_threshold_mb",
2941 (void *)JSGC_ALLOCATION_THRESHOLD
);
2943 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2944 "javascript.options.mem.gc_decommit_threshold_mb",
2945 (void *)JSGC_DECOMMIT_THRESHOLD
);
2947 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
2952 Preferences::AddBoolVarCache(&sGCOnMemoryPressure
,
2953 "javascript.options.gc_on_memory_pressure",
2956 nsIObserver
* observer
= new nsJSEnvironmentObserver();
2957 obs
->AddObserver(observer
, "memory-pressure", false);
2958 obs
->AddObserver(observer
, "quit-application", false);
2960 // Bug 907848 - We need to explicitly get the nsIDOMScriptObjectFactory
2961 // service in order to force its constructor to run, which registers a
2962 // shutdown observer. It would be nice to make this more explicit and less
2964 nsCOMPtr
<nsIDOMScriptObjectFactory
> factory
= do_GetService(kDOMScriptObjectFactoryCID
);
2969 sIsInitialized
= true;
2972 nsScriptNameSpaceManager
*
2973 mozilla::dom::GetNameSpaceManager()
2978 if (!gNameSpaceManager
) {
2979 gNameSpaceManager
= new nsScriptNameSpaceManager
;
2980 NS_ADDREF(gNameSpaceManager
);
2982 nsresult rv
= gNameSpaceManager
->Init();
2983 NS_ENSURE_SUCCESS(rv
, nullptr);
2986 return gNameSpaceManager
;
2990 mozilla::dom::ShutdownJSEnvironment()
2994 NS_IF_RELEASE(gNameSpaceManager
);
2996 if (!sContextCount
) {
2997 // We're being shutdown, and there are no more contexts
2998 // alive, release the JS runtime service and the security manager.
3000 NS_IF_RELEASE(sRuntimeService
);
3001 NS_IF_RELEASE(sSecurityManager
);
3004 sShuttingDown
= true;
3005 sDidShutdown
= true;
3008 // A fast-array class for JS. This class supports both nsIJSScriptArray and
3009 // nsIArray. If it is JS itself providing and consuming this class, all work
3010 // can be done via nsIJSScriptArray, and avoid the conversion of elements
3011 // to/from nsISupports.
3012 // When consumed by non-JS (eg, another script language), conversion is done
3014 class nsJSArgArray MOZ_FINAL
: public nsIJSArgArray
{
3016 nsJSArgArray(JSContext
*aContext
, uint32_t argc
, JS::Value
*argv
,
3020 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
3021 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray
,
3028 nsresult
GetArgs(uint32_t *argc
, void **argv
);
3030 void ReleaseJSObjects();
3033 JSContext
*mContext
;
3034 JS::Heap
<JS::Value
> *mArgv
;
3038 nsJSArgArray::nsJSArgArray(JSContext
*aContext
, uint32_t argc
, JS::Value
*argv
,
3044 // copy the array - we don't know its lifetime, and ours is tied to xpcom
3047 static const fallible_t fallible
= fallible_t();
3048 mArgv
= new (fallible
) JS::Heap
<JS::Value
>[argc
];
3050 *prv
= NS_ERROR_OUT_OF_MEMORY
;
3055 // Callers are allowed to pass in a null argv even for argc > 0. They can
3056 // then use GetArgs to initialize the values.
3058 for (uint32_t i
= 0; i
< argc
; ++i
)
3063 mozilla::HoldJSObjects(this);
3069 nsJSArgArray::~nsJSArgArray()
3075 nsJSArgArray::ReleaseJSObjects()
3082 mozilla::DropJSObjects(this);
3086 // QueryInterface implementation for nsJSArgArray
3087 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSArgArray
)
3089 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSArgArray
)
3090 tmp
->ReleaseJSObjects();
3091 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
3092 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray
)
3093 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
3094 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
3096 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray
)
3098 for (uint32_t i
= 0; i
< tmp
->mArgc
; ++i
) {
3099 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mArgv
[i
])
3102 NS_IMPL_CYCLE_COLLECTION_TRACE_END
3104 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSArgArray
)
3105 NS_INTERFACE_MAP_ENTRY(nsIArray
)
3106 NS_INTERFACE_MAP_ENTRY(nsIJSArgArray
)
3107 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIJSArgArray
)
3108 NS_INTERFACE_MAP_END
3110 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSArgArray
)
3111 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSArgArray
)
3114 nsJSArgArray::GetArgs(uint32_t *argc
, void **argv
)
3116 *argv
= (void *)mArgv
;
3122 NS_IMETHODIMP
nsJSArgArray::GetLength(uint32_t *aLength
)
3128 /* void queryElementAt (in unsigned long index, in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
3129 NS_IMETHODIMP
nsJSArgArray::QueryElementAt(uint32_t index
, const nsIID
& uuid
, void * *result
)
3133 return NS_ERROR_INVALID_ARG
;
3135 if (uuid
.Equals(NS_GET_IID(nsIVariant
)) || uuid
.Equals(NS_GET_IID(nsISupports
))) {
3136 return nsContentUtils::XPConnect()->JSToVariant(mContext
, mArgv
[index
],
3137 (nsIVariant
**)result
);
3139 NS_WARNING("nsJSArgArray only handles nsIVariant");
3140 return NS_ERROR_NO_INTERFACE
;
3143 /* unsigned long indexOf (in unsigned long startIndex, in nsISupports element); */
3144 NS_IMETHODIMP
nsJSArgArray::IndexOf(uint32_t startIndex
, nsISupports
*element
, uint32_t *_retval
)
3146 return NS_ERROR_NOT_IMPLEMENTED
;
3149 /* nsISimpleEnumerator enumerate (); */
3150 NS_IMETHODIMP
nsJSArgArray::Enumerate(nsISimpleEnumerator
**_retval
)
3152 return NS_ERROR_NOT_IMPLEMENTED
;
3155 // The factory function
3156 nsresult
NS_CreateJSArgv(JSContext
*aContext
, uint32_t argc
, void *argv
,
3157 nsIJSArgArray
**aArray
)
3160 nsJSArgArray
*ret
= new nsJSArgArray(aContext
, argc
,
3161 static_cast<JS::Value
*>(argv
), &rv
);
3163 return NS_ERROR_OUT_OF_MEMORY
;
3164 if (NS_FAILED(rv
)) {
3168 return ret
->QueryInterface(NS_GET_IID(nsIArray
), (void **)aArray
);