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"
31 #include "nsGUIEvent.h"
34 #include "nsContentUtils.h"
35 #include "nsCxPusher.h"
36 #include "nsEventDispatcher.h"
37 #include "nsIContent.h"
38 #include "nsCycleCollector.h"
39 #include "nsNetUtil.h"
40 #include "nsXPCOMCIDInternal.h"
41 #include "nsIXULRuntime.h"
42 #include "nsTextFormatter.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/dom/ImageData.h"
57 #include "mozilla/dom/ImageDataBinding.h"
58 #include "nsAXPCNativeCallContext.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/CanvasRenderingContext2DBinding.h"
83 #include "mozilla/CycleCollectedJSRuntime.h"
85 #include "nsCycleCollectionNoteRootCallback.h"
86 #include "GeckoProfiler.h"
88 using namespace mozilla
;
89 using namespace mozilla::dom
;
91 const size_t gStackSize
= 8192;
94 static PRLogModuleInfo
* gJSDiagnostics
;
97 // Thank you Microsoft!
102 #define NS_SHRINK_GC_BUFFERS_DELAY 4000 // ms
104 // The amount of time we wait from the first request to GC to actually
105 // doing the first GC.
106 #define NS_FIRST_GC_DELAY 10000 // ms
108 #define NS_FULL_GC_DELAY 60000 // ms
110 // Maximum amount of time that should elapse between incremental GC slices
111 #define NS_INTERSLICE_GC_DELAY 100 // ms
113 // If we haven't painted in 100ms, we allow for a longer GC budget
114 #define NS_INTERSLICE_GC_BUDGET 40 // ms
116 // The amount of time we wait between a request to CC (after GC ran)
117 // and doing the actual CC.
118 #define NS_CC_DELAY 6000 // ms
120 #define NS_CC_SKIPPABLE_DELAY 400 // ms
122 // Force a CC after this long if there's more than NS_CC_FORCED_PURPLE_LIMIT
123 // objects in the purple buffer.
124 #define NS_CC_FORCED (2 * 60 * PR_USEC_PER_SEC) // 2 min
125 #define NS_CC_FORCED_PURPLE_LIMIT 10
127 // Don't allow an incremental GC to lock out the CC for too long.
128 #define NS_MAX_CC_LOCKEDOUT_TIME (15 * PR_USEC_PER_SEC) // 15 seconds
130 // Trigger a CC if the purple buffer exceeds this size when we check it.
131 #define NS_CC_PURPLE_LIMIT 200
133 #define JAVASCRIPT nsIProgrammingLanguage::JAVASCRIPT
135 // Large value used to specify that a script should run essentially forever
136 #define NS_UNLIMITED_SCRIPT_RUNTIME (0x40000000LL << 32)
138 #define NS_MAJOR_FORGET_SKIPPABLE_CALLS 2
140 // if you add statics here, add them to the list in StartupJSEnvironment
142 static nsITimer
*sGCTimer
;
143 static nsITimer
*sShrinkGCBuffersTimer
;
144 static nsITimer
*sCCTimer
;
145 static nsITimer
*sFullGCTimer
;
146 static nsITimer
*sInterSliceGCTimer
;
148 static PRTime sLastCCEndTime
;
150 static bool sCCLockedOut
;
151 static PRTime sCCLockedOutTime
;
153 static JS::GCSliceCallback sPrevGCSliceCallback
;
155 static bool sHasRunGC
;
157 // The number of currently pending document loads. This count isn't
158 // guaranteed to always reflect reality and can't easily as we don't
159 // have an easy place to know when a load ends or is interrupted in
160 // all cases. This counter also gets reset if we end up GC'ing while
161 // we're waiting for a slow page to load. IOW, this count may be 0
162 // even when there are pending loads.
163 static uint32_t sPendingLoadCount
;
164 static bool sLoadingInProgress
;
166 static uint32_t sCCollectedWaitingForGC
;
167 static uint32_t sLikelyShortLivingObjectsNeedingGC
;
168 static bool sPostGCEventsToConsole
;
169 static bool sPostGCEventsToObserver
;
170 static uint32_t sCCTimerFireCount
= 0;
171 static uint32_t sMinForgetSkippableTime
= UINT32_MAX
;
172 static uint32_t sMaxForgetSkippableTime
= 0;
173 static uint32_t sTotalForgetSkippableTime
= 0;
174 static uint32_t sRemovedPurples
= 0;
175 static uint32_t sForgetSkippableBeforeCC
= 0;
176 static uint32_t sPreviousSuspectedCount
= 0;
177 static uint32_t sCleanupsSinceLastGC
= UINT32_MAX
;
178 static bool sNeedsFullCC
= false;
179 static bool sNeedsGCAfterCC
= false;
180 static nsJSContext
*sContextList
= nullptr;
182 static nsScriptNameSpaceManager
*gNameSpaceManager
;
184 static nsIJSRuntimeService
*sRuntimeService
;
186 static const char kJSRuntimeServiceContractID
[] =
187 "@mozilla.org/js/xpc/RuntimeService;1";
189 static PRTime sFirstCollectionTime
;
191 static JSRuntime
*sRuntime
;
193 static bool sIsInitialized
;
194 static bool sDidShutdown
;
195 static bool sShuttingDown
;
196 static int32_t sContextCount
;
198 static nsIScriptSecurityManager
*sSecurityManager
;
200 // nsJSEnvironmentObserver observes the memory-pressure notifications
201 // and forces a garbage collection and cycle collection when it happens, if
202 // the appropriate pref is set.
204 static bool sGCOnMemoryPressure
;
207 GetCollectionTimeDelta()
209 PRTime now
= PR_Now();
210 if (sFirstCollectionTime
) {
211 return now
- sFirstCollectionTime
;
213 sFirstCollectionTime
= now
;
220 nsJSContext::KillGCTimer();
221 nsJSContext::KillShrinkGCBuffersTimer();
222 nsJSContext::KillCCTimer();
223 nsJSContext::KillFullGCTimer();
224 nsJSContext::KillInterSliceGCTimer();
227 class nsJSEnvironmentObserver MOZ_FINAL
: public nsIObserver
234 NS_IMPL_ISUPPORTS1(nsJSEnvironmentObserver
, nsIObserver
)
237 nsJSEnvironmentObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
238 const PRUnichar
* aData
)
240 if (sGCOnMemoryPressure
&& !nsCRT::strcmp(aTopic
, "memory-pressure")) {
241 if(StringBeginsWith(nsDependentString(aData
),
242 NS_LITERAL_STRING("low-memory-ongoing"))) {
243 // Don't GC/CC if we are in an ongoing low-memory state since its very
244 // slow and it likely won't help us anyway.
247 nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE
,
248 nsJSContext::NonIncrementalGC
,
249 nsJSContext::NonCompartmentGC
,
250 nsJSContext::ShrinkingGC
);
251 nsJSContext::CycleCollectNow();
252 } else if (!nsCRT::strcmp(aTopic
, "quit-application")) {
253 sShuttingDown
= true;
260 class nsRootedJSValueArray
{
262 explicit nsRootedJSValueArray(JSContext
*cx
) : avr(cx
, vals
.Length(), vals
.Elements()) {}
264 void SetCapacity(JSContext
*cx
, size_t capacity
) {
265 vals
.SetCapacity(capacity
);
266 // Values must be safe for the GC to inspect (they must not contain garbage).
267 memset(vals
.Elements(), 0, vals
.Capacity() * sizeof(JS::Value
));
271 JS::Value
*Elements() {
272 return vals
.Elements();
276 void resetRooter(JSContext
*cx
) {
277 avr
.changeArray(vals
.Elements(), vals
.Length());
280 nsAutoTArray
<JS::Value
, 16> vals
;
281 JS::AutoArrayRooter avr
;
284 /****************************************************************
285 ************************** AutoFree ****************************
286 ****************************************************************/
290 AutoFree(void *aPtr
) : mPtr(aPtr
) {
294 nsMemory::Free(mPtr
);
303 // A utility function for script languages to call. Although it looks small,
304 // the use of nsIDocShell and nsPresContext triggers a huge number of
305 // dependencies that most languages would not otherwise need.
306 // XXXmarkh - This function is mis-placed!
308 NS_HandleScriptError(nsIScriptGlobalObject
*aScriptGlobal
,
309 nsScriptErrorEvent
*aErrorEvent
,
310 nsEventStatus
*aStatus
)
313 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(aScriptGlobal
));
314 nsIDocShell
*docShell
= win
? win
->GetDocShell() : nullptr;
316 nsRefPtr
<nsPresContext
> presContext
;
317 docShell
->GetPresContext(getter_AddRefs(presContext
));
319 static int32_t errorDepth
; // Recursion prevention
322 if (presContext
&& errorDepth
< 2) {
323 // Dispatch() must be synchronous for the recursion block
324 // (errorDepth) to work.
325 nsEventDispatcher::Dispatch(win
, presContext
, aErrorEvent
, nullptr,
337 AsyncErrorReporter::AsyncErrorReporter(JSRuntime
* aRuntime
,
338 JSErrorReport
* aErrorReport
,
339 const char* aFallbackMessage
,
340 nsIPrincipal
* aGlobalPrincipal
,
341 nsPIDOMWindow
* aWindow
)
342 : mSourceLine(static_cast<const PRUnichar
*>(aErrorReport
->uclinebuf
))
343 , mLineNumber(aErrorReport
->lineno
)
344 , mColumn(aErrorReport
->uctokenptr
- aErrorReport
->uclinebuf
)
345 , mFlags(aErrorReport
->flags
)
347 if (!aErrorReport
->filename
) {
348 mFileName
.SetIsVoid(true);
350 mFileName
.AssignWithConversion(aErrorReport
->filename
);
353 const PRUnichar
* m
= static_cast<const PRUnichar
*>(aErrorReport
->ucmessage
);
355 const PRUnichar
* n
= static_cast<const PRUnichar
*>
356 (js::GetErrorTypeName(aRuntime
, aErrorReport
->exnType
));
359 mErrorMsg
.AppendLiteral(": ");
364 if (mErrorMsg
.IsEmpty() && aFallbackMessage
) {
365 mErrorMsg
.AssignWithConversion(aFallbackMessage
);
368 mCategory
= nsContentUtils::IsSystemPrincipal(aGlobalPrincipal
) ?
369 NS_LITERAL_CSTRING("chrome javascript") :
370 NS_LITERAL_CSTRING("content javascript");
373 if (aWindow
&& aWindow
->IsOuterWindow()) {
374 aWindow
= aWindow
->GetCurrentInnerWindow();
377 mInnerWindowID
= aWindow
->WindowID();
382 AsyncErrorReporter::ReportError()
384 nsCOMPtr
<nsIScriptError
> errorObject
=
385 do_CreateInstance("@mozilla.org/scripterror;1");
390 nsresult rv
= errorObject
->InitWithWindowID(mErrorMsg
, mFileName
,
391 mSourceLine
, mLineNumber
,
392 mColumn
, mFlags
, mCategory
,
398 nsCOMPtr
<nsIConsoleService
> consoleService
=
399 do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
400 if (!consoleService
) {
404 consoleService
->LogMessage(errorObject
);
409 } // namespace mozilla
411 class ScriptErrorEvent
: public AsyncErrorReporter
414 ScriptErrorEvent(nsIScriptGlobalObject
* aScriptGlobal
,
416 JSErrorReport
* aErrorReport
,
417 const char* aFallbackMessage
,
418 nsIPrincipal
* aScriptOriginPrincipal
,
419 nsIPrincipal
* aGlobalPrincipal
,
420 nsPIDOMWindow
* aWindow
,
422 // Pass an empty category, then compute ours
423 : AsyncErrorReporter(aRuntime
, aErrorReport
, aFallbackMessage
,
424 aGlobalPrincipal
, aWindow
)
425 , mScriptGlobal(aScriptGlobal
)
426 , mOriginPrincipal(aScriptOriginPrincipal
)
427 , mDispatchEvent(aDispatchEvent
)
433 nsEventStatus status
= nsEventStatus_eIgnore
;
434 // First, notify the DOM that we have a script error.
435 if (mDispatchEvent
) {
436 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
437 nsIDocShell
* docShell
= win
? win
->GetDocShell() : nullptr;
439 !JSREPORT_IS_WARNING(mFlags
) &&
440 !sHandlingScriptError
) {
441 sHandlingScriptError
= true; // Recursion prevention
443 nsRefPtr
<nsPresContext
> presContext
;
444 docShell
->GetPresContext(getter_AddRefs(presContext
));
447 nsScriptErrorEvent
errorevent(true, NS_LOAD_ERROR
);
449 errorevent
.fileName
= mFileName
.get();
451 nsCOMPtr
<nsIScriptObjectPrincipal
> sop(do_QueryInterface(win
));
452 NS_ENSURE_STATE(sop
);
453 nsIPrincipal
* p
= sop
->GetPrincipal();
456 bool sameOrigin
= !mOriginPrincipal
;
458 if (p
&& !sameOrigin
) {
459 if (NS_FAILED(p
->Subsumes(mOriginPrincipal
, &sameOrigin
))) {
464 NS_NAMED_LITERAL_STRING(xoriginMsg
, "Script error.");
466 errorevent
.errorMsg
= mErrorMsg
.get();
467 errorevent
.lineNr
= mLineNumber
;
469 NS_WARNING("Not same origin error!");
470 errorevent
.errorMsg
= xoriginMsg
.get();
471 errorevent
.lineNr
= 0;
474 nsEventDispatcher::Dispatch(win
, presContext
, &errorevent
, nullptr,
478 sHandlingScriptError
= false;
482 if (status
!= nsEventStatus_eConsumeNoDefault
) {
483 AsyncErrorReporter::ReportError();
490 nsCOMPtr
<nsIScriptGlobalObject
> mScriptGlobal
;
491 nsCOMPtr
<nsIPrincipal
> mOriginPrincipal
;
494 static bool sHandlingScriptError
;
497 bool ScriptErrorEvent::sHandlingScriptError
= false;
499 // NOTE: This function could be refactored to use the above. The only reason
500 // it has not been done is that the code below only fills the error event
501 // after it has a good nsPresContext - whereas using the above function
502 // would involve always filling it. Is that a concern?
504 NS_ScriptErrorReporter(JSContext
*cx
,
506 JSErrorReport
*report
)
508 // We don't want to report exceptions too eagerly, but warnings in the
509 // absence of werror are swallowed whole, so report those now.
510 if (!JSREPORT_IS_WARNING(report
->flags
)) {
511 nsIXPConnect
* xpc
= nsContentUtils::XPConnect();
512 if (JS_DescribeScriptedCaller(cx
, nullptr, nullptr)) {
513 xpc
->MarkErrorUnreported(cx
);
518 nsAXPCNativeCallContext
*cc
= nullptr;
519 xpc
->GetCurrentNativeCallContext(&cc
);
521 nsAXPCNativeCallContext
*prev
= cc
;
522 while (NS_SUCCEEDED(prev
->GetPreviousCallContext(&prev
)) && prev
) {
524 if (NS_SUCCEEDED(prev
->GetLanguage(&lang
)) &&
525 lang
== nsAXPCNativeCallContext::LANG_JS
) {
526 xpc
->MarkErrorUnreported(cx
);
534 // XXX this means we are not going to get error reports on non DOM contexts
535 nsIScriptContext
*context
= nsJSUtils::GetDynamicScriptContext(cx
);
537 // Note: we must do this before running any more code on cx (if cx is the
538 // dynamic script context).
539 ::JS_ClearPendingException(cx
);
542 nsIScriptGlobalObject
*globalObject
= context
->GetGlobalObject();
546 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(globalObject
);
547 nsCOMPtr
<nsIScriptObjectPrincipal
> scriptPrincipal
=
548 do_QueryInterface(globalObject
);
549 NS_ASSERTION(scriptPrincipal
, "Global objects must implement "
550 "nsIScriptObjectPrincipal");
551 nsContentUtils::AddScriptRunner(
552 new ScriptErrorEvent(globalObject
,
556 nsJSPrincipals::get(report
->originPrincipals
),
557 scriptPrincipal
->GetPrincipal(),
559 /* We do not try to report Out Of Memory via a dom
560 * event because the dom event handler would
561 * encounter an OOM exception trying to process the
562 * event, and then we'd need to generate a new OOM
563 * event for that new OOM instance -- this isn't
566 report
->errorNumber
!= JSMSG_OUT_OF_MEMORY
));
570 if (nsContentUtils::DOMWindowDumpEnabled()) {
571 // Print it to stderr as well, for the benefit of those invoking
572 // mozilla with -console.
574 error
.Assign("JavaScript ");
575 if (JSREPORT_IS_STRICT(report
->flags
))
576 error
.Append("strict ");
577 if (JSREPORT_IS_WARNING(report
->flags
))
578 error
.Append("warning: ");
580 error
.Append("error: ");
581 error
.Append(report
->filename
);
582 error
.Append(", line ");
583 error
.AppendInt(report
->lineno
, 10);
585 if (report
->ucmessage
) {
586 AppendUTF16toUTF8(reinterpret_cast<const PRUnichar
*>(report
->ucmessage
),
589 error
.Append(message
);
592 fprintf(stderr
, "%s\n", error
.get());
598 gJSDiagnostics
= PR_NewLogModule("JSDiagnostics");
600 if (gJSDiagnostics
) {
601 PR_LOG(gJSDiagnostics
,
602 JSREPORT_IS_WARNING(report
->flags
) ? PR_LOG_WARNING
: PR_LOG_ERROR
,
603 ("file %s, line %u: %s\n%s%s",
604 report
->filename
, report
->lineno
, message
,
605 report
->linebuf
? report
->linebuf
: "",
607 report
->linebuf
[strlen(report
->linebuf
)-1] != '\n')
615 // A couple of useful functions to call when you're debugging.
617 JSObject2Win(JSContext
*cx
, JSObject
*obj
)
619 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
624 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapper
;
625 xpc
->GetWrappedNativeOfJSObject(cx
, obj
, getter_AddRefs(wrapper
));
627 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryWrappedNative(wrapper
);
629 return static_cast<nsGlobalWindow
*>
630 (static_cast<nsPIDOMWindow
*>(win
));
638 PrintWinURI(nsGlobalWindow
*win
)
641 printf("No window passed in.\n");
645 nsCOMPtr
<nsIDocument
> doc
= win
->GetExtantDoc();
647 printf("No document in the window.\n");
651 nsIURI
*uri
= doc
->GetDocumentURI();
653 printf("Document doesn't have a URI.\n");
659 printf("%s\n", spec
.get());
663 PrintWinCodebase(nsGlobalWindow
*win
)
666 printf("No window passed in.\n");
670 nsIPrincipal
*prin
= win
->GetPrincipal();
672 printf("Window doesn't have principals.\n");
676 nsCOMPtr
<nsIURI
> uri
;
677 prin
->GetURI(getter_AddRefs(uri
));
679 printf("No URI, maybe the system principal.\n");
685 printf("%s\n", spec
.get());
689 DumpString(const nsAString
&str
)
691 printf("%s\n", NS_ConvertUTF16toUTF8(str
).get());
695 #define JS_OPTIONS_DOT_STR "javascript.options."
697 static const char js_options_dot_str
[] = JS_OPTIONS_DOT_STR
;
698 static const char js_strict_option_str
[] = JS_OPTIONS_DOT_STR
"strict";
700 static const char js_strict_debug_option_str
[] = JS_OPTIONS_DOT_STR
"strict.debug";
702 static const char js_werror_option_str
[] = JS_OPTIONS_DOT_STR
"werror";
704 static const char js_zeal_option_str
[] = JS_OPTIONS_DOT_STR
"gczeal";
705 static const char js_zeal_frequency_str
[] = JS_OPTIONS_DOT_STR
"gczeal.frequency";
707 static const char js_typeinfer_content_str
[] = JS_OPTIONS_DOT_STR
"typeinference.content";
708 static const char js_typeinfer_chrome_str
[] = JS_OPTIONS_DOT_STR
"typeinference.chrome";
709 static const char js_jit_hardening_str
[] = JS_OPTIONS_DOT_STR
"jit_hardening";
710 static const char js_memlog_option_str
[] = JS_OPTIONS_DOT_STR
"mem.log";
711 static const char js_memnotify_option_str
[] = JS_OPTIONS_DOT_STR
"mem.notify";
712 static const char js_asmjs_content_str
[] = JS_OPTIONS_DOT_STR
"asmjs";
713 static const char js_baselinejit_content_str
[] = JS_OPTIONS_DOT_STR
"baselinejit.content";
714 static const char js_baselinejit_chrome_str
[] = JS_OPTIONS_DOT_STR
"baselinejit.chrome";
715 static const char js_baselinejit_eager_str
[] = JS_OPTIONS_DOT_STR
"baselinejit.unsafe_eager_compilation";
716 static const char js_ion_content_str
[] = JS_OPTIONS_DOT_STR
"ion.content";
717 static const char js_ion_chrome_str
[] = JS_OPTIONS_DOT_STR
"ion.chrome";
718 static const char js_ion_eager_str
[] = JS_OPTIONS_DOT_STR
"ion.unsafe_eager_compilation";
719 static const char js_parallel_parsing_str
[] = JS_OPTIONS_DOT_STR
"parallel_parsing";
720 static const char js_ion_parallel_compilation_str
[] = JS_OPTIONS_DOT_STR
"ion.parallel_compilation";
723 nsJSContext::JSOptionChangedCallback(const char *pref
, void *data
)
725 nsJSContext
*context
= reinterpret_cast<nsJSContext
*>(data
);
726 uint32_t oldDefaultJSOptions
= context
->mDefaultJSOptions
;
727 uint32_t newDefaultJSOptions
= oldDefaultJSOptions
;
729 sPostGCEventsToConsole
= Preferences::GetBool(js_memlog_option_str
);
730 sPostGCEventsToObserver
= Preferences::GetBool(js_memnotify_option_str
);
732 bool strict
= Preferences::GetBool(js_strict_option_str
);
734 newDefaultJSOptions
|= JSOPTION_EXTRA_WARNINGS
;
736 newDefaultJSOptions
&= ~JSOPTION_EXTRA_WARNINGS
;
738 // The vanilla GetGlobalObject returns null if a global isn't set up on
739 // the context yet. We can sometimes be call midway through context init,
740 // So ask for the member directly instead.
741 nsIScriptGlobalObject
*global
= context
->GetGlobalObjectRef();
743 // XXX should we check for sysprin instead of a chrome window, to make
744 // XXX components be covered by the chrome pref instead of the content one?
745 nsCOMPtr
<nsIDOMWindow
> contentWindow(do_QueryInterface(global
));
746 nsCOMPtr
<nsIDOMChromeWindow
> chromeWindow(do_QueryInterface(global
));
748 bool useTypeInference
= Preferences::GetBool((chromeWindow
|| !contentWindow
) ?
749 js_typeinfer_chrome_str
:
750 js_typeinfer_content_str
);
751 bool useHardening
= Preferences::GetBool(js_jit_hardening_str
);
752 bool useBaselineJIT
= Preferences::GetBool((chromeWindow
|| !contentWindow
) ?
753 js_baselinejit_chrome_str
:
754 js_baselinejit_content_str
);
755 bool useBaselineJITEager
= Preferences::GetBool(js_baselinejit_eager_str
);
756 bool useIon
= Preferences::GetBool((chromeWindow
|| !contentWindow
) ?
759 bool useIonEager
= Preferences::GetBool(js_ion_eager_str
);
760 bool useAsmJS
= Preferences::GetBool(js_asmjs_content_str
);
761 bool parallelParsing
= Preferences::GetBool(js_parallel_parsing_str
);
762 bool parallelIonCompilation
= Preferences::GetBool(js_ion_parallel_compilation_str
);
763 nsCOMPtr
<nsIXULRuntime
> xr
= do_GetService(XULRUNTIME_SERVICE_CONTRACTID
);
765 bool safeMode
= false;
766 xr
->GetInSafeMode(&safeMode
);
768 useTypeInference
= false;
769 useHardening
= false;
770 useBaselineJIT
= false;
771 useBaselineJITEager
= false;
778 if (useTypeInference
)
779 newDefaultJSOptions
|= JSOPTION_TYPE_INFERENCE
;
781 newDefaultJSOptions
&= ~JSOPTION_TYPE_INFERENCE
;
784 newDefaultJSOptions
|= JSOPTION_BASELINE
;
786 newDefaultJSOptions
&= ~JSOPTION_BASELINE
;
789 newDefaultJSOptions
|= JSOPTION_ION
;
791 newDefaultJSOptions
&= ~JSOPTION_ION
;
794 newDefaultJSOptions
|= JSOPTION_ASMJS
;
796 newDefaultJSOptions
&= ~JSOPTION_ASMJS
;
799 // In debug builds, warnings are enabled in chrome context if
800 // javascript.options.strict.debug is true
801 bool strictDebug
= Preferences::GetBool(js_strict_debug_option_str
);
802 if (strictDebug
&& (newDefaultJSOptions
& JSOPTION_EXTRA_WARNINGS
) == 0) {
803 if (chromeWindow
|| !contentWindow
)
804 newDefaultJSOptions
|= JSOPTION_EXTRA_WARNINGS
;
808 bool werror
= Preferences::GetBool(js_werror_option_str
);
810 newDefaultJSOptions
|= JSOPTION_WERROR
;
812 newDefaultJSOptions
&= ~JSOPTION_WERROR
;
814 ::JS_SetOptions(context
->mContext
, newDefaultJSOptions
& JSOPTION_MASK
);
816 ::JS_SetParallelParsingEnabled(context
->mContext
, parallelParsing
);
817 ::JS_SetParallelIonCompilationEnabled(context
->mContext
, parallelIonCompilation
);
819 ::JS_SetGlobalJitCompilerOption(context
->mContext
, JSJITCOMPILER_BASELINE_USECOUNT_TRIGGER
,
820 (useBaselineJITEager
? 0 : -1));
822 ::JS_SetGlobalJitCompilerOption(context
->mContext
, JSJITCOMPILER_ION_USECOUNT_TRIGGER
,
823 (useIonEager
? 0 : -1));
825 // Save the new defaults for the next page load (InitContext).
826 context
->mDefaultJSOptions
= newDefaultJSOptions
;
828 JSRuntime
*rt
= JS_GetRuntime(context
->mContext
);
829 JS_SetJitHardening(rt
, useHardening
);
832 int32_t zeal
= Preferences::GetInt(js_zeal_option_str
, -1);
833 int32_t frequency
= Preferences::GetInt(js_zeal_frequency_str
, JS_DEFAULT_ZEAL_FREQ
);
835 ::JS_SetGCZeal(context
->mContext
, (uint8_t)zeal
, frequency
);
841 nsJSContext::nsJSContext(bool aGCOnDestruction
,
842 nsIScriptGlobalObject
* aGlobalObject
)
843 : mWindowProxy(nullptr)
844 , mGCOnDestruction(aGCOnDestruction
)
845 , mGlobalObjectRef(aGlobalObject
)
849 mNext
= sContextList
;
850 mPrev
= &sContextList
;
852 sContextList
->mPrev
= &mNext
;
858 mDefaultJSOptions
= JSOPTION_PRIVATE_IS_NSISUPPORTS
|
859 JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT
;
861 mContext
= ::JS_NewContext(sRuntime
, gStackSize
);
863 ::JS_SetContextPrivate(mContext
, static_cast<nsIScriptContext
*>(this));
865 // Preserve any flags the context callback might have set.
866 mDefaultJSOptions
|= ::JS_GetOptions(mContext
);
868 // Make sure the new context gets the default context options
869 ::JS_SetOptions(mContext
, mDefaultJSOptions
);
871 // Watch for the JS boolean options
872 Preferences::RegisterCallback(JSOptionChangedCallback
,
873 js_options_dot_str
, this);
875 mIsInitialized
= false;
876 mScriptsEnabled
= true;
877 mProcessingScriptTag
= false;
881 nsJSContext::~nsJSContext()
885 mNext
->mPrev
= mPrev
;
888 mGlobalObjectRef
= nullptr;
894 if (!sContextCount
&& sDidShutdown
) {
895 // The last context is being deleted, and we're already in the
896 // process of shutting down, release the JS runtime service, and
897 // the security manager.
899 NS_IF_RELEASE(sRuntimeService
);
900 NS_IF_RELEASE(sSecurityManager
);
904 // This function is called either by the destructor or unlink, which means that
905 // it can never be called when there is an outstanding ref to the
906 // nsIScriptContext on the stack. Our stack-scoped cx pushers hold such a ref,
907 // so we can assume here that mContext is not on the stack (and therefore not
910 nsJSContext::DestroyJSContext()
916 // Clear our entry in the JSContext, bugzilla bug 66413
917 ::JS_SetContextPrivate(mContext
, nullptr);
919 // Unregister our "javascript.options.*" pref-changed callback.
920 Preferences::UnregisterCallback(JSOptionChangedCallback
,
921 js_options_dot_str
, this);
923 if (mGCOnDestruction
) {
924 PokeGC(JS::gcreason::NSJSCONTEXT_DESTROY
);
927 JS_DestroyContextNoGC(mContext
);
932 // QueryInterface implementation for nsJSContext
933 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSContext
)
935 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSContext
)
936 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mWindowProxy
)
937 NS_IMPL_CYCLE_COLLECTION_TRACE_END
939 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSContext
)
940 NS_ASSERTION(!tmp
->mContext
|| !js::ContextHasOutstandingRequests(tmp
->mContext
),
941 "Trying to unlink a context with outstanding requests.");
942 tmp
->mIsInitialized
= false;
943 tmp
->mGCOnDestruction
= false;
944 tmp
->mWindowProxy
= nullptr;
945 tmp
->DestroyJSContext();
946 NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobalObjectRef
)
947 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
948 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSContext
)
949 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSContext
, tmp
->GetCCRefcnt())
950 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobalObjectRef
)
951 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
952 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
954 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext
)
955 NS_INTERFACE_MAP_ENTRY(nsIScriptContext
)
956 NS_INTERFACE_MAP_ENTRY(nsISupports
)
960 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSContext
)
961 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSContext
)
964 nsJSContext::GetCCRefcnt()
966 nsrefcnt refcnt
= mRefCnt
.get();
968 // In the (abnormal) case of synchronous cycle-collection, the context may be
969 // actively running JS code in which case we must keep it alive by adding an
971 if (mContext
&& js::ContextHasOutstandingRequests(mContext
)) {
979 nsJSContext::EvaluateString(const nsAString
& aScript
,
980 JS::Handle
<JSObject
*> aScopeObject
,
981 JS::CompileOptions
& aCompileOptions
,
982 bool aCoerceToString
,
983 JS::Value
* aRetValue
,
984 void **aOffThreadToken
)
986 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
987 if (!mScriptsEnabled
) {
991 AutoCxPusher
pusher(mContext
);
992 nsJSUtils::EvaluateOptions evalOptions
;
993 evalOptions
.setCoerceToString(aCoerceToString
);
994 return nsJSUtils::EvaluateString(mContext
, aScript
, aScopeObject
,
995 aCompileOptions
, evalOptions
, aRetValue
,
1001 AtomIsEventHandlerName(nsIAtom
*aName
)
1003 const PRUnichar
*name
= aName
->GetUTF16String();
1005 const PRUnichar
*cp
;
1007 for (cp
= name
; *cp
!= '\0'; ++cp
)
1010 if ((c
< 'A' || c
> 'Z') && (c
< 'a' || c
> 'z'))
1018 // Helper function to find the JSObject associated with a (presumably DOM)
1021 nsJSContext::JSObjectFromInterface(nsISupports
* aTarget
,
1022 JS::Handle
<JSObject
*> aScope
,
1025 // It is legal to specify a null target.
1033 // Get the jsobject associated with this target
1034 // We don't wrap here because we trust the JS engine to wrap the target
1036 JS::Rooted
<JS::Value
> v(cx
);
1037 nsresult rv
= nsContentUtils::WrapNative(cx
, aScope
, aTarget
,
1039 NS_ENSURE_SUCCESS(rv
, rv
);
1042 nsCOMPtr
<nsISupports
> targetSupp
= do_QueryInterface(aTarget
);
1043 nsCOMPtr
<nsISupports
> native
=
1044 nsContentUtils::XPConnect()->GetNativeOfWrapper(cx
,
1045 JSVAL_TO_OBJECT(v
));
1046 NS_ASSERTION(native
== targetSupp
, "Native should be the target!");
1049 JSObject
* obj
= v
.toObjectOrNull();
1051 JS::ExposeObjectToActiveJS(obj
);
1059 nsJSContext::BindCompiledEventHandler(nsISupports
* aTarget
,
1060 JS::Handle
<JSObject
*> aScope
,
1061 JS::Handle
<JSObject
*> aHandler
,
1062 JS::MutableHandle
<JSObject
*> aBoundHandler
)
1064 NS_ENSURE_ARG(aHandler
);
1065 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1066 NS_PRECONDITION(!aBoundHandler
, "Shouldn't already have a bound handler!");
1069 JS::ExposeObjectToActiveJS(aScope
);
1071 JS::ExposeObjectToActiveJS(aHandler
);
1072 AutoPushJSContext
cx(mContext
);
1074 // Get the jsobject associated with this target
1075 JS::Rooted
<JSObject
*> target(cx
);
1076 JS::Rooted
<JSObject
*> scope(cx
, aScope
);
1077 nsresult rv
= JSObjectFromInterface(aTarget
, scope
, target
.address());
1078 NS_ENSURE_SUCCESS(rv
, rv
);
1082 JSAutoCompartment
ac(cx
, aHandler
);
1083 NS_ASSERTION(JS_TypeOfValue(cx
,
1084 OBJECT_TO_JSVAL(aHandler
)) == JSTYPE_FUNCTION
,
1085 "Event handler object not a function");
1089 JSAutoCompartment
ac(cx
, target
);
1092 // Make sure the handler function is parented by its event target object
1094 funobj
= JS_CloneFunctionObject(cx
, aHandler
, target
);
1096 rv
= NS_ERROR_OUT_OF_MEMORY
;
1102 aBoundHandler
.set(funobj
);
1107 nsIScriptGlobalObject
*
1108 nsJSContext::GetGlobalObject()
1111 JS::Rooted
<JSObject
*> global(mContext
, GetWindowProxy());
1116 if (mGlobalObjectRef
)
1117 return mGlobalObjectRef
;
1121 JSObject
*inner
= JS_ObjectToInnerObject(cx
, global
);
1123 // If this assertion hits then it means that we have a window object as
1124 // our global, but we never called CreateOuterObject.
1125 NS_ASSERTION(inner
== global
, "Shouldn't be able to innerize here");
1129 const JSClass
*c
= JS_GetClass(global
);
1131 // Whenever we end up with globals that are JSCLASS_IS_DOMJSCLASS
1132 // and have an nsISupports DOM object, we will need to modify this
1134 MOZ_ASSERT(!(c
->flags
& JSCLASS_IS_DOMJSCLASS
));
1135 if ((~c
->flags
) & (JSCLASS_HAS_PRIVATE
|
1136 JSCLASS_PRIVATE_IS_NSISUPPORTS
)) {
1140 nsISupports
*priv
= static_cast<nsISupports
*>(js::GetObjectPrivate(global
));
1142 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapped_native
=
1143 do_QueryInterface(priv
);
1145 nsCOMPtr
<nsIScriptGlobalObject
> sgo
;
1146 if (wrapped_native
) {
1147 // The global object is a XPConnect wrapped native, the native in
1148 // the wrapper might be the nsIScriptGlobalObject
1150 sgo
= do_QueryWrappedNative(wrapped_native
);
1152 sgo
= do_QueryInterface(priv
);
1155 // This'll return a pointer to something we're about to release, but
1156 // that's ok, the JS object will hold it alive long enough.
1161 nsJSContext::GetNativeContext()
1167 nsJSContext::InitContext()
1169 // Make sure callers of this use
1170 // WillInitializeContext/DidInitializeContext around this call.
1171 NS_ENSURE_TRUE(!mIsInitialized
, NS_ERROR_ALREADY_INITIALIZED
);
1174 return NS_ERROR_OUT_OF_MEMORY
;
1176 ::JS_SetErrorReporter(mContext
, NS_ScriptErrorReporter
);
1178 JSOptionChangedCallback(js_options_dot_str
, this);
1184 nsJSContext::InitializeExternalClasses()
1186 nsScriptNameSpaceManager
*nameSpaceManager
= GetNameSpaceManager();
1187 NS_ENSURE_TRUE(nameSpaceManager
, NS_ERROR_NOT_INITIALIZED
);
1189 return nameSpaceManager
->InitForContext(this);
1193 nsJSContext::SetProperty(JS::Handle
<JSObject
*> aTarget
, const char* aPropName
, nsISupports
* aArgs
)
1196 JS::Value
*argv
= nullptr;
1199 pusher
.Push(mContext
);
1201 Maybe
<nsRootedJSValueArray
> tempStorage
;
1203 JS::Rooted
<JSObject
*> global(mContext
, GetWindowProxy());
1205 ConvertSupportsTojsvals(aArgs
, global
, &argc
, &argv
, tempStorage
);
1206 NS_ENSURE_SUCCESS(rv
, rv
);
1208 // got the arguments, now attach them.
1210 for (uint32_t i
= 0; i
< argc
; ++i
) {
1211 if (!JS_WrapValue(mContext
, &argv
[i
])) {
1212 return NS_ERROR_FAILURE
;
1216 JSObject
*args
= ::JS_NewArrayObject(mContext
, argc
, argv
);
1217 JS::Value vargs
= OBJECT_TO_JSVAL(args
);
1219 return JS_DefineProperty(mContext
, aTarget
, aPropName
, vargs
, NULL
, NULL
, 0)
1225 nsJSContext::ConvertSupportsTojsvals(nsISupports
*aArgs
,
1226 JS::Handle
<JSObject
*> aScope
,
1229 Maybe
<nsRootedJSValueArray
> &aTempStorage
)
1231 nsresult rv
= NS_OK
;
1233 // If the array implements nsIJSArgArray, just grab the values directly.
1234 nsCOMPtr
<nsIJSArgArray
> fastArray
= do_QueryInterface(aArgs
);
1235 if (fastArray
!= nullptr)
1236 return fastArray
->GetArgs(aArgc
, reinterpret_cast<void **>(aArgv
));
1238 // Take the slower path converting each item.
1239 // Handle only nsIArray and nsIVariant. nsIArray is only needed for
1240 // SetProperty('arguments', ...);
1245 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
1246 NS_ENSURE_TRUE(xpc
, NS_ERROR_UNEXPECTED
);
1252 // This general purpose function may need to convert an arg array
1253 // (window.arguments, event-handler args) and a generic property.
1254 nsCOMPtr
<nsIArray
> argsArray(do_QueryInterface(aArgs
));
1257 rv
= argsArray
->GetLength(&argCount
);
1258 NS_ENSURE_SUCCESS(rv
, rv
);
1262 argCount
= 1; // the nsISupports which is not an array
1265 // Use the caller's auto guards to release and unroot.
1266 aTempStorage
.construct((JSContext
*)cx
);
1267 aTempStorage
.ref().SetCapacity(cx
, argCount
);
1268 JS::Value
*argv
= aTempStorage
.ref().Elements();
1271 for (uint32_t argCtr
= 0; argCtr
< argCount
&& NS_SUCCEEDED(rv
); argCtr
++) {
1272 nsCOMPtr
<nsISupports
> arg
;
1273 JS::Value
*thisval
= argv
+ argCtr
;
1274 argsArray
->QueryElementAt(argCtr
, NS_GET_IID(nsISupports
),
1275 getter_AddRefs(arg
));
1277 *thisval
= JSVAL_NULL
;
1280 nsCOMPtr
<nsIVariant
> variant(do_QueryInterface(arg
));
1281 if (variant
!= nullptr) {
1282 rv
= xpc
->VariantToJS(cx
, aScope
, variant
, thisval
);
1284 // And finally, support the nsISupportsPrimitives supplied
1285 // by the AppShell. It generally will pass only strings, but
1286 // as we have code for handling all, we may as well use it.
1287 rv
= AddSupportsPrimitiveTojsvals(arg
, thisval
);
1288 if (rv
== NS_ERROR_NO_INTERFACE
) {
1289 // something else - probably an event object or similar -
1292 // but first, check its not another nsISupportsPrimitive, as
1293 // these are now deprecated for use with script contexts.
1294 nsCOMPtr
<nsISupportsPrimitive
> prim(do_QueryInterface(arg
));
1295 NS_ASSERTION(prim
== nullptr,
1296 "Don't pass nsISupportsPrimitives - use nsIVariant!");
1298 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
1299 JS::Rooted
<JS::Value
> v(cx
);
1300 rv
= nsContentUtils::WrapNative(cx
, aScope
, arg
, v
.address(),
1301 getter_AddRefs(wrapper
));
1302 if (NS_SUCCEEDED(rv
)) {
1309 nsCOMPtr
<nsIVariant
> variant
= do_QueryInterface(aArgs
);
1311 rv
= xpc
->VariantToJS(cx
, aScope
, variant
, argv
);
1313 NS_ERROR("Not an array, not an interface?");
1314 rv
= NS_ERROR_UNEXPECTED
;
1324 // This really should go into xpconnect somewhere...
1326 nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports
*aArg
, JS::Value
*aArgv
)
1328 NS_PRECONDITION(aArg
, "Empty arg");
1330 nsCOMPtr
<nsISupportsPrimitive
> argPrimitive(do_QueryInterface(aArg
));
1332 return NS_ERROR_NO_INTERFACE
;
1336 argPrimitive
->GetType(&type
);
1339 case nsISupportsPrimitive::TYPE_CSTRING
: {
1340 nsCOMPtr
<nsISupportsCString
> p(do_QueryInterface(argPrimitive
));
1341 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1348 JSString
*str
= ::JS_NewStringCopyN(cx
, data
.get(), data
.Length());
1349 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
1351 *aArgv
= STRING_TO_JSVAL(str
);
1355 case nsISupportsPrimitive::TYPE_STRING
: {
1356 nsCOMPtr
<nsISupportsString
> p(do_QueryInterface(argPrimitive
));
1357 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1363 // cast is probably safe since wchar_t and jschar are expected
1364 // to be equivalent; both unsigned 16-bit entities
1366 ::JS_NewUCStringCopyN(cx
,
1367 reinterpret_cast<const jschar
*>(data
.get()),
1369 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
1371 *aArgv
= STRING_TO_JSVAL(str
);
1374 case nsISupportsPrimitive::TYPE_PRBOOL
: {
1375 nsCOMPtr
<nsISupportsPRBool
> p(do_QueryInterface(argPrimitive
));
1376 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1382 *aArgv
= BOOLEAN_TO_JSVAL(data
);
1386 case nsISupportsPrimitive::TYPE_PRUINT8
: {
1387 nsCOMPtr
<nsISupportsPRUint8
> p(do_QueryInterface(argPrimitive
));
1388 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1394 *aArgv
= INT_TO_JSVAL(data
);
1398 case nsISupportsPrimitive::TYPE_PRUINT16
: {
1399 nsCOMPtr
<nsISupportsPRUint16
> p(do_QueryInterface(argPrimitive
));
1400 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1406 *aArgv
= INT_TO_JSVAL(data
);
1410 case nsISupportsPrimitive::TYPE_PRUINT32
: {
1411 nsCOMPtr
<nsISupportsPRUint32
> p(do_QueryInterface(argPrimitive
));
1412 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1418 *aArgv
= INT_TO_JSVAL(data
);
1422 case nsISupportsPrimitive::TYPE_CHAR
: {
1423 nsCOMPtr
<nsISupportsChar
> p(do_QueryInterface(argPrimitive
));
1424 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1430 JSString
*str
= ::JS_NewStringCopyN(cx
, &data
, 1);
1431 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
1433 *aArgv
= STRING_TO_JSVAL(str
);
1437 case nsISupportsPrimitive::TYPE_PRINT16
: {
1438 nsCOMPtr
<nsISupportsPRInt16
> p(do_QueryInterface(argPrimitive
));
1439 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1445 *aArgv
= INT_TO_JSVAL(data
);
1449 case nsISupportsPrimitive::TYPE_PRINT32
: {
1450 nsCOMPtr
<nsISupportsPRInt32
> p(do_QueryInterface(argPrimitive
));
1451 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1457 *aArgv
= INT_TO_JSVAL(data
);
1461 case nsISupportsPrimitive::TYPE_FLOAT
: {
1462 nsCOMPtr
<nsISupportsFloat
> p(do_QueryInterface(argPrimitive
));
1463 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1469 *aArgv
= ::JS_NumberValue(data
);
1473 case nsISupportsPrimitive::TYPE_DOUBLE
: {
1474 nsCOMPtr
<nsISupportsDouble
> p(do_QueryInterface(argPrimitive
));
1475 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1481 *aArgv
= ::JS_NumberValue(data
);
1485 case nsISupportsPrimitive::TYPE_INTERFACE_POINTER
: {
1486 nsCOMPtr
<nsISupportsInterfacePointer
> p(do_QueryInterface(argPrimitive
));
1487 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
1489 nsCOMPtr
<nsISupports
> data
;
1490 nsIID
*iid
= nullptr;
1492 p
->GetData(getter_AddRefs(data
));
1493 p
->GetDataIID(&iid
);
1494 NS_ENSURE_TRUE(iid
, NS_ERROR_UNEXPECTED
);
1496 AutoFree
iidGuard(iid
); // Free iid upon destruction.
1498 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
1499 JS::Rooted
<JSObject
*> global(cx
, GetWindowProxy());
1500 JS::Rooted
<JS::Value
> v(cx
);
1501 nsresult rv
= nsContentUtils::WrapNative(cx
, global
,
1502 data
, iid
, v
.address(),
1503 getter_AddRefs(wrapper
));
1504 NS_ENSURE_SUCCESS(rv
, rv
);
1510 case nsISupportsPrimitive::TYPE_ID
:
1511 case nsISupportsPrimitive::TYPE_PRUINT64
:
1512 case nsISupportsPrimitive::TYPE_PRINT64
:
1513 case nsISupportsPrimitive::TYPE_PRTIME
:
1514 case nsISupportsPrimitive::TYPE_VOID
: {
1515 NS_WARNING("Unsupported primitive type used");
1516 *aArgv
= JSVAL_NULL
;
1520 NS_WARNING("Unknown primitive type used");
1521 *aArgv
= JSVAL_NULL
;
1528 #ifdef NS_TRACE_MALLOC
1530 #include <errno.h> // XXX assume Linux if NS_TRACE_MALLOC
1538 #include "nsTraceMalloc.h"
1541 CheckUniversalXPConnectForTraceMalloc(JSContext
*cx
)
1543 if (nsContentUtils::IsCallerChrome())
1545 JS_ReportError(cx
, "trace-malloc functions require UniversalXPConnect");
1550 TraceMallocDisable(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1552 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1555 NS_TraceMallocDisable();
1556 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1561 TraceMallocEnable(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1563 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1566 NS_TraceMallocEnable();
1567 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1572 TraceMallocOpenLogFile(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1577 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1583 str
= JS_ValueToString(cx
, JS_ARGV(cx
, vp
)[0]);
1586 JSAutoByteString
filename(cx
, str
);
1589 fd
= open(filename
.ptr(), O_CREAT
| O_WRONLY
| O_TRUNC
, 0644);
1591 JS_ReportError(cx
, "can't open %s: %s", filename
.ptr(), strerror(errno
));
1595 JS_SET_RVAL(cx
, vp
, INT_TO_JSVAL(fd
));
1600 TraceMallocChangeLogFD(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1602 JS::CallArgs args
= CallArgsFromVp(argc
, vp
);
1604 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1608 if (args
.length() == 0) {
1611 if (!JS::ToInt32(cx
, args
[0], &fd
))
1613 oldfd
= NS_TraceMallocChangeLogFD(fd
);
1615 JS_ReportOutOfMemory(cx
);
1619 args
.rval().setInt32(oldfd
);
1624 TraceMallocCloseLogFD(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1626 JS::CallArgs args
= CallArgsFromVp(argc
, vp
);
1628 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1632 if (args
.length() == 0) {
1633 args
.rval().setUndefined();
1636 if (!JS::ToInt32(cx
, args
[0], &fd
))
1638 NS_TraceMallocCloseLogFD((int) fd
);
1639 args
.rval().setInt32(fd
);
1644 TraceMallocLogTimestamp(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1646 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1649 JSString
*str
= JS_ValueToString(cx
, argc
? JS_ARGV(cx
, vp
)[0] : JSVAL_VOID
);
1652 JSAutoByteString
caption(cx
, str
);
1655 NS_TraceMallocLogTimestamp(caption
.ptr());
1656 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1661 TraceMallocDumpAllocations(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1663 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
1666 JSString
*str
= JS_ValueToString(cx
, argc
? JS_ARGV(cx
, vp
)[0] : JSVAL_VOID
);
1669 JSAutoByteString
pathname(cx
, str
);
1672 if (NS_TraceMallocDumpAllocations(pathname
.ptr()) < 0) {
1673 JS_ReportError(cx
, "can't dump to %s: %s", pathname
.ptr(), strerror(errno
));
1676 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1680 static const JSFunctionSpec TraceMallocFunctions
[] = {
1681 JS_FS("TraceMallocDisable", TraceMallocDisable
, 0, 0),
1682 JS_FS("TraceMallocEnable", TraceMallocEnable
, 0, 0),
1683 JS_FS("TraceMallocOpenLogFile", TraceMallocOpenLogFile
, 1, 0),
1684 JS_FS("TraceMallocChangeLogFD", TraceMallocChangeLogFD
, 1, 0),
1685 JS_FS("TraceMallocCloseLogFD", TraceMallocCloseLogFD
, 1, 0),
1686 JS_FS("TraceMallocLogTimestamp", TraceMallocLogTimestamp
, 1, 0),
1687 JS_FS("TraceMallocDumpAllocations", TraceMallocDumpAllocations
, 1, 0),
1691 #endif /* NS_TRACE_MALLOC */
1700 // See https://wiki.mozilla.org/Performance/MemShrink/DMD for instructions on
1704 ReportAndDump(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1706 JSString
*str
= JS_ValueToString(cx
, argc
? JS_ARGV(cx
, vp
)[0] : JSVAL_VOID
);
1709 JSAutoByteString
pathname(cx
, str
);
1713 FILE* fp
= fopen(pathname
.ptr(), "w");
1715 JS_ReportError(cx
, "DMD can't open %s: %s",
1716 pathname
.ptr(), strerror(errno
));
1720 dmd::ClearReports();
1721 fprintf(stderr
, "DMD: running reporters...\n");
1722 dmd::RunReporters();
1723 dmd::Writer
writer(FpWrite
, fp
);
1728 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1733 } // namespace mozilla
1735 static const JSFunctionSpec DMDFunctions
[] = {
1736 JS_FS("DMDReportAndDump", dmd::ReportAndDump
, 1, 0),
1740 #endif // defined(MOZ_DMD)
1747 IsJProfAction(struct sigaction
*action
)
1749 return (action
->sa_sigaction
&&
1750 (action
->sa_flags
& (SA_RESTART
| SA_SIGINFO
)) == (SA_RESTART
| SA_SIGINFO
));
1753 void NS_JProfStartProfiling();
1754 void NS_JProfStopProfiling();
1755 void NS_JProfClearCircular();
1758 JProfStartProfilingJS(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1760 NS_JProfStartProfiling();
1764 void NS_JProfStartProfiling()
1766 // Figure out whether we're dealing with SIGPROF, SIGALRM, or
1767 // SIGPOLL profiling (SIGALRM for JP_REALTIME, SIGPOLL for
1769 struct sigaction action
;
1771 // Must check ALRM before PROF since both are enabled for real-time
1772 sigaction(SIGALRM
, nullptr, &action
);
1773 //printf("SIGALRM: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
1774 if (IsJProfAction(&action
)) {
1775 //printf("Beginning real-time jprof profiling.\n");
1780 sigaction(SIGPROF
, nullptr, &action
);
1781 //printf("SIGPROF: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
1782 if (IsJProfAction(&action
)) {
1783 //printf("Beginning process-time jprof profiling.\n");
1788 sigaction(SIGPOLL
, nullptr, &action
);
1789 //printf("SIGPOLL: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
1790 if (IsJProfAction(&action
)) {
1791 //printf("Beginning rtc-based jprof profiling.\n");
1796 printf("Could not start jprof-profiling since JPROF_FLAGS was not set.\n");
1800 JProfStopProfilingJS(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1802 NS_JProfStopProfiling();
1807 NS_JProfStopProfiling()
1810 //printf("Stopped jprof profiling.\n");
1814 JProfClearCircularJS(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1816 NS_JProfClearCircular();
1821 NS_JProfClearCircular()
1824 //printf("cleared jprof buffer\n");
1828 JProfSaveCircularJS(JSContext
*cx
, unsigned argc
, JS::Value
*vp
)
1831 NS_JProfStopProfiling();
1832 NS_JProfStartProfiling();
1836 static const JSFunctionSpec JProfFunctions
[] = {
1837 JS_FS("JProfStartProfiling", JProfStartProfilingJS
, 0, 0),
1838 JS_FS("JProfStopProfiling", JProfStopProfilingJS
, 0, 0),
1839 JS_FS("JProfClearCircular", JProfClearCircularJS
, 0, 0),
1840 JS_FS("JProfSaveCircular", JProfSaveCircularJS
, 0, 0),
1844 #endif /* defined(MOZ_JPROF) */
1847 nsJSContext::InitClasses(JS::Handle
<JSObject
*> aGlobalObj
)
1849 nsresult rv
= InitializeExternalClasses();
1850 NS_ENSURE_SUCCESS(rv
, rv
);
1852 JSOptionChangedCallback(js_options_dot_str
, this);
1853 AutoPushJSContext
cx(mContext
);
1855 // Attempt to initialize profiling functions
1856 ::JS_DefineProfilingFunctions(cx
, aGlobalObj
);
1858 #ifdef NS_TRACE_MALLOC
1859 if (nsContentUtils::IsCallerChrome()) {
1860 // Attempt to initialize TraceMalloc functions
1861 ::JS_DefineFunctions(cx
, aGlobalObj
, TraceMallocFunctions
);
1866 // Attempt to initialize DMD functions
1867 ::JS_DefineFunctions(cx
, aGlobalObj
, DMDFunctions
);
1871 // Attempt to initialize JProf functions
1872 ::JS_DefineFunctions(cx
, aGlobalObj
, JProfFunctions
);
1879 nsJSContext::WillInitializeContext()
1881 mIsInitialized
= false;
1885 nsJSContext::DidInitializeContext()
1887 mIsInitialized
= true;
1891 nsJSContext::IsContextInitialized()
1893 return mIsInitialized
;
1897 nsJSContext::GetScriptsEnabled()
1899 return mScriptsEnabled
;
1903 nsJSContext::SetScriptsEnabled(bool aEnabled
, bool aFireTimeouts
)
1905 // eeek - this seems the wrong way around - the global should callback
1906 // into each context, so every language is disabled.
1907 mScriptsEnabled
= aEnabled
;
1909 nsIScriptGlobalObject
*global
= GetGlobalObject();
1912 global
->SetScriptsEnabled(aEnabled
, aFireTimeouts
);
1918 nsJSContext::GetProcessingScriptTag()
1920 return mProcessingScriptTag
;
1924 nsJSContext::SetProcessingScriptTag(bool aFlag
)
1926 mProcessingScriptTag
= aFlag
;
1930 FullGCTimerFired(nsITimer
* aTimer
, void* aClosure
)
1932 NS_RELEASE(sFullGCTimer
);
1934 uintptr_t reason
= reinterpret_cast<uintptr_t>(aClosure
);
1935 nsJSContext::GarbageCollectNow(static_cast<JS::gcreason::Reason
>(reason
),
1936 nsJSContext::IncrementalGC
);
1941 nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason
,
1942 IsIncremental aIncremental
,
1943 IsCompartment aCompartment
,
1944 IsShrinking aShrinking
,
1945 int64_t aSliceMillis
)
1947 PROFILER_LABEL("GC", "GarbageCollectNow");
1949 MOZ_ASSERT_IF(aSliceMillis
, aIncremental
== IncrementalGC
);
1952 KillShrinkGCBuffersTimer();
1954 // Reset sPendingLoadCount in case the timer that fired was a
1955 // timer we scheduled due to a normal GC timer firing while
1956 // documents were loading. If this happens we're waiting for a
1957 // document that is taking a long time to load, and we effectively
1958 // ignore the fact that the currently loading documents are still
1959 // loading and move on as if they weren't.
1960 sPendingLoadCount
= 0;
1961 sLoadingInProgress
= false;
1963 if (!nsContentUtils::XPConnect() || !sRuntime
) {
1967 if (sCCLockedOut
&& aIncremental
== IncrementalGC
) {
1968 // We're in the middle of incremental GC. Do another slice.
1969 JS::PrepareForIncrementalGC(sRuntime
);
1970 JS::IncrementalGC(sRuntime
, aReason
, aSliceMillis
);
1974 JS::PrepareForFullGC(sRuntime
);
1975 if (aIncremental
== IncrementalGC
) {
1976 JS::IncrementalGC(sRuntime
, aReason
, aSliceMillis
);
1978 JS::GCForReason(sRuntime
, aReason
);
1984 nsJSContext::ShrinkGCBuffersNow()
1986 PROFILER_LABEL("GC", "ShrinkGCBuffersNow");
1988 KillShrinkGCBuffersTimer();
1990 JS::ShrinkGCBuffers(sRuntime
);
1994 FinishAnyIncrementalGC()
1997 // We're in the middle of an incremental GC, so finish it.
1998 JS::PrepareForIncrementalGC(sRuntime
);
1999 JS::FinishIncrementalGC(sRuntime
, JS::gcreason::CC_FORCED
);
2004 FireForgetSkippable(uint32_t aSuspected
, bool aRemoveChildless
)
2006 PRTime startTime
= PR_Now();
2007 FinishAnyIncrementalGC();
2008 bool earlyForgetSkippable
=
2009 sCleanupsSinceLastGC
< NS_MAJOR_FORGET_SKIPPABLE_CALLS
;
2010 nsCycleCollector_forgetSkippable(aRemoveChildless
, earlyForgetSkippable
);
2011 sPreviousSuspectedCount
= nsCycleCollector_suspectedCount();
2012 ++sCleanupsSinceLastGC
;
2013 PRTime delta
= PR_Now() - startTime
;
2014 if (sMinForgetSkippableTime
> delta
) {
2015 sMinForgetSkippableTime
= delta
;
2017 if (sMaxForgetSkippableTime
< delta
) {
2018 sMaxForgetSkippableTime
= delta
;
2020 sTotalForgetSkippableTime
+= delta
;
2021 sRemovedPurples
+= (aSuspected
- sPreviousSuspectedCount
);
2022 ++sForgetSkippableBeforeCC
;
2027 TimeBetween(PRTime start
, PRTime end
)
2029 MOZ_ASSERT(end
>= start
);
2030 return (uint32_t)(end
- start
) / PR_USEC_PER_MSEC
;
2035 nsJSContext::CycleCollectNow(nsICycleCollectorListener
*aListener
,
2036 int32_t aExtraForgetSkippableCalls
,
2037 bool aManuallyTriggered
)
2039 if (!NS_IsMainThread()) {
2043 PROFILER_LABEL("CC", "CycleCollectNow");
2045 PRTime start
= PR_Now();
2047 // Before we begin the cycle collection, make sure there is no active GC.
2048 bool finishedIGC
= sCCLockedOut
;
2049 FinishAnyIncrementalGC();
2050 PRTime endGCTime
= PR_Now();
2051 uint32_t gcDuration
= TimeBetween(start
, endGCTime
);
2055 uint32_t suspected
= nsCycleCollector_suspectedCount();
2056 bool ranSyncForgetSkippable
= false;
2058 // Run forgetSkippable synchronously to reduce the size of the CC graph. This
2059 // is particularly useful if we recently finished a GC.
2060 if (sCleanupsSinceLastGC
< NS_MAJOR_FORGET_SKIPPABLE_CALLS
&&
2061 aExtraForgetSkippableCalls
>= 0) {
2062 while (sCleanupsSinceLastGC
< NS_MAJOR_FORGET_SKIPPABLE_CALLS
) {
2063 FireForgetSkippable(nsCycleCollector_suspectedCount(), false);
2064 ranSyncForgetSkippable
= true;
2068 for (int32_t i
= 0; i
< aExtraForgetSkippableCalls
; ++i
) {
2069 FireForgetSkippable(nsCycleCollector_suspectedCount(), false);
2070 ranSyncForgetSkippable
= true;
2073 PRTime endSkippableTime
= PR_Now();
2074 uint32_t skippableDuration
= TimeBetween(endGCTime
, endSkippableTime
);
2076 // Prepare to actually run the CC.
2077 nsCycleCollectorResults ccResults
;
2078 nsCycleCollector_collect(aManuallyTriggered
, &ccResults
, aListener
);
2079 sCCollectedWaitingForGC
+= ccResults
.mFreedRefCounted
+ ccResults
.mFreedGCed
;
2081 // If we collected a substantial amount of cycles, poke the GC since more objects
2082 // might be unreachable now.
2083 if (sCCollectedWaitingForGC
> 250 ||
2084 sLikelyShortLivingObjectsNeedingGC
> 2500 ||
2086 PokeGC(JS::gcreason::CC_WAITING
);
2089 PRTime endCCTime
= PR_Now();
2091 // Log information about the CC via telemetry, JSON and the console.
2092 uint32_t ccNowDuration
= TimeBetween(start
, endCCTime
);
2093 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC
, finishedIGC
);
2094 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE
, ranSyncForgetSkippable
);
2095 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FULL
, ccNowDuration
);
2097 if (sLastCCEndTime
) {
2098 uint32_t timeBetween
= (uint32_t)(start
- sLastCCEndTime
) / PR_USEC_PER_SEC
;
2099 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN
, timeBetween
);
2101 sLastCCEndTime
= endCCTime
;
2103 Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX
,
2104 sMaxForgetSkippableTime
/ PR_USEC_PER_MSEC
);
2106 PRTime delta
= GetCollectionTimeDelta();
2108 uint32_t cleanups
= sForgetSkippableBeforeCC
? sForgetSkippableBeforeCC
: 1;
2109 uint32_t minForgetSkippableTime
= (sMinForgetSkippableTime
== UINT32_MAX
)
2110 ? 0 : sMinForgetSkippableTime
;
2112 if (sPostGCEventsToConsole
) {
2114 if (ccResults
.mMergedZones
) {
2115 mergeMsg
.AssignLiteral(" merged");
2119 if (ccResults
.mForcedGC
) {
2120 gcMsg
.AssignLiteral(", forced a GC");
2123 NS_NAMED_MULTILINE_LITERAL_STRING(kFmt
,
2124 NS_LL("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")
2125 NS_LL("ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, sync: %lu ms, removed: %lu"));
2127 msg
.Adopt(nsTextFormatter::smprintf(kFmt
.get(), double(delta
) / PR_USEC_PER_SEC
,
2128 ccNowDuration
, suspected
,
2129 ccResults
.mVisitedRefCounted
, ccResults
.mVisitedGCed
, mergeMsg
.get(),
2130 ccResults
.mFreedRefCounted
, ccResults
.mFreedGCed
,
2131 sCCollectedWaitingForGC
, sLikelyShortLivingObjectsNeedingGC
,
2133 sForgetSkippableBeforeCC
,
2134 minForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2135 sMaxForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2136 (sTotalForgetSkippableTime
/ cleanups
) /
2138 sTotalForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2139 skippableDuration
, sRemovedPurples
));
2140 nsCOMPtr
<nsIConsoleService
> cs
=
2141 do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
2143 cs
->LogStringMessage(msg
.get());
2147 if (sPostGCEventsToObserver
) {
2148 NS_NAMED_MULTILINE_LITERAL_STRING(kJSONFmt
,
2149 NS_LL("{ \"timestamp\": %llu, ")
2150 NS_LL("\"duration\": %llu, ")
2151 NS_LL("\"finish_gc_duration\": %llu, ")
2152 NS_LL("\"sync_skippable_duration\": %llu, ")
2153 NS_LL("\"suspected\": %lu, ")
2154 NS_LL("\"visited\": { ")
2155 NS_LL("\"RCed\": %lu, ")
2156 NS_LL("\"GCed\": %lu }, ")
2157 NS_LL("\"collected\": { ")
2158 NS_LL("\"RCed\": %lu, ")
2159 NS_LL("\"GCed\": %lu }, ")
2160 NS_LL("\"waiting_for_gc\": %lu, ")
2161 NS_LL("\"short_living_objects_waiting_for_gc\": %lu, ")
2162 NS_LL("\"forced_gc\": %d, ")
2163 NS_LL("\"forget_skippable\": { ")
2164 NS_LL("\"times_before_cc\": %lu, ")
2165 NS_LL("\"min\": %lu, ")
2166 NS_LL("\"max\": %lu, ")
2167 NS_LL("\"avg\": %lu, ")
2168 NS_LL("\"total\": %lu, ")
2169 NS_LL("\"removed\": %lu } ")
2172 json
.Adopt(nsTextFormatter::smprintf(kJSONFmt
.get(), endCCTime
,
2173 ccNowDuration
, gcDuration
, skippableDuration
,
2175 ccResults
.mVisitedRefCounted
, ccResults
.mVisitedGCed
,
2176 ccResults
.mFreedRefCounted
, ccResults
.mFreedGCed
,
2177 sCCollectedWaitingForGC
,
2178 sLikelyShortLivingObjectsNeedingGC
,
2179 ccResults
.mForcedGC
,
2180 sForgetSkippableBeforeCC
,
2181 minForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2182 sMaxForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2183 (sTotalForgetSkippableTime
/ cleanups
) /
2185 sTotalForgetSkippableTime
/ PR_USEC_PER_MSEC
,
2187 nsCOMPtr
<nsIObserverService
> observerService
= mozilla::services::GetObserverService();
2188 if (observerService
) {
2189 observerService
->NotifyObservers(nullptr, "cycle-collection-statistics", json
.get());
2193 // Update global state to indicate we have just run a cycle collection.
2194 sMinForgetSkippableTime
= UINT32_MAX
;
2195 sMaxForgetSkippableTime
= 0;
2196 sTotalForgetSkippableTime
= 0;
2197 sRemovedPurples
= 0;
2198 sForgetSkippableBeforeCC
= 0;
2199 sNeedsFullCC
= false;
2200 sNeedsGCAfterCC
= false;
2205 InterSliceGCTimerFired(nsITimer
*aTimer
, void *aClosure
)
2207 NS_RELEASE(sInterSliceGCTimer
);
2208 nsJSContext::GarbageCollectNow(JS::gcreason::INTER_SLICE_GC
,
2209 nsJSContext::IncrementalGC
,
2210 nsJSContext::CompartmentGC
,
2211 nsJSContext::NonShrinkingGC
,
2212 NS_INTERSLICE_GC_BUDGET
);
2217 GCTimerFired(nsITimer
*aTimer
, void *aClosure
)
2219 NS_RELEASE(sGCTimer
);
2221 uintptr_t reason
= reinterpret_cast<uintptr_t>(aClosure
);
2222 nsJSContext::GarbageCollectNow(static_cast<JS::gcreason::Reason
>(reason
),
2223 nsJSContext::IncrementalGC
,
2224 nsJSContext::CompartmentGC
);
2228 ShrinkGCBuffersTimerFired(nsITimer
*aTimer
, void *aClosure
)
2230 NS_RELEASE(sShrinkGCBuffersTimer
);
2232 nsJSContext::ShrinkGCBuffersNow();
2236 ShouldTriggerCC(uint32_t aSuspected
)
2238 return sNeedsFullCC
||
2239 aSuspected
> NS_CC_PURPLE_LIMIT
||
2240 (aSuspected
> NS_CC_FORCED_PURPLE_LIMIT
&&
2241 sLastCCEndTime
+ NS_CC_FORCED
< PR_Now());
2245 CCTimerFired(nsITimer
*aTimer
, void *aClosure
)
2251 static uint32_t ccDelay
= NS_CC_DELAY
;
2253 ccDelay
= NS_CC_DELAY
/ 3;
2255 PRTime now
= PR_Now();
2256 if (sCCLockedOutTime
== 0) {
2257 // Reset sCCTimerFireCount so that we run forgetSkippable
2258 // often enough before CC. Because of reduced ccDelay
2259 // forgetSkippable will be called just a few times.
2260 // NS_MAX_CC_LOCKEDOUT_TIME limit guarantees that we end up calling
2261 // forgetSkippable and CycleCollectNow eventually.
2262 sCCTimerFireCount
= 0;
2263 sCCLockedOutTime
= now
;
2266 if (now
- sCCLockedOutTime
< NS_MAX_CC_LOCKEDOUT_TIME
) {
2271 ++sCCTimerFireCount
;
2273 // During early timer fires, we only run forgetSkippable. During the first
2274 // late timer fire, we decide if we are going to have a second and final
2275 // late timer fire, where we may run the CC.
2276 const uint32_t numEarlyTimerFires
= ccDelay
/ NS_CC_SKIPPABLE_DELAY
- 2;
2277 bool isLateTimerFire
= sCCTimerFireCount
> numEarlyTimerFires
;
2278 uint32_t suspected
= nsCycleCollector_suspectedCount();
2279 if (isLateTimerFire
&& ShouldTriggerCC(suspected
)) {
2280 if (sCCTimerFireCount
== numEarlyTimerFires
+ 1) {
2281 FireForgetSkippable(suspected
, true);
2282 if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
2283 // Our efforts to avoid a CC have failed, so we return to let the
2284 // timer fire once more to trigger a CC.
2288 // We are in the final timer fire and still meet the conditions for
2289 // triggering a CC. Let CycleCollectNow finish the current IGC, if any,
2290 // because that will allow us to include the GC time in the CC pause.
2291 nsJSContext::CycleCollectNow(nullptr, 0, false);
2293 } else if ((sPreviousSuspectedCount
+ 100) <= suspected
) {
2294 // Only do a forget skippable if there are more than a few new objects.
2295 FireForgetSkippable(suspected
, false);
2298 if (isLateTimerFire
) {
2299 ccDelay
= NS_CC_DELAY
;
2301 // We have either just run the CC or decided we don't want to run the CC
2302 // next time, so kill the timer.
2303 sPreviousSuspectedCount
= 0;
2304 nsJSContext::KillCCTimer();
2310 nsJSContext::CleanupsSinceLastGC()
2312 return sCleanupsSinceLastGC
;
2317 nsJSContext::LoadStart()
2319 sLoadingInProgress
= true;
2320 ++sPendingLoadCount
;
2325 nsJSContext::LoadEnd()
2327 if (!sLoadingInProgress
)
2330 // sPendingLoadCount is not a well managed load counter (and doesn't
2331 // need to be), so make sure we don't make it wrap backwards here.
2332 if (sPendingLoadCount
> 0) {
2333 --sPendingLoadCount
;
2337 // Its probably a good idea to GC soon since we have finished loading.
2338 sLoadingInProgress
= false;
2339 PokeGC(JS::gcreason::LOAD_END
);
2344 nsJSContext::PokeGC(JS::gcreason::Reason aReason
, int aDelay
)
2346 if (sGCTimer
|| sShuttingDown
) {
2347 // There's already a timer for GC'ing, just return
2352 // Make sure CC is called...
2353 sNeedsFullCC
= true;
2355 sNeedsGCAfterCC
= true;
2359 CallCreateInstance("@mozilla.org/timer;1", &sGCTimer
);
2362 // Failed to create timer (probably because we're in XPCOM shutdown)
2366 static bool first
= true;
2368 sGCTimer
->InitWithFuncCallback(GCTimerFired
, reinterpret_cast<void *>(aReason
),
2374 nsITimer::TYPE_ONE_SHOT
);
2381 nsJSContext::PokeShrinkGCBuffers()
2383 if (sShrinkGCBuffersTimer
|| sShuttingDown
) {
2387 CallCreateInstance("@mozilla.org/timer;1", &sShrinkGCBuffersTimer
);
2389 if (!sShrinkGCBuffersTimer
) {
2390 // Failed to create timer (probably because we're in XPCOM shutdown)
2394 sShrinkGCBuffersTimer
->InitWithFuncCallback(ShrinkGCBuffersTimerFired
, nullptr,
2395 NS_SHRINK_GC_BUFFERS_DELAY
,
2396 nsITimer::TYPE_ONE_SHOT
);
2401 nsJSContext::MaybePokeCC()
2403 if (sCCTimer
|| sShuttingDown
|| !sHasRunGC
) {
2407 if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
2408 sCCTimerFireCount
= 0;
2409 CallCreateInstance("@mozilla.org/timer;1", &sCCTimer
);
2413 // We can kill some objects before running forgetSkippable.
2414 nsCycleCollector_dispatchDeferredDeletion();
2416 sCCTimer
->InitWithFuncCallback(CCTimerFired
, nullptr,
2417 NS_CC_SKIPPABLE_DELAY
,
2418 nsITimer::TYPE_REPEATING_SLACK
);
2424 nsJSContext::KillGCTimer()
2429 NS_RELEASE(sGCTimer
);
2434 nsJSContext::KillFullGCTimer()
2437 sFullGCTimer
->Cancel();
2438 NS_RELEASE(sFullGCTimer
);
2443 nsJSContext::KillInterSliceGCTimer()
2445 if (sInterSliceGCTimer
) {
2446 sInterSliceGCTimer
->Cancel();
2447 NS_RELEASE(sInterSliceGCTimer
);
2453 nsJSContext::KillShrinkGCBuffersTimer()
2455 if (sShrinkGCBuffersTimer
) {
2456 sShrinkGCBuffersTimer
->Cancel();
2458 NS_RELEASE(sShrinkGCBuffersTimer
);
2464 nsJSContext::KillCCTimer()
2466 sCCLockedOutTime
= 0;
2471 NS_RELEASE(sCCTimer
);
2476 nsJSContext::GC(JS::gcreason::Reason aReason
)
2481 class NotifyGCEndRunnable
: public nsRunnable
2486 NotifyGCEndRunnable(const nsString
& aMessage
) : mMessage(aMessage
) {}
2492 NotifyGCEndRunnable::Run()
2494 MOZ_ASSERT(NS_IsMainThread());
2496 nsCOMPtr
<nsIObserverService
> observerService
= mozilla::services::GetObserverService();
2497 if (!observerService
) {
2501 const jschar oomMsg
[3] = { '{', '}', 0 };
2502 const jschar
*toSend
= mMessage
.get() ? mMessage
.get() : oomMsg
;
2503 observerService
->NotifyObservers(nullptr, "garbage-collection-statistics", toSend
);
2509 DOMGCSliceCallback(JSRuntime
*aRt
, JS::GCProgress aProgress
, const JS::GCDescription
&aDesc
)
2511 NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread");
2513 if (aProgress
== JS::GC_CYCLE_END
) {
2514 PRTime delta
= GetCollectionTimeDelta();
2516 if (sPostGCEventsToConsole
) {
2517 NS_NAMED_LITERAL_STRING(kFmt
, "GC(T+%.1f) ");
2518 nsString prefix
, gcstats
;
2519 gcstats
.Adopt(aDesc
.formatMessage(aRt
));
2520 prefix
.Adopt(nsTextFormatter::smprintf(kFmt
.get(),
2521 double(delta
) / PR_USEC_PER_SEC
));
2522 nsString msg
= prefix
+ gcstats
;
2523 nsCOMPtr
<nsIConsoleService
> cs
= do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
2525 cs
->LogStringMessage(msg
.get());
2529 if (sPostGCEventsToObserver
) {
2531 json
.Adopt(aDesc
.formatJSON(aRt
, PR_Now()));
2532 nsRefPtr
<NotifyGCEndRunnable
> notify
= new NotifyGCEndRunnable(json
);
2533 NS_DispatchToMainThread(notify
);
2537 // Prevent cycle collections and shrinking during incremental GC.
2538 if (aProgress
== JS::GC_CYCLE_BEGIN
) {
2539 sCCLockedOut
= true;
2540 nsJSContext::KillShrinkGCBuffersTimer();
2541 } else if (aProgress
== JS::GC_CYCLE_END
) {
2542 sCCLockedOut
= false;
2545 // The GC has more work to do, so schedule another GC slice.
2546 if (aProgress
== JS::GC_SLICE_END
) {
2547 nsJSContext::KillInterSliceGCTimer();
2548 if (!sShuttingDown
) {
2549 CallCreateInstance("@mozilla.org/timer;1", &sInterSliceGCTimer
);
2550 sInterSliceGCTimer
->InitWithFuncCallback(InterSliceGCTimerFired
,
2552 NS_INTERSLICE_GC_DELAY
,
2553 nsITimer::TYPE_ONE_SHOT
);
2557 if (aProgress
== JS::GC_CYCLE_END
) {
2558 // May need to kill the inter-slice GC timer
2559 nsJSContext::KillInterSliceGCTimer();
2561 sCCollectedWaitingForGC
= 0;
2562 sLikelyShortLivingObjectsNeedingGC
= 0;
2563 sCleanupsSinceLastGC
= 0;
2564 sNeedsFullCC
= true;
2566 nsJSContext::MaybePokeCC();
2568 if (aDesc
.isCompartment_
) {
2569 if (!sFullGCTimer
&& !sShuttingDown
) {
2570 CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer
);
2571 JS::gcreason::Reason reason
= JS::gcreason::FULL_GC_TIMER
;
2572 sFullGCTimer
->InitWithFuncCallback(FullGCTimerFired
,
2573 reinterpret_cast<void *>(reason
),
2575 nsITimer::TYPE_ONE_SHOT
);
2578 nsJSContext::KillFullGCTimer();
2580 // Avoid shrinking during heavy activity, which is suggested by
2582 nsJSContext::PokeShrinkGCBuffers();
2586 if ((aProgress
== JS::GC_SLICE_END
|| aProgress
== JS::GC_CYCLE_END
) &&
2587 ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
2588 nsCycleCollector_dispatchDeferredDeletion();
2591 if (sPrevGCSliceCallback
)
2592 (*sPrevGCSliceCallback
)(aRt
, aProgress
, aDesc
);
2596 nsJSContext::ReportPendingException()
2598 if (mIsInitialized
) {
2599 nsJSUtils::ReportPendingException(mContext
);
2604 nsJSContext::SetWindowProxy(JS::Handle
<JSObject
*> aWindowProxy
)
2606 mWindowProxy
= aWindowProxy
;
2610 nsJSContext::GetWindowProxy()
2612 JSObject
* windowProxy
= GetWindowProxyPreserveColor();
2614 JS::ExposeObjectToActiveJS(windowProxy
);
2621 nsJSContext::GetWindowProxyPreserveColor()
2623 return mWindowProxy
;
2627 nsJSContext::LikelyShortLivingObjectCreated()
2629 ++sLikelyShortLivingObjectsNeedingGC
;
2633 mozilla::dom::StartupJSEnvironment()
2635 // initialize all our statics, so that we can restart XPCOM
2636 sGCTimer
= sFullGCTimer
= sCCTimer
= nullptr;
2637 sCCLockedOut
= false;
2638 sCCLockedOutTime
= 0;
2641 sPendingLoadCount
= 0;
2642 sLoadingInProgress
= false;
2643 sCCollectedWaitingForGC
= 0;
2644 sLikelyShortLivingObjectsNeedingGC
= 0;
2645 sPostGCEventsToConsole
= false;
2646 sNeedsFullCC
= false;
2647 sNeedsGCAfterCC
= false;
2648 gNameSpaceManager
= nullptr;
2649 sRuntimeService
= nullptr;
2651 sIsInitialized
= false;
2652 sDidShutdown
= false;
2653 sShuttingDown
= false;
2655 sSecurityManager
= nullptr;
2659 ReportAllJSExceptionsPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2661 bool reportAll
= Preferences::GetBool(aPrefName
, false);
2662 nsContentUtils::XPConnect()->SetReportAllJSExceptions(reportAll
);
2667 SetMemoryHighWaterMarkPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2669 int32_t highwatermark
= Preferences::GetInt(aPrefName
, 128);
2671 JS_SetGCParameter(sRuntime
, JSGC_MAX_MALLOC_BYTES
,
2672 highwatermark
* 1024L * 1024L);
2677 SetMemoryMaxPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2679 int32_t pref
= Preferences::GetInt(aPrefName
, -1);
2680 // handle overflow and negative pref values
2681 uint32_t max
= (pref
<= 0 || pref
>= 0x1000) ? -1 : (uint32_t)pref
* 1024 * 1024;
2682 JS_SetGCParameter(sRuntime
, JSGC_MAX_BYTES
, max
);
2687 SetMemoryGCModePrefChangedCallback(const char* aPrefName
, void* aClosure
)
2689 bool enableCompartmentGC
= Preferences::GetBool("javascript.options.mem.gc_per_compartment");
2690 bool enableIncrementalGC
= Preferences::GetBool("javascript.options.mem.gc_incremental");
2692 if (enableIncrementalGC
) {
2693 mode
= JSGC_MODE_INCREMENTAL
;
2694 } else if (enableCompartmentGC
) {
2695 mode
= JSGC_MODE_COMPARTMENT
;
2697 mode
= JSGC_MODE_GLOBAL
;
2699 JS_SetGCParameter(sRuntime
, JSGC_MODE
, mode
);
2704 SetMemoryGCSliceTimePrefChangedCallback(const char* aPrefName
, void* aClosure
)
2706 int32_t pref
= Preferences::GetInt(aPrefName
, -1);
2707 // handle overflow and negative pref values
2708 if (pref
> 0 && pref
< 100000)
2709 JS_SetGCParameter(sRuntime
, JSGC_SLICE_TIME_BUDGET
, pref
);
2714 SetMemoryGCPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2716 int32_t pref
= Preferences::GetInt(aPrefName
, -1);
2717 // handle overflow and negative pref values
2718 if (pref
>= 0 && pref
< 10000)
2719 JS_SetGCParameter(sRuntime
, (JSGCParamKey
)(intptr_t)aClosure
, pref
);
2724 SetMemoryGCDynamicHeapGrowthPrefChangedCallback(const char* aPrefName
, void* aClosure
)
2726 bool pref
= Preferences::GetBool(aPrefName
);
2727 JS_SetGCParameter(sRuntime
, JSGC_DYNAMIC_HEAP_GROWTH
, pref
);
2732 SetMemoryGCDynamicMarkSlicePrefChangedCallback(const char* aPrefName
, void* aClosure
)
2734 bool pref
= Preferences::GetBool(aPrefName
);
2735 JS_SetGCParameter(sRuntime
, JSGC_DYNAMIC_MARK_SLICE
, pref
);
2740 NS_DOMReadStructuredClone(JSContext
* cx
,
2741 JSStructuredCloneReader
* reader
,
2746 if (tag
== SCTAG_DOM_IMAGEDATA
) {
2747 // Read the information out of the stream.
2748 uint32_t width
, height
;
2749 JS::Rooted
<JS::Value
> dataArray(cx
);
2750 if (!JS_ReadUint32Pair(reader
, &width
, &height
) ||
2751 !JS_ReadTypedArray(reader
, dataArray
.address())) {
2754 MOZ_ASSERT(dataArray
.isObject());
2756 // Construct the ImageData.
2757 nsRefPtr
<ImageData
> imageData
= new ImageData(width
, height
,
2758 dataArray
.toObject());
2759 // Wrap it in a JS::Value.
2760 JS::Rooted
<JSObject
*> global(cx
, JS::CurrentGlobalOrNull(cx
));
2764 return imageData
->WrapObject(cx
, global
);
2767 // Don't know what this is. Bail.
2768 xpc::Throw(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
2773 NS_DOMWriteStructuredClone(JSContext
* cx
,
2774 JSStructuredCloneWriter
* writer
,
2775 JS::Handle
<JSObject
*> obj
,
2778 ImageData
* imageData
;
2779 nsresult rv
= UNWRAP_OBJECT(ImageData
, cx
, obj
, imageData
);
2780 if (NS_FAILED(rv
)) {
2781 // Don't know what this is. Bail.
2782 xpc::Throw(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
2786 // Prepare the ImageData internals.
2787 uint32_t width
= imageData
->Width();
2788 uint32_t height
= imageData
->Height();
2789 JS::Rooted
<JSObject
*> dataArray(cx
, imageData
->GetDataObject());
2791 // Write the internals to the stream.
2792 JSAutoCompartment
ac(cx
, dataArray
);
2793 return JS_WriteUint32Pair(writer
, SCTAG_DOM_IMAGEDATA
, 0) &&
2794 JS_WriteUint32Pair(writer
, width
, height
) &&
2795 JS_WriteTypedArray(writer
, JS::ObjectValue(*dataArray
));
2799 NS_DOMStructuredCloneError(JSContext
* cx
,
2802 // We don't currently support any extensions to structured cloning.
2803 xpc::Throw(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
2806 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID
, NS_DOM_SCRIPT_OBJECT_FACTORY_CID
);
2809 nsJSContext::EnsureStatics()
2811 if (sIsInitialized
) {
2812 if (!nsContentUtils::XPConnect()) {
2818 nsresult rv
= CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
,
2820 if (NS_FAILED(rv
)) {
2824 rv
= CallGetService(kJSRuntimeServiceContractID
, &sRuntimeService
);
2825 if (NS_FAILED(rv
)) {
2829 rv
= sRuntimeService
->GetRuntime(&sRuntime
);
2830 if (NS_FAILED(rv
)) {
2834 // Let's make sure that our main thread is the same as the xpcom main thread.
2835 MOZ_ASSERT(NS_IsMainThread());
2837 sPrevGCSliceCallback
= JS::SetGCSliceCallback(sRuntime
, DOMGCSliceCallback
);
2839 // Set up the structured clone callbacks.
2840 static JSStructuredCloneCallbacks cloneCallbacks
= {
2841 NS_DOMReadStructuredClone
,
2842 NS_DOMWriteStructuredClone
,
2843 NS_DOMStructuredCloneError
2845 JS_SetStructuredCloneCallbacks(sRuntime
, &cloneCallbacks
);
2847 static js::DOMCallbacks DOMcallbacks
= {
2848 InstanceClassHasProtoAtDepth
2850 SetDOMCallbacks(sRuntime
, &DOMcallbacks
);
2852 // Set these global xpconnect options...
2853 Preferences::RegisterCallbackAndCall(ReportAllJSExceptionsPrefChangedCallback
,
2854 "dom.report_all_js_exceptions");
2856 Preferences::RegisterCallbackAndCall(SetMemoryHighWaterMarkPrefChangedCallback
,
2857 "javascript.options.mem.high_water_mark");
2859 Preferences::RegisterCallbackAndCall(SetMemoryMaxPrefChangedCallback
,
2860 "javascript.options.mem.max");
2862 Preferences::RegisterCallbackAndCall(SetMemoryGCModePrefChangedCallback
,
2863 "javascript.options.mem.gc_per_compartment");
2865 Preferences::RegisterCallbackAndCall(SetMemoryGCModePrefChangedCallback
,
2866 "javascript.options.mem.gc_incremental");
2868 Preferences::RegisterCallbackAndCall(SetMemoryGCSliceTimePrefChangedCallback
,
2869 "javascript.options.mem.gc_incremental_slice_ms");
2871 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2872 "javascript.options.mem.gc_high_frequency_time_limit_ms",
2873 (void *)JSGC_HIGH_FREQUENCY_TIME_LIMIT
);
2875 Preferences::RegisterCallbackAndCall(SetMemoryGCDynamicMarkSlicePrefChangedCallback
,
2876 "javascript.options.mem.gc_dynamic_mark_slice");
2878 Preferences::RegisterCallbackAndCall(SetMemoryGCDynamicHeapGrowthPrefChangedCallback
,
2879 "javascript.options.mem.gc_dynamic_heap_growth");
2881 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2882 "javascript.options.mem.gc_low_frequency_heap_growth",
2883 (void *)JSGC_LOW_FREQUENCY_HEAP_GROWTH
);
2885 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2886 "javascript.options.mem.gc_high_frequency_heap_growth_min",
2887 (void *)JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN
);
2889 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2890 "javascript.options.mem.gc_high_frequency_heap_growth_max",
2891 (void *)JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX
);
2893 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2894 "javascript.options.mem.gc_high_frequency_low_limit_mb",
2895 (void *)JSGC_HIGH_FREQUENCY_LOW_LIMIT
);
2897 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2898 "javascript.options.mem.gc_high_frequency_high_limit_mb",
2899 (void *)JSGC_HIGH_FREQUENCY_HIGH_LIMIT
);
2901 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2902 "javascript.options.mem.gc_allocation_threshold_mb",
2903 (void *)JSGC_ALLOCATION_THRESHOLD
);
2905 Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback
,
2906 "javascript.options.mem.gc_decommit_threshold_mb",
2907 (void *)JSGC_DECOMMIT_THRESHOLD
);
2909 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
2914 Preferences::AddBoolVarCache(&sGCOnMemoryPressure
,
2915 "javascript.options.gc_on_memory_pressure",
2918 nsIObserver
* observer
= new nsJSEnvironmentObserver();
2919 obs
->AddObserver(observer
, "memory-pressure", false);
2920 obs
->AddObserver(observer
, "quit-application", false);
2922 // Bug 907848 - We need to explicitly get the nsIDOMScriptObjectFactory
2923 // service in order to force its constructor to run, which registers a
2924 // shutdown observer. It would be nice to make this more explicit and less
2926 nsCOMPtr
<nsIDOMScriptObjectFactory
> factory
= do_GetService(kDOMScriptObjectFactoryCID
);
2931 sIsInitialized
= true;
2934 nsScriptNameSpaceManager
*
2935 mozilla::dom::GetNameSpaceManager()
2940 if (!gNameSpaceManager
) {
2941 gNameSpaceManager
= new nsScriptNameSpaceManager
;
2942 NS_ADDREF(gNameSpaceManager
);
2944 nsresult rv
= gNameSpaceManager
->Init();
2945 NS_ENSURE_SUCCESS(rv
, nullptr);
2948 return gNameSpaceManager
;
2952 mozilla::dom::ShutdownJSEnvironment()
2956 NS_IF_RELEASE(gNameSpaceManager
);
2958 if (!sContextCount
) {
2959 // We're being shutdown, and there are no more contexts
2960 // alive, release the JS runtime service and the security manager.
2962 NS_IF_RELEASE(sRuntimeService
);
2963 NS_IF_RELEASE(sSecurityManager
);
2966 sShuttingDown
= true;
2967 sDidShutdown
= true;
2970 // A fast-array class for JS. This class supports both nsIJSScriptArray and
2971 // nsIArray. If it is JS itself providing and consuming this class, all work
2972 // can be done via nsIJSScriptArray, and avoid the conversion of elements
2973 // to/from nsISupports.
2974 // When consumed by non-JS (eg, another script language), conversion is done
2976 class nsJSArgArray MOZ_FINAL
: public nsIJSArgArray
{
2978 nsJSArgArray(JSContext
*aContext
, uint32_t argc
, JS::Value
*argv
,
2982 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
2983 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray
,
2990 nsresult
GetArgs(uint32_t *argc
, void **argv
);
2992 void ReleaseJSObjects();
2995 JSContext
*mContext
;
2996 JS::Heap
<JS::Value
> *mArgv
;
3000 nsJSArgArray::nsJSArgArray(JSContext
*aContext
, uint32_t argc
, JS::Value
*argv
,
3006 // copy the array - we don't know its lifetime, and ours is tied to xpcom
3009 static const fallible_t fallible
= fallible_t();
3010 mArgv
= new (fallible
) JS::Heap
<JS::Value
>[argc
];
3012 *prv
= NS_ERROR_OUT_OF_MEMORY
;
3017 // Callers are allowed to pass in a null argv even for argc > 0. They can
3018 // then use GetArgs to initialize the values.
3020 for (uint32_t i
= 0; i
< argc
; ++i
)
3025 mozilla::HoldJSObjects(this);
3031 nsJSArgArray::~nsJSArgArray()
3037 nsJSArgArray::ReleaseJSObjects()
3044 mozilla::DropJSObjects(this);
3048 // QueryInterface implementation for nsJSArgArray
3049 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSArgArray
)
3051 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSArgArray
)
3052 tmp
->ReleaseJSObjects();
3053 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
3054 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray
)
3055 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
3056 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
3058 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray
)
3060 for (uint32_t i
= 0; i
< tmp
->mArgc
; ++i
) {
3061 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mArgv
[i
])
3064 NS_IMPL_CYCLE_COLLECTION_TRACE_END
3066 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSArgArray
)
3067 NS_INTERFACE_MAP_ENTRY(nsIArray
)
3068 NS_INTERFACE_MAP_ENTRY(nsIJSArgArray
)
3069 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIJSArgArray
)
3070 NS_INTERFACE_MAP_END
3072 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSArgArray
)
3073 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSArgArray
)
3076 nsJSArgArray::GetArgs(uint32_t *argc
, void **argv
)
3078 *argv
= (void *)mArgv
;
3084 NS_IMETHODIMP
nsJSArgArray::GetLength(uint32_t *aLength
)
3090 /* void queryElementAt (in unsigned long index, in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
3091 NS_IMETHODIMP
nsJSArgArray::QueryElementAt(uint32_t index
, const nsIID
& uuid
, void * *result
)
3095 return NS_ERROR_INVALID_ARG
;
3097 if (uuid
.Equals(NS_GET_IID(nsIVariant
)) || uuid
.Equals(NS_GET_IID(nsISupports
))) {
3098 return nsContentUtils::XPConnect()->JSToVariant(mContext
, mArgv
[index
],
3099 (nsIVariant
**)result
);
3101 NS_WARNING("nsJSArgArray only handles nsIVariant");
3102 return NS_ERROR_NO_INTERFACE
;
3105 /* unsigned long indexOf (in unsigned long startIndex, in nsISupports element); */
3106 NS_IMETHODIMP
nsJSArgArray::IndexOf(uint32_t startIndex
, nsISupports
*element
, uint32_t *_retval
)
3108 return NS_ERROR_NOT_IMPLEMENTED
;
3111 /* nsISimpleEnumerator enumerate (); */
3112 NS_IMETHODIMP
nsJSArgArray::Enumerate(nsISimpleEnumerator
**_retval
)
3114 return NS_ERROR_NOT_IMPLEMENTED
;
3117 // The factory function
3118 nsresult
NS_CreateJSArgv(JSContext
*aContext
, uint32_t argc
, void *argv
,
3119 nsIJSArgArray
**aArray
)
3122 nsJSArgArray
*ret
= new nsJSArgArray(aContext
, argc
,
3123 static_cast<JS::Value
*>(argv
), &rv
);
3125 return NS_ERROR_OUT_OF_MEMORY
;
3126 if (NS_FAILED(rv
)) {
3130 return ret
->QueryInterface(NS_GET_IID(nsIArray
), (void **)aArray
);