2013-01-14 16:26:47 -08:00
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
2012-05-21 04:12:37 -07:00
/* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/. */
2007-03-22 10:30:00 -07:00
2012-07-27 07:03:27 -07:00
# include "nsError.h"
2007-03-22 10:30:00 -07:00
# include "nsJSEnvironment.h"
# include "nsIScriptGlobalObject.h"
# include "nsIScriptObjectPrincipal.h"
# include "nsIDOMChromeWindow.h"
# include "nsPIDOMWindow.h"
# include "nsIScriptSecurityManager.h"
# include "nsDOMCID.h"
# include "nsIServiceManager.h"
# include "nsIXPConnect.h"
# include "nsIJSRuntimeService.h"
# include "nsCOMPtr.h"
# include "nsISupportsPrimitives.h"
# include "nsReadableUtils.h"
# include "nsJSUtils.h"
# include "nsIDocShell.h"
# include "nsIDocShellTreeItem.h"
# include "nsPresContext.h"
# include "nsIConsoleService.h"
# include "nsIScriptError.h"
# include "nsIInterfaceRequestor.h"
# include "nsIInterfaceRequestorUtils.h"
# include "nsIPrompt.h"
# include "nsIObserverService.h"
# include "nsITimer.h"
# include "nsIAtom.h"
# include "nsContentUtils.h"
2013-05-22 09:05:26 -07:00
# include "nsCxPusher.h"
2014-03-17 21:48:21 -07:00
# include "mozilla/EventDispatcher.h"
2007-03-22 10:30:00 -07:00
# include "nsIContent.h"
# include "nsCycleCollector.h"
2007-07-09 15:07:07 -07:00
# include "nsNetUtil.h"
2009-01-12 08:05:10 -08:00
# include "nsXPCOMCIDInternal.h"
# include "nsIXULRuntime.h"
2013-08-15 11:17:48 -07:00
# include "nsTextFormatter.h"
2007-03-22 10:30:00 -07:00
2011-02-16 12:47:08 -08:00
# include "xpcpublic.h"
2007-03-22 10:30:00 -07:00
2013-08-26 19:05:20 -07:00
# include "js/OldDebugAPI.h"
2011-05-02 15:47:10 -07:00
# include "jswrapper.h"
2007-03-22 10:30:00 -07:00
# include "nsIArray.h"
# include "nsIObjectInputStream.h"
# include "nsIObjectOutputStream.h"
2012-12-05 01:19:33 -08:00
# include "prmem.h"
2010-10-10 15:38:10 -07:00
# include "WrapperFactory.h"
2007-03-22 10:30:00 -07:00
# include "nsGlobalWindow.h"
2011-10-03 12:11:31 -07:00
# include "nsScriptNameSpaceManager.h"
2012-04-24 03:58:07 -07:00
# include "StructuredCloneTags.h"
2014-02-22 21:01:12 -08:00
# include "mozilla/AutoRestore.h"
# include "mozilla/dom/ErrorEvent.h"
2012-04-24 03:58:07 -07:00
# include "mozilla/dom/ImageData.h"
2012-10-22 10:08:52 -07:00
# include "mozilla/dom/ImageDataBinding.h"
2013-09-06 10:50:24 -07:00
# include "nsAXPCNativeCallContext.h"
2013-11-20 14:35:16 -08:00
# include "mozilla/CycleCollectedJSRuntime.h"
2007-03-22 10:30:00 -07:00
2011-12-19 09:48:12 -08:00
# include "nsJSPrincipals.h"
2010-10-21 22:15:21 -07:00
# ifdef XP_MACOSX
// AssertMacros.h defines 'check' and conflicts with AccessCheck.h
# undef check
# endif
# include "AccessCheck.h"
2007-03-22 10:30:00 -07:00
# ifdef MOZ_JSDEBUGGER
# include "jsdIDebuggerService.h"
# endif
# ifdef MOZ_LOGGING
// Force PR_LOGGING so we can get JS strict warnings even in release builds
# define FORCE_PR_LOG 1
# endif
# include "prlog.h"
# include "prthread.h"
2011-05-24 23:31:59 -07:00
# include "mozilla/Preferences.h"
2012-01-20 12:02:18 -08:00
# include "mozilla/Telemetry.h"
2012-05-02 21:35:38 -07:00
# include "mozilla/dom/BindingUtils.h"
2012-06-14 19:31:55 -07:00
# include "mozilla/Attributes.h"
2013-11-18 13:49:53 -08:00
# include "mozilla/dom/asmjscache/AsmJSCache.h"
2012-06-13 08:14:15 -07:00
# include "mozilla/dom/CanvasRenderingContext2DBinding.h"
2013-09-04 14:06:54 -07:00
# include "mozilla/CycleCollectedJSRuntime.h"
2013-09-25 04:21:20 -07:00
# include "mozilla/ContentEvents.h"
2010-05-19 16:22:19 -07:00
2013-09-04 14:06:54 -07:00
# include "nsCycleCollectionNoteRootCallback.h"
2013-03-18 07:25:50 -07:00
# include "GeckoProfiler.h"
2011-12-02 14:05:33 -08:00
2011-04-28 15:48:52 -07:00
using namespace mozilla ;
2012-04-24 03:58:07 -07:00
using namespace mozilla : : dom ;
2011-04-28 15:48:52 -07:00
2007-03-22 10:30:00 -07:00
const size_t gStackSize = 8192 ;
# ifdef PR_LOGGING
static PRLogModuleInfo * gJSDiagnostics ;
# endif
// Thank you Microsoft!
# ifdef CompareString
# undef CompareString
# endif
2011-12-27 03:59:29 -08:00
# define NS_SHRINK_GC_BUFFERS_DELAY 4000 // ms
2007-03-22 10:30:00 -07:00
// The amount of time we wait from the first request to GC to actually
// doing the first GC.
# define NS_FIRST_GC_DELAY 10000 // ms
2012-05-09 11:53:23 -07:00
# define NS_FULL_GC_DELAY 60000 // ms
2012-02-17 14:35:20 -08:00
// Maximum amount of time that should elapse between incremental GC slices
# define NS_INTERSLICE_GC_DELAY 100 // ms
2012-07-31 18:39:39 -07:00
// If we haven't painted in 100ms, we allow for a longer GC budget
# define NS_INTERSLICE_GC_BUDGET 40 // ms
2011-02-16 15:47:12 -08:00
// The amount of time we wait between a request to CC (after GC ran)
// and doing the actual CC.
2012-02-19 10:36:06 -08:00
# define NS_CC_DELAY 6000 // ms
2007-03-22 10:30:00 -07:00
2012-02-19 10:36:06 -08:00
# define NS_CC_SKIPPABLE_DELAY 400 // ms
2012-01-30 12:06:18 -08:00
2013-12-21 06:35:08 -08:00
// Maximum amount of time that should elapse between incremental CC slices
static const int64_t kICCIntersliceDelay = 32 ; // ms
2013-12-22 06:58:19 -08:00
// Time budget for an incremental CC slice
static const int64_t kICCSliceBudget = 10 ; // ms
// Maximum total duration for an ICC
static const uint32_t kMaxICCDuration = 2000 ; // ms
2012-07-15 03:30:39 -07:00
// Force a CC after this long if there's more than NS_CC_FORCED_PURPLE_LIMIT
// objects in the purple buffer.
2012-03-05 13:48:33 -08:00
# define NS_CC_FORCED (2 * 60 * PR_USEC_PER_SEC) // 2 min
2012-07-15 03:30:39 -07:00
# define NS_CC_FORCED_PURPLE_LIMIT 10
2012-03-05 13:48:33 -08:00
2012-03-08 15:37:13 -08:00
// Don't allow an incremental GC to lock out the CC for too long.
2012-07-15 14:37:09 -07:00
# define NS_MAX_CC_LOCKEDOUT_TIME (15 * PR_USEC_PER_SEC) // 15 seconds
2012-03-08 15:37:13 -08:00
2012-03-05 13:48:33 -08:00
// Trigger a CC if the purple buffer exceeds this size when we check it.
2012-07-15 03:30:39 -07:00
# define NS_CC_PURPLE_LIMIT 200
2012-01-30 12:06:18 -08:00
2011-02-16 15:47:12 -08:00
# define JAVASCRIPT nsIProgrammingLanguage::JAVASCRIPT
2007-10-22 14:42:25 -07:00
2013-01-31 09:23:50 -08:00
// Large value used to specify that a script should run essentially forever
# define NS_UNLIMITED_SCRIPT_RUNTIME (0x40000000LL << 32)
2013-07-27 03:48:45 -07:00
# define NS_MAJOR_FORGET_SKIPPABLE_CALLS 2
2013-08-19 16:24:29 -07:00
// if you add statics here, add them to the list in StartupJSEnvironment
2007-03-22 10:30:00 -07:00
static nsITimer * sGCTimer ;
2011-12-27 03:59:29 -08:00
static nsITimer * sShrinkGCBuffersTimer ;
2011-02-16 15:47:12 -08:00
static nsITimer * sCCTimer ;
2013-12-21 06:35:08 -08:00
static nsITimer * sICCTimer ;
2012-05-09 11:53:23 -07:00
static nsITimer * sFullGCTimer ;
2012-06-10 21:27:59 -07:00
static nsITimer * sInterSliceGCTimer ;
2007-03-22 10:30:00 -07:00
2013-12-31 09:20:21 -08:00
static TimeStamp sLastCCEndTime ;
2012-01-20 12:02:18 -08:00
2012-02-17 14:35:20 -08:00
static bool sCCLockedOut ;
2012-03-08 15:37:13 -08:00
static PRTime sCCLockedOutTime ;
2012-02-17 14:35:20 -08:00
2013-01-27 12:35:12 -08:00
static JS : : GCSliceCallback sPrevGCSliceCallback ;
2011-02-23 00:08:36 -08:00
2013-01-30 14:46:37 -08:00
static bool sHasRunGC ;
2007-03-22 10:30:00 -07:00
// The number of currently pending document loads. This count isn't
// guaranteed to always reflect reality and can't easily as we don't
// have an easy place to know when a load ends or is interrupted in
// all cases. This counter also gets reset if we end up GC'ing while
// we're waiting for a slow page to load. IOW, this count may be 0
// even when there are pending loads.
2012-08-22 08:56:38 -07:00
static uint32_t sPendingLoadCount ;
2011-09-28 23:19:26 -07:00
static bool sLoadingInProgress ;
2007-03-22 10:30:00 -07:00
2012-08-22 08:56:38 -07:00
static uint32_t sCCollectedWaitingForGC ;
2013-03-07 10:53:19 -08:00
static uint32_t sLikelyShortLivingObjectsNeedingGC ;
2011-09-28 23:19:26 -07:00
static bool sPostGCEventsToConsole ;
2012-07-13 12:13:52 -07:00
static bool sPostGCEventsToObserver ;
2014-03-04 16:21:48 -08:00
static int32_t sCCTimerFireCount = 0 ;
2012-09-27 23:57:33 -07:00
static uint32_t sMinForgetSkippableTime = UINT32_MAX ;
2012-08-22 08:56:38 -07:00
static uint32_t sMaxForgetSkippableTime = 0 ;
static uint32_t sTotalForgetSkippableTime = 0 ;
static uint32_t sRemovedPurples = 0 ;
static uint32_t sForgetSkippableBeforeCC = 0 ;
static uint32_t sPreviousSuspectedCount = 0 ;
2012-09-27 23:57:33 -07:00
static uint32_t sCleanupsSinceLastGC = UINT32_MAX ;
2012-02-27 06:49:59 -08:00
static bool sNeedsFullCC = false ;
2013-08-21 14:02:12 -07:00
static bool sNeedsGCAfterCC = false ;
2013-12-21 06:35:08 -08:00
static bool sIncrementalCC = false ;
2007-03-22 10:30:00 -07:00
2012-11-04 14:18:44 -08:00
static nsScriptNameSpaceManager * gNameSpaceManager ;
2007-03-22 10:30:00 -07:00
static nsIJSRuntimeService * sRuntimeService ;
static const char kJSRuntimeServiceContractID [ ] =
" @mozilla.org/js/xpc/RuntimeService;1 " ;
2011-11-09 13:32:17 -08:00
static PRTime sFirstCollectionTime ;
2007-03-22 10:30:00 -07:00
2013-08-19 16:24:29 -07:00
static JSRuntime * sRuntime ;
2011-09-28 23:19:26 -07:00
static bool sIsInitialized ;
static bool sDidShutdown ;
2013-01-22 11:17:48 -08:00
static bool sShuttingDown ;
2012-08-22 08:56:38 -07:00
static int32_t sContextCount ;
2007-03-22 10:30:00 -07:00
static nsIScriptSecurityManager * sSecurityManager ;
2013-01-22 11:17:48 -08:00
// nsJSEnvironmentObserver observes the memory-pressure notifications
2011-07-07 11:27:07 -07:00
// and forces a garbage collection and cycle collection when it happens, if
// the appropriate pref is set.
2011-09-28 23:19:26 -07:00
static bool sGCOnMemoryPressure ;
2007-10-22 14:42:25 -07:00
2012-08-22 11:28:34 -07:00
static PRTime
GetCollectionTimeDelta ( )
{
PRTime now = PR_Now ( ) ;
if ( sFirstCollectionTime ) {
return now - sFirstCollectionTime ;
}
sFirstCollectionTime = now ;
return 0 ;
}
2013-01-22 11:17:48 -08:00
static void
KillTimers ( )
{
nsJSContext : : KillGCTimer ( ) ;
nsJSContext : : KillShrinkGCBuffersTimer ( ) ;
nsJSContext : : KillCCTimer ( ) ;
2013-12-21 06:35:08 -08:00
nsJSContext : : KillICCTimer ( ) ;
2013-01-22 11:17:48 -08:00
nsJSContext : : KillFullGCTimer ( ) ;
nsJSContext : : KillInterSliceGCTimer ( ) ;
}
2014-02-03 07:31:11 -08:00
// If we collected a substantial amount of cycles, poke the GC since more objects
// might be unreachable now.
static bool
NeedsGCAfterCC ( )
{
return sCCollectedWaitingForGC > 250 | |
sLikelyShortLivingObjectsNeedingGC > 2500 | |
sNeedsGCAfterCC ;
}
2013-01-22 11:17:48 -08:00
class nsJSEnvironmentObserver MOZ_FINAL : public nsIObserver
2007-10-22 14:42:25 -07:00
{
public :
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
} ;
2013-01-22 11:17:48 -08:00
NS_IMPL_ISUPPORTS1 ( nsJSEnvironmentObserver , nsIObserver )
2007-10-22 14:42:25 -07:00
NS_IMETHODIMP
2013-01-22 11:17:48 -08:00
nsJSEnvironmentObserver : : Observe ( nsISupports * aSubject , const char * aTopic ,
2014-01-04 07:02:17 -08:00
const char16_t * aData )
2007-11-06 13:47:35 -08:00
{
2013-01-22 11:17:48 -08:00
if ( sGCOnMemoryPressure & & ! nsCRT : : strcmp ( aTopic , " memory-pressure " ) ) {
2013-04-25 18:36:53 -07:00
if ( StringBeginsWith ( nsDependentString ( aData ) ,
NS_LITERAL_STRING ( " low-memory-ongoing " ) ) ) {
// Don't GC/CC if we are in an ongoing low-memory state since its very
// slow and it likely won't help us anyway.
return NS_OK ;
}
2013-01-27 12:35:12 -08:00
nsJSContext : : GarbageCollectNow ( JS : : gcreason : : MEM_PRESSURE ,
2012-06-30 14:16:32 -07:00
nsJSContext : : NonIncrementalGC ,
nsJSContext : : NonCompartmentGC ,
nsJSContext : : ShrinkingGC ) ;
2011-07-07 11:27:07 -07:00
nsJSContext : : CycleCollectNow ( ) ;
2014-02-03 07:31:11 -08:00
if ( NeedsGCAfterCC ( ) ) {
nsJSContext : : GarbageCollectNow ( JS : : gcreason : : MEM_PRESSURE ,
nsJSContext : : NonIncrementalGC ,
nsJSContext : : NonCompartmentGC ,
nsJSContext : : ShrinkingGC ) ;
}
2013-01-22 11:17:48 -08:00
} else if ( ! nsCRT : : strcmp ( aTopic , " quit-application " ) ) {
sShuttingDown = true ;
KillTimers ( ) ;
2011-07-07 11:27:07 -07:00
}
2013-01-22 11:17:48 -08:00
2007-11-06 13:47:35 -08:00
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
/****************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * AutoFree * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class AutoFree {
public :
AutoFree ( void * aPtr ) : mPtr ( aPtr ) {
}
~ AutoFree ( ) {
if ( mPtr )
nsMemory : : Free ( mPtr ) ;
}
void Invalidate ( ) {
mPtr = 0 ;
}
private :
void * mPtr ;
} ;
// A utility function for script languages to call. Although it looks small,
// the use of nsIDocShell and nsPresContext triggers a huge number of
// dependencies that most languages would not otherwise need.
// XXXmarkh - This function is mis-placed!
2011-09-28 23:19:26 -07:00
bool
2007-03-22 10:30:00 -07:00
NS_HandleScriptError ( nsIScriptGlobalObject * aScriptGlobal ,
2014-02-22 21:01:12 -08:00
const ErrorEventInit & aErrorEventInit ,
2007-03-22 10:30:00 -07:00
nsEventStatus * aStatus )
{
2011-09-28 23:19:26 -07:00
bool called = false ;
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsPIDOMWindow > win ( do_QueryInterface ( aScriptGlobal ) ) ;
2012-07-30 07:20:58 -07:00
nsIDocShell * docShell = win ? win - > GetDocShell ( ) : nullptr ;
2007-03-22 10:30:00 -07:00
if ( docShell ) {
2010-03-25 06:17:11 -07:00
nsRefPtr < nsPresContext > presContext ;
2007-03-22 10:30:00 -07:00
docShell - > GetPresContext ( getter_AddRefs ( presContext ) ) ;
2012-08-22 08:56:38 -07:00
static int32_t errorDepth ; // Recursion prevention
2007-03-22 10:30:00 -07:00
+ + errorDepth ;
2008-07-26 16:17:12 -07:00
2014-02-22 21:01:12 -08:00
if ( errorDepth < 2 ) {
2007-03-22 10:30:00 -07:00
// Dispatch() must be synchronous for the recursion block
// (errorDepth) to work.
2014-02-22 21:01:12 -08:00
nsRefPtr < ErrorEvent > event =
ErrorEvent : : Constructor ( static_cast < nsGlobalWindow * > ( win . get ( ) ) ,
NS_LITERAL_STRING ( " error " ) ,
aErrorEventInit ) ;
event - > SetTrusted ( true ) ;
2014-03-17 21:48:21 -07:00
EventDispatcher : : DispatchDOMEvent ( win , nullptr , event , presContext ,
aStatus ) ;
2011-10-17 07:59:28 -07:00
called = true ;
2007-03-22 10:30:00 -07:00
}
- - errorDepth ;
}
return called ;
}
2013-08-28 21:30:06 -07:00
namespace mozilla {
namespace dom {
AsyncErrorReporter : : AsyncErrorReporter ( JSRuntime * aRuntime ,
JSErrorReport * aErrorReport ,
const char * aFallbackMessage ,
2013-10-30 16:17:36 -07:00
bool aIsChromeError ,
2013-08-28 21:30:06 -07:00
nsPIDOMWindow * aWindow )
2014-01-04 07:02:17 -08:00
: mSourceLine ( static_cast < const char16_t * > ( aErrorReport - > uclinebuf ) )
2013-08-28 21:30:06 -07:00
, mLineNumber ( aErrorReport - > lineno )
2014-03-20 08:46:28 -07:00
, mColumn ( aErrorReport - > column )
2013-08-28 21:30:06 -07:00
, mFlags ( aErrorReport - > flags )
{
if ( ! aErrorReport - > filename ) {
mFileName . SetIsVoid ( true ) ;
} else {
mFileName . AssignWithConversion ( aErrorReport - > filename ) ;
}
2014-01-04 07:02:17 -08:00
const char16_t * m = static_cast < const char16_t * > ( aErrorReport - > ucmessage ) ;
2013-08-28 21:30:06 -07:00
if ( m ) {
2014-01-04 07:02:17 -08:00
const char16_t * n = static_cast < const char16_t * >
2013-08-28 21:30:06 -07:00
( js : : GetErrorTypeName ( aRuntime , aErrorReport - > exnType ) ) ;
if ( n ) {
mErrorMsg . Assign ( n ) ;
mErrorMsg . AppendLiteral ( " : " ) ;
}
mErrorMsg . Append ( m ) ;
}
if ( mErrorMsg . IsEmpty ( ) & & aFallbackMessage ) {
mErrorMsg . AssignWithConversion ( aFallbackMessage ) ;
}
2013-10-30 16:17:36 -07:00
mCategory = aIsChromeError ? NS_LITERAL_CSTRING ( " chrome javascript " ) :
NS_LITERAL_CSTRING ( " content javascript " ) ;
2013-08-28 21:30:06 -07:00
mInnerWindowID = 0 ;
if ( aWindow & & aWindow - > IsOuterWindow ( ) ) {
aWindow = aWindow - > GetCurrentInnerWindow ( ) ;
}
if ( aWindow ) {
mInnerWindowID = aWindow - > WindowID ( ) ;
}
}
void
AsyncErrorReporter : : ReportError ( )
{
nsCOMPtr < nsIScriptError > errorObject =
do_CreateInstance ( " @mozilla.org/scripterror;1 " ) ;
if ( ! errorObject ) {
return ;
}
nsresult rv = errorObject - > InitWithWindowID ( mErrorMsg , mFileName ,
mSourceLine , mLineNumber ,
mColumn , mFlags , mCategory ,
mInnerWindowID ) ;
if ( NS_FAILED ( rv ) ) {
return ;
}
nsCOMPtr < nsIConsoleService > consoleService =
do_GetService ( NS_CONSOLESERVICE_CONTRACTID ) ;
if ( ! consoleService ) {
return ;
}
consoleService - > LogMessage ( errorObject ) ;
return ;
}
} // namespace dom
} // namespace mozilla
class ScriptErrorEvent : public AsyncErrorReporter
2009-12-18 11:27:57 -08:00
{
public :
ScriptErrorEvent ( nsIScriptGlobalObject * aScriptGlobal ,
2013-08-28 21:30:06 -07:00
JSRuntime * aRuntime ,
JSErrorReport * aErrorReport ,
const char * aFallbackMessage ,
2011-12-19 09:48:12 -08:00
nsIPrincipal * aScriptOriginPrincipal ,
2013-08-28 21:30:06 -07:00
nsIPrincipal * aGlobalPrincipal ,
nsPIDOMWindow * aWindow ,
2014-01-02 17:04:15 -08:00
JS : : Handle < JS : : Value > aError ,
2013-08-28 21:30:06 -07:00
bool aDispatchEvent )
// Pass an empty category, then compute ours
: AsyncErrorReporter ( aRuntime , aErrorReport , aFallbackMessage ,
2013-10-30 16:17:36 -07:00
nsContentUtils : : IsSystemPrincipal ( aGlobalPrincipal ) ,
aWindow )
2013-08-28 21:30:06 -07:00
, mScriptGlobal ( aScriptGlobal )
, mOriginPrincipal ( aScriptOriginPrincipal )
, mDispatchEvent ( aDispatchEvent )
2014-01-02 17:04:15 -08:00
, mError ( aRuntime , aError )
2013-08-28 21:30:06 -07:00
{
}
2009-12-18 11:27:57 -08:00
NS_IMETHOD Run ( )
{
nsEventStatus status = nsEventStatus_eIgnore ;
// First, notify the DOM that we have a script error.
if ( mDispatchEvent ) {
nsCOMPtr < nsPIDOMWindow > win ( do_QueryInterface ( mScriptGlobal ) ) ;
2012-07-30 07:20:58 -07:00
nsIDocShell * docShell = win ? win - > GetDocShell ( ) : nullptr ;
2009-12-18 11:27:57 -08:00
if ( docShell & &
! JSREPORT_IS_WARNING ( mFlags ) & &
! sHandlingScriptError ) {
2014-02-22 21:01:12 -08:00
AutoRestore < bool > recursionGuard ( sHandlingScriptError ) ;
sHandlingScriptError = true ;
2009-12-18 11:27:57 -08:00
2010-03-25 06:17:11 -07:00
nsRefPtr < nsPresContext > presContext ;
2009-12-18 11:27:57 -08:00
docShell - > GetPresContext ( getter_AddRefs ( presContext ) ) ;
2014-01-02 17:04:15 -08:00
ThreadsafeAutoJSContext cx ;
RootedDictionary < ErrorEventInit > init ( cx ) ;
2014-02-22 21:01:12 -08:00
init . mCancelable = true ;
init . mFilename = mFileName ;
init . mBubbles = true ;
2009-12-18 11:27:57 -08:00
2014-02-22 21:01:12 -08:00
nsCOMPtr < nsIScriptObjectPrincipal > sop ( do_QueryInterface ( win ) ) ;
NS_ENSURE_STATE ( sop ) ;
nsIPrincipal * p = sop - > GetPrincipal ( ) ;
NS_ENSURE_STATE ( p ) ;
2009-12-18 11:27:57 -08:00
2014-02-22 21:01:12 -08:00
bool sameOrigin = ! mOriginPrincipal ;
2009-12-18 11:27:57 -08:00
2014-02-22 21:01:12 -08:00
if ( p & & ! sameOrigin ) {
if ( NS_FAILED ( p - > Subsumes ( mOriginPrincipal , & sameOrigin ) ) ) {
sameOrigin = false ;
2009-12-18 11:27:57 -08:00
}
2014-02-22 21:01:12 -08:00
}
2009-12-18 11:27:57 -08:00
2014-02-22 21:01:12 -08:00
NS_NAMED_LITERAL_STRING ( xoriginMsg , " Script error. " ) ;
if ( sameOrigin ) {
init . mMessage = mErrorMsg ;
init . mLineno = mLineNumber ;
2014-03-20 08:46:28 -07:00
init . mColumn = mColumn ;
2014-01-02 17:04:15 -08:00
init . mError = mError ;
2014-02-22 21:01:12 -08:00
} else {
NS_WARNING ( " Not same origin error! " ) ;
init . mMessage = xoriginMsg ;
init . mLineno = 0 ;
2009-12-18 11:27:57 -08:00
}
2014-02-22 21:01:12 -08:00
nsRefPtr < ErrorEvent > event =
ErrorEvent : : Constructor ( static_cast < nsGlobalWindow * > ( win . get ( ) ) ,
NS_LITERAL_STRING ( " error " ) , init ) ;
event - > SetTrusted ( true ) ;
2014-03-17 21:48:21 -07:00
EventDispatcher : : DispatchDOMEvent ( win , nullptr , event , presContext ,
& status ) ;
2009-12-18 11:27:57 -08:00
}
}
if ( status ! = nsEventStatus_eConsumeNoDefault ) {
2013-08-28 21:30:06 -07:00
AsyncErrorReporter : : ReportError ( ) ;
2009-12-18 11:27:57 -08:00
}
2013-08-28 21:30:06 -07:00
2009-12-18 11:27:57 -08:00
return NS_OK ;
}
2013-08-28 21:30:06 -07:00
private :
2009-12-18 11:27:57 -08:00
nsCOMPtr < nsIScriptGlobalObject > mScriptGlobal ;
2011-12-19 09:48:12 -08:00
nsCOMPtr < nsIPrincipal > mOriginPrincipal ;
2011-09-28 23:19:26 -07:00
bool mDispatchEvent ;
2014-01-02 17:04:15 -08:00
JS : : PersistentRootedValue mError ;
2009-12-18 11:27:57 -08:00
2011-09-28 23:19:26 -07:00
static bool sHandlingScriptError ;
2009-12-18 11:27:57 -08:00
} ;
2011-09-28 23:19:26 -07:00
bool ScriptErrorEvent : : sHandlingScriptError = false ;
2009-12-18 11:27:57 -08:00
2007-03-22 10:30:00 -07:00
// NOTE: This function could be refactored to use the above. The only reason
// it has not been done is that the code below only fills the error event
// after it has a good nsPresContext - whereas using the above function
// would involve always filling it. Is that a concern?
2008-09-06 15:21:43 -07:00
void
2007-03-22 10:30:00 -07:00
NS_ScriptErrorReporter ( JSContext * cx ,
const char * message ,
JSErrorReport * report )
{
2009-02-25 17:32:48 -08:00
// We don't want to report exceptions too eagerly, but warnings in the
// absence of werror are swallowed whole, so report those now.
if ( ! JSREPORT_IS_WARNING ( report - > flags ) ) {
2013-07-23 08:32:36 -07:00
nsIXPConnect * xpc = nsContentUtils : : XPConnect ( ) ;
2014-02-25 07:43:14 -08:00
if ( JS : : DescribeScriptedCaller ( cx ) ) {
2013-07-23 08:32:36 -07:00
xpc - > MarkErrorUnreported ( cx ) ;
2012-04-16 12:30:00 -07:00
return ;
2008-10-12 11:32:34 -07:00
}
2009-02-25 17:32:48 -08:00
if ( xpc ) {
2012-07-30 07:20:58 -07:00
nsAXPCNativeCallContext * cc = nullptr ;
2009-02-25 17:32:48 -08:00
xpc - > GetCurrentNativeCallContext ( & cc ) ;
if ( cc ) {
nsAXPCNativeCallContext * prev = cc ;
while ( NS_SUCCEEDED ( prev - > GetPreviousCallContext ( & prev ) ) & & prev ) {
2012-08-22 08:56:38 -07:00
uint16_t lang ;
2009-02-25 17:32:48 -08:00
if ( NS_SUCCEEDED ( prev - > GetLanguage ( & lang ) ) & &
lang = = nsAXPCNativeCallContext : : LANG_JS ) {
2013-07-23 08:32:36 -07:00
xpc - > MarkErrorUnreported ( cx ) ;
2009-02-25 17:32:48 -08:00
return ;
}
2008-10-12 11:32:34 -07:00
}
}
}
}
2007-03-22 10:30:00 -07:00
// XXX this means we are not going to get error reports on non DOM contexts
nsIScriptContext * context = nsJSUtils : : GetDynamicScriptContext ( cx ) ;
2014-01-02 17:04:15 -08:00
JS : : Rooted < JS : : Value > exception ( cx ) ;
: : JS_GetPendingException ( cx , & exception ) ;
2007-03-22 10:30:00 -07:00
// Note: we must do this before running any more code on cx (if cx is the
// dynamic script context).
: : JS_ClearPendingException ( cx ) ;
if ( context ) {
nsIScriptGlobalObject * globalObject = context - > GetGlobalObject ( ) ;
if ( globalObject ) {
2010-10-20 17:24:15 -07:00
nsCOMPtr < nsPIDOMWindow > win = do_QueryInterface ( globalObject ) ;
2013-08-28 21:30:06 -07:00
nsCOMPtr < nsIScriptObjectPrincipal > scriptPrincipal =
do_QueryInterface ( globalObject ) ;
NS_ASSERTION ( scriptPrincipal , " Global objects must implement "
" nsIScriptObjectPrincipal " ) ;
2009-12-18 11:27:57 -08:00
nsContentUtils : : AddScriptRunner (
2012-03-09 01:48:50 -08:00
new ScriptErrorEvent ( globalObject ,
2013-08-28 21:30:06 -07:00
JS_GetRuntime ( cx ) ,
report ,
message ,
2012-03-09 01:48:50 -08:00
nsJSPrincipals : : get ( report - > originPrincipals ) ,
2013-08-28 21:30:06 -07:00
scriptPrincipal - > GetPrincipal ( ) ,
win ,
2014-01-02 17:04:15 -08:00
exception ,
2013-08-28 21:30:06 -07:00
/* We do not try to report Out Of Memory via a dom
* event because the dom event handler would
* encounter an OOM exception trying to process the
* event , and then we ' d need to generate a new OOM
* event for that new OOM instance - - this isn ' t
* pretty .
*/
report - > errorNumber ! = JSMSG_OUT_OF_MEMORY ) ) ;
2007-03-22 10:30:00 -07:00
}
}
2013-07-31 17:04:49 -07:00
if ( nsContentUtils : : DOMWindowDumpEnabled ( ) ) {
// Print it to stderr as well, for the benefit of those invoking
// mozilla with -console.
nsAutoCString error ;
error . Assign ( " JavaScript " ) ;
if ( JSREPORT_IS_STRICT ( report - > flags ) )
error . Append ( " strict " ) ;
if ( JSREPORT_IS_WARNING ( report - > flags ) )
error . Append ( " warning: " ) ;
else
error . Append ( " error: " ) ;
error . Append ( report - > filename ) ;
error . Append ( " , line " ) ;
error . AppendInt ( report - > lineno , 10 ) ;
error . Append ( " : " ) ;
if ( report - > ucmessage ) {
2014-01-04 07:02:17 -08:00
AppendUTF16toUTF8 ( reinterpret_cast < const char16_t * > ( report - > ucmessage ) ,
2013-07-31 17:04:49 -07:00
error ) ;
} else {
error . Append ( message ) ;
}
2009-12-18 11:27:57 -08:00
2013-07-31 17:04:49 -07:00
fprintf ( stderr , " %s \n " , error . get ( ) ) ;
fflush ( stderr ) ;
}
2007-03-22 10:30:00 -07:00
# ifdef PR_LOGGING
2007-07-11 17:04:11 -07:00
if ( ! gJSDiagnostics )
gJSDiagnostics = PR_NewLogModule ( " JSDiagnostics " ) ;
if ( gJSDiagnostics ) {
PR_LOG ( gJSDiagnostics ,
JSREPORT_IS_WARNING ( report - > flags ) ? PR_LOG_WARNING : PR_LOG_ERROR ,
( " file %s, line %u: %s \n %s%s " ,
report - > filename , report - > lineno , message ,
report - > linebuf ? report - > linebuf : " " ,
( report - > linebuf & &
report - > linebuf [ strlen ( report - > linebuf ) - 1 ] ! = ' \n ' )
? " \n "
: " " ) ) ;
2007-03-22 10:30:00 -07:00
}
# endif
}
# ifdef DEBUG
// A couple of useful functions to call when you're debugging.
nsGlobalWindow *
2014-01-30 06:31:16 -08:00
JSObject2Win ( JSObject * obj )
2007-03-22 10:30:00 -07:00
{
2014-01-30 06:31:16 -08:00
return xpc : : WindowOrNull ( obj ) ;
2007-03-22 10:30:00 -07:00
}
void
PrintWinURI ( nsGlobalWindow * win )
{
if ( ! win ) {
printf ( " No window passed in. \n " ) ;
return ;
}
2013-04-23 21:22:37 -07:00
nsCOMPtr < nsIDocument > doc = win - > GetExtantDoc ( ) ;
2007-03-22 10:30:00 -07:00
if ( ! doc ) {
printf ( " No document in the window. \n " ) ;
return ;
}
nsIURI * uri = doc - > GetDocumentURI ( ) ;
if ( ! uri ) {
printf ( " Document doesn't have a URI. \n " ) ;
return ;
}
2012-09-01 19:35:17 -07:00
nsAutoCString spec ;
2007-03-22 10:30:00 -07:00
uri - > GetSpec ( spec ) ;
printf ( " %s \n " , spec . get ( ) ) ;
}
void
PrintWinCodebase ( nsGlobalWindow * win )
{
if ( ! win ) {
printf ( " No window passed in. \n " ) ;
return ;
}
nsIPrincipal * prin = win - > GetPrincipal ( ) ;
if ( ! prin ) {
printf ( " Window doesn't have principals. \n " ) ;
return ;
}
nsCOMPtr < nsIURI > uri ;
prin - > GetURI ( getter_AddRefs ( uri ) ) ;
if ( ! uri ) {
printf ( " No URI, maybe the system principal. \n " ) ;
return ;
}
2012-09-01 19:35:17 -07:00
nsAutoCString spec ;
2007-03-22 10:30:00 -07:00
uri - > GetSpec ( spec ) ;
printf ( " %s \n " , spec . get ( ) ) ;
}
2010-02-11 17:04:41 -08:00
void
DumpString ( const nsAString & str )
{
printf ( " %s \n " , NS_ConvertUTF16toUTF8 ( str ) . get ( ) ) ;
}
2007-03-22 10:30:00 -07:00
# endif
# define JS_OPTIONS_DOT_STR "javascript.options."
static const char js_options_dot_str [ ] = JS_OPTIONS_DOT_STR ;
static const char js_strict_option_str [ ] = JS_OPTIONS_DOT_STR " strict " ;
2009-12-22 16:52:13 -08:00
# ifdef DEBUG
static const char js_strict_debug_option_str [ ] = JS_OPTIONS_DOT_STR " strict.debug " ;
# endif
2007-03-22 10:30:00 -07:00
static const char js_werror_option_str [ ] = JS_OPTIONS_DOT_STR " werror " ;
2007-11-11 10:59:28 -08:00
# ifdef JS_GC_ZEAL
2011-07-21 14:31:36 -07:00
static const char js_zeal_option_str [ ] = JS_OPTIONS_DOT_STR " gczeal " ;
static const char js_zeal_frequency_str [ ] = JS_OPTIONS_DOT_STR " gczeal.frequency " ;
2007-11-11 10:59:28 -08:00
# endif
2012-07-13 12:13:52 -07:00
static const char js_memlog_option_str [ ] = JS_OPTIONS_DOT_STR " mem.log " ;
static const char js_memnotify_option_str [ ] = JS_OPTIONS_DOT_STR " mem.notify " ;
2007-03-22 10:30:00 -07:00
2013-12-10 15:10:01 -08:00
void
2007-03-22 10:30:00 -07:00
nsJSContext : : JSOptionChangedCallback ( const char * pref , void * data )
{
2007-07-08 00:08:04 -07:00
nsJSContext * context = reinterpret_cast < nsJSContext * > ( data ) ;
2013-10-28 04:51:05 -07:00
JSContext * cx = context - > mContext ;
2007-03-22 10:30:00 -07:00
2011-05-24 23:31:59 -07:00
sPostGCEventsToConsole = Preferences : : GetBool ( js_memlog_option_str ) ;
2012-07-13 12:13:52 -07:00
sPostGCEventsToObserver = Preferences : : GetBool ( js_memnotify_option_str ) ;
2011-02-16 15:47:12 -08:00
2013-10-28 04:51:05 -07:00
JS : : ContextOptionsRef ( cx ) . setExtraWarnings ( Preferences : : GetBool ( js_strict_option_str ) ) ;
2007-03-22 10:30:00 -07:00
2012-04-12 11:21:12 -07:00
// The vanilla GetGlobalObject returns null if a global isn't set up on
// the context yet. We can sometimes be call midway through context init,
// So ask for the member directly instead.
nsIScriptGlobalObject * global = context - > GetGlobalObjectRef ( ) ;
2008-08-20 08:49:00 -07:00
// XXX should we check for sysprin instead of a chrome window, to make
// XXX components be covered by the chrome pref instead of the content one?
2012-03-28 04:09:33 -07:00
nsCOMPtr < nsIDOMWindow > contentWindow ( do_QueryInterface ( global ) ) ;
2008-07-10 20:05:27 -07:00
nsCOMPtr < nsIDOMChromeWindow > chromeWindow ( do_QueryInterface ( global ) ) ;
2009-01-12 08:05:10 -08:00
2007-07-10 01:05:54 -07:00
# ifdef DEBUG
2011-01-27 02:54:58 -08:00
// In debug builds, warnings are enabled in chrome context if
// javascript.options.strict.debug is true
2013-10-28 04:51:05 -07:00
if ( Preferences : : GetBool ( js_strict_debug_option_str ) & &
( chromeWindow | | ! contentWindow ) ) {
JS : : ContextOptionsRef ( cx ) . setExtraWarnings ( true ) ;
2007-07-10 01:05:54 -07:00
}
# endif
2013-10-28 04:51:05 -07:00
JS : : ContextOptionsRef ( cx ) . setWerror ( Preferences : : GetBool ( js_werror_option_str ) ) ;
2007-03-22 10:30:00 -07:00
2007-11-11 10:59:28 -08:00
# ifdef JS_GC_ZEAL
2012-08-22 08:56:38 -07:00
int32_t zeal = Preferences : : GetInt ( js_zeal_option_str , - 1 ) ;
int32_t frequency = Preferences : : GetInt ( js_zeal_frequency_str , JS_DEFAULT_ZEAL_FREQ ) ;
2007-11-11 10:59:28 -08:00
if ( zeal > = 0 )
2012-08-22 08:56:38 -07:00
: : JS_SetGCZeal ( context - > mContext , ( uint8_t ) zeal , frequency ) ;
2007-11-11 10:59:28 -08:00
# endif
2007-03-22 10:30:00 -07:00
}
2013-08-19 16:24:29 -07:00
nsJSContext : : nsJSContext ( bool aGCOnDestruction ,
2012-11-04 01:05:23 -07:00
nsIScriptGlobalObject * aGlobalObject )
2013-09-04 14:06:56 -07:00
: mWindowProxy ( nullptr )
, mGCOnDestruction ( aGCOnDestruction )
2012-11-04 01:04:04 -07:00
, mGlobalObjectRef ( aGlobalObject )
2007-03-22 10:30:00 -07:00
{
2013-08-19 16:24:29 -07:00
EnsureStatics ( ) ;
2007-03-22 10:30:00 -07:00
+ + sContextCount ;
2013-08-19 16:24:29 -07:00
mContext = : : JS_NewContext ( sRuntime , gStackSize ) ;
2007-03-22 10:30:00 -07:00
if ( mContext ) {
2007-07-08 00:08:04 -07:00
: : JS_SetContextPrivate ( mContext , static_cast < nsIScriptContext * > ( this ) ) ;
2007-03-22 10:30:00 -07:00
// Make sure the new context gets the default context options
2013-10-28 04:51:05 -07:00
JS : : ContextOptionsRef ( mContext ) . setPrivateIsNSISupports ( true )
. setNoDefaultCompartmentObject ( true ) ;
2007-03-22 10:30:00 -07:00
2007-03-23 14:27:14 -07:00
// Watch for the JS boolean options
2011-05-28 16:42:57 -07:00
Preferences : : RegisterCallback ( JSOptionChangedCallback ,
js_options_dot_str , this ) ;
2007-03-22 10:30:00 -07:00
}
2011-10-17 07:59:28 -07:00
mIsInitialized = false ;
2013-01-15 03:46:35 -08:00
mProcessingScriptTag = false ;
2013-09-04 14:58:23 -07:00
HoldJSObjects ( this ) ;
2007-03-22 10:30:00 -07:00
}
nsJSContext : : ~ nsJSContext ( )
{
2012-07-30 07:20:58 -07:00
mGlobalObjectRef = nullptr ;
2009-05-07 11:19:36 -07:00
DestroyJSContext ( ) ;
2007-11-01 15:51:57 -07:00
- - sContextCount ;
if ( ! sContextCount & & sDidShutdown ) {
// The last context is being deleted, and we're already in the
// process of shutting down, release the JS runtime service, and
// the security manager.
NS_IF_RELEASE ( sRuntimeService ) ;
NS_IF_RELEASE ( sSecurityManager ) ;
}
}
2013-07-03 10:05:19 -07:00
// This function is called either by the destructor or unlink, which means that
// it can never be called when there is an outstanding ref to the
// nsIScriptContext on the stack. Our stack-scoped cx pushers hold such a ref,
// so we can assume here that mContext is not on the stack (and therefore not
// in use).
2007-11-01 15:51:57 -07:00
void
2009-05-07 11:19:36 -07:00
nsJSContext : : DestroyJSContext ( )
2007-11-01 15:51:57 -07:00
{
2011-12-27 03:59:29 -08:00
if ( ! mContext ) {
2007-03-22 10:30:00 -07:00
return ;
2011-12-27 03:59:29 -08:00
}
2007-03-22 10:30:00 -07:00
// Clear our entry in the JSContext, bugzilla bug 66413
2012-07-30 07:20:58 -07:00
: : JS_SetContextPrivate ( mContext , nullptr ) ;
2007-03-22 10:30:00 -07:00
// Unregister our "javascript.options.*" pref-changed callback.
2011-05-28 16:42:57 -07:00
Preferences : : UnregisterCallback ( JSOptionChangedCallback ,
js_options_dot_str , this ) ;
2007-03-22 10:30:00 -07:00
2011-12-27 03:59:29 -08:00
if ( mGCOnDestruction ) {
2013-01-27 12:35:12 -08:00
PokeGC ( JS : : gcreason : : NSJSCONTEXT_DESTROY ) ;
2011-12-27 03:59:29 -08:00
}
2013-07-03 10:05:19 -07:00
JS_DestroyContextNoGC ( mContext ) ;
2012-07-30 07:20:58 -07:00
mContext = nullptr ;
2013-09-04 14:58:23 -07:00
DropJSObjects ( this ) ;
2007-05-25 01:42:08 -07:00
}
2007-03-22 10:30:00 -07:00
// QueryInterface implementation for nsJSContext
2013-08-01 18:29:05 -07:00
NS_IMPL_CYCLE_COLLECTION_CLASS ( nsJSContext )
2010-11-08 07:02:49 -08:00
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN ( nsJSContext )
2013-09-04 14:06:56 -07:00
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK ( mWindowProxy )
2010-11-08 07:02:49 -08:00
NS_IMPL_CYCLE_COLLECTION_TRACE_END
2013-08-01 18:29:05 -07:00
2010-11-08 07:02:49 -08:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN ( nsJSContext )
2012-09-04 15:22:05 -07:00
NS_ASSERTION ( ! tmp - > mContext | | ! js : : ContextHasOutstandingRequests ( tmp - > mContext ) ,
2009-05-07 11:19:36 -07:00
" Trying to unlink a context with outstanding requests. " ) ;
2011-10-17 07:59:28 -07:00
tmp - > mIsInitialized = false ;
tmp - > mGCOnDestruction = false ;
2013-09-04 14:06:56 -07:00
tmp - > mWindowProxy = nullptr ;
2009-05-07 11:19:36 -07:00
tmp - > DestroyJSContext ( ) ;
2012-11-14 23:32:40 -08:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mGlobalObjectRef )
2007-11-01 15:51:57 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2009-02-27 06:48:26 -08:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL ( nsJSContext )
NS_IMPL_CYCLE_COLLECTION_DESCRIBE ( nsJSContext , tmp - > GetCCRefcnt ( ) )
2012-11-14 23:32:40 -08:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mGlobalObjectRef )
2013-09-04 14:06:56 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
2007-03-22 10:30:00 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2007-04-25 09:35:27 -07:00
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION ( nsJSContext )
2007-03-22 10:30:00 -07:00
NS_INTERFACE_MAP_ENTRY ( nsIScriptContext )
2013-08-14 14:00:03 -07:00
NS_INTERFACE_MAP_ENTRY ( nsISupports )
2007-03-22 10:30:00 -07:00
NS_INTERFACE_MAP_END
2011-03-06 03:11:31 -08:00
NS_IMPL_CYCLE_COLLECTING_ADDREF ( nsJSContext )
NS_IMPL_CYCLE_COLLECTING_RELEASE ( nsJSContext )
2007-03-22 10:30:00 -07:00
2009-05-07 11:19:36 -07:00
nsrefcnt
nsJSContext : : GetCCRefcnt ( )
{
2009-05-22 11:45:26 -07:00
nsrefcnt refcnt = mRefCnt . get ( ) ;
2012-09-04 15:22:05 -07:00
// In the (abnormal) case of synchronous cycle-collection, the context may be
// actively running JS code in which case we must keep it alive by adding an
// extra refcount.
if ( mContext & & js : : ContextHasOutstandingRequests ( mContext ) ) {
refcnt + + ;
}
2009-05-22 11:45:26 -07:00
return refcnt ;
2009-05-07 11:19:36 -07:00
}
2010-03-08 07:45:00 -08:00
# ifdef DEBUG
2011-09-28 23:19:26 -07:00
bool
2010-03-08 07:45:00 -08:00
AtomIsEventHandlerName ( nsIAtom * aName )
2007-03-22 10:30:00 -07:00
{
2014-01-04 07:02:17 -08:00
const char16_t * name = aName - > GetUTF16String ( ) ;
2007-03-22 10:30:00 -07:00
2014-01-04 07:02:17 -08:00
const char16_t * cp ;
char16_t c ;
2007-03-22 10:30:00 -07:00
for ( cp = name ; * cp ! = ' \0 ' ; + + cp )
{
c = * cp ;
2010-03-08 07:45:00 -08:00
if ( ( c < ' A ' | | c > ' Z ' ) & & ( c < ' a ' | | c > ' z ' ) )
2011-10-17 07:59:28 -07:00
return false ;
2007-03-22 10:30:00 -07:00
}
2011-10-17 07:59:28 -07:00
return true ;
2007-03-22 10:30:00 -07:00
}
2010-03-08 07:45:00 -08:00
# endif
2007-03-22 10:30:00 -07:00
nsIScriptGlobalObject *
nsJSContext : : GetGlobalObject ( )
{
2013-05-22 09:05:24 -07:00
AutoJSContext cx ;
2013-09-04 14:06:57 -07:00
JS : : Rooted < JSObject * > global ( mContext , GetWindowProxy ( ) ) ;
2007-03-22 10:30:00 -07:00
if ( ! global ) {
2012-07-30 07:20:58 -07:00
return nullptr ;
2010-09-17 14:54:40 -07:00
}
2011-04-28 13:28:54 -07:00
if ( mGlobalObjectRef )
return mGlobalObjectRef ;
# ifdef DEBUG
{
2013-05-22 09:05:24 -07:00
JSObject * inner = JS_ObjectToInnerObject ( cx , global ) ;
2011-04-28 13:28:54 -07:00
// If this assertion hits then it means that we have a window object as
// our global, but we never called CreateOuterObject.
NS_ASSERTION ( inner = = global , " Shouldn't be able to innerize here " ) ;
2007-03-22 10:30:00 -07:00
}
2011-04-28 13:28:54 -07:00
# endif
2007-03-22 10:30:00 -07:00
2013-09-11 05:49:05 -07:00
const JSClass * c = JS_GetClass ( global ) ;
2007-03-22 10:30:00 -07:00
2014-01-30 06:31:16 -08:00
nsCOMPtr < nsIScriptGlobalObject > sgo ;
if ( IsDOMClass ( c ) ) {
sgo = do_QueryInterface ( UnwrapDOMObjectToISupports ( global ) ) ;
} else {
if ( ( ~ c - > flags ) & ( JSCLASS_HAS_PRIVATE |
JSCLASS_PRIVATE_IS_NSISUPPORTS ) ) {
return nullptr ;
}
2007-03-22 10:30:00 -07:00
2014-01-30 06:31:16 -08:00
nsISupports * priv = static_cast < nsISupports * > ( js : : GetObjectPrivate ( global ) ) ;
2007-03-22 10:30:00 -07:00
2014-01-30 06:31:16 -08:00
nsCOMPtr < nsIXPConnectWrappedNative > wrapped_native =
do_QueryInterface ( priv ) ;
if ( wrapped_native ) {
// The global object is a XPConnect wrapped native, the native in
// the wrapper might be the nsIScriptGlobalObject
2007-03-22 10:30:00 -07:00
2014-01-30 06:31:16 -08:00
sgo = do_QueryWrappedNative ( wrapped_native ) ;
} else {
sgo = do_QueryInterface ( priv ) ;
}
2007-03-22 10:30:00 -07:00
}
// This'll return a pointer to something we're about to release, but
// that's ok, the JS object will hold it alive long enough.
2011-04-28 13:28:54 -07:00
return sgo ;
2007-03-22 10:30:00 -07:00
}
2011-09-18 02:22:17 -07:00
JSContext *
2007-03-22 10:30:00 -07:00
nsJSContext : : GetNativeContext ( )
{
2013-09-04 14:06:56 -07:00
return mContext ;
2007-03-22 10:30:00 -07:00
}
nsresult
2010-07-15 15:16:29 -07:00
nsJSContext : : InitContext ( )
2007-03-22 10:30:00 -07:00
{
// Make sure callers of this use
// WillInitializeContext/DidInitializeContext around this call.
NS_ENSURE_TRUE ( ! mIsInitialized , NS_ERROR_ALREADY_INITIALIZED ) ;
if ( ! mContext )
return NS_ERROR_OUT_OF_MEMORY ;
: : JS_SetErrorReporter ( mContext , NS_ScriptErrorReporter ) ;
2012-03-22 01:36:36 -07:00
JSOptionChangedCallback ( js_options_dot_str , this ) ;
2010-07-15 15:16:29 -07:00
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
nsresult
nsJSContext : : InitializeExternalClasses ( )
{
2013-08-19 16:24:29 -07:00
nsScriptNameSpaceManager * nameSpaceManager = GetNameSpaceManager ( ) ;
2007-11-13 02:35:49 -08:00
NS_ENSURE_TRUE ( nameSpaceManager , NS_ERROR_NOT_INITIALIZED ) ;
2007-03-22 10:30:00 -07:00
2007-11-13 02:35:49 -08:00
return nameSpaceManager - > InitForContext ( this ) ;
2007-03-22 10:30:00 -07:00
}
nsresult
2013-05-11 22:17:42 -07:00
nsJSContext : : SetProperty ( JS : : Handle < JSObject * > aTarget , const char * aPropName , nsISupports * aArgs )
2007-03-22 10:30:00 -07:00
{
2013-02-26 11:04:12 -08:00
nsCxPusher pusher ;
pusher . Push ( mContext ) ;
2007-07-26 10:52:26 -07:00
2014-02-11 02:59:15 -08:00
JS : : AutoValueVector args ( mContext ) ;
2010-01-25 08:48:07 -08:00
2013-09-04 14:06:57 -07:00
JS : : Rooted < JSObject * > global ( mContext , GetWindowProxy ( ) ) ;
2012-03-11 00:50:22 -08:00
nsresult rv =
2014-02-11 02:59:15 -08:00
ConvertSupportsTojsvals ( aArgs , global , args ) ;
2007-03-22 10:30:00 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2007-07-26 10:52:26 -07:00
// got the arguments, now attach them.
2014-02-11 02:59:15 -08:00
for ( uint32_t i = 0 ; i < args . length ( ) ; + + i ) {
if ( ! JS_WrapValue ( mContext , args . handleAt ( i ) ) ) {
2013-05-17 10:43:19 -07:00
return NS_ERROR_FAILURE ;
2010-09-27 20:40:27 -07:00
}
2013-05-17 01:08:44 -07:00
}
2013-05-16 23:33:14 -07:00
2014-02-12 02:50:46 -08:00
JSObject * array = : : JS_NewArrayObject ( mContext , args ) ;
2014-02-11 02:59:15 -08:00
if ( ! array ) {
2013-10-26 09:19:05 -07:00
return NS_ERROR_FAILURE ;
}
2014-02-11 02:59:15 -08:00
JS : : Rooted < JS : : Value > arrayVal ( mContext , JS : : ObjectValue ( * array ) ) ;
2013-05-17 10:43:19 -07:00
2014-02-11 02:59:15 -08:00
return JS_DefineProperty ( mContext , aTarget , aPropName , arrayVal ,
nullptr , nullptr , 0 ) ? NS_OK : NS_ERROR_FAILURE ;
2007-03-22 10:30:00 -07:00
}
nsresult
2014-02-11 02:59:15 -08:00
nsJSContext : : ConvertSupportsTojsvals ( nsISupports * aArgs ,
2013-05-02 02:12:46 -07:00
JS : : Handle < JSObject * > aScope ,
2014-02-11 02:59:15 -08:00
JS : : AutoValueVector & aArgsOut )
2007-03-22 10:30:00 -07:00
{
nsresult rv = NS_OK ;
2014-02-11 02:59:15 -08:00
// If the array implements nsIJSArgArray, copy the contents and return.
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIJSArgArray > fastArray = do_QueryInterface ( aArgs ) ;
2014-02-11 02:59:15 -08:00
if ( fastArray ) {
uint32_t argc ;
JS : : Value * argv ;
rv = fastArray - > GetArgs ( & argc , reinterpret_cast < void * * > ( & argv ) ) ;
if ( NS_SUCCEEDED ( rv ) & & ! aArgsOut . append ( argv , argc ) ) {
rv = NS_ERROR_OUT_OF_MEMORY ;
}
return rv ;
}
2010-01-25 08:48:07 -08:00
2007-03-22 10:30:00 -07:00
// Take the slower path converting each item.
// Handle only nsIArray and nsIVariant. nsIArray is only needed for
// SetProperty('arguments', ...);
nsIXPConnect * xpc = nsContentUtils : : XPConnect ( ) ;
NS_ENSURE_TRUE ( xpc , NS_ERROR_UNEXPECTED ) ;
2013-05-22 09:05:24 -07:00
AutoJSContext cx ;
2007-03-22 10:30:00 -07:00
if ( ! aArgs )
return NS_OK ;
2012-08-22 08:56:38 -07:00
uint32_t argCount ;
2007-03-22 10:30:00 -07:00
// This general purpose function may need to convert an arg array
// (window.arguments, event-handler args) and a generic property.
nsCOMPtr < nsIArray > argsArray ( do_QueryInterface ( aArgs ) ) ;
if ( argsArray ) {
rv = argsArray - > GetLength ( & argCount ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
if ( argCount = = 0 )
return NS_OK ;
} else {
argCount = 1 ; // the nsISupports which is not an array
}
2010-02-17 11:32:47 -08:00
// Use the caller's auto guards to release and unroot.
2014-02-11 02:59:15 -08:00
if ( ! aArgsOut . resize ( argCount ) ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
2010-01-25 08:48:07 -08:00
2007-03-22 10:30:00 -07:00
if ( argsArray ) {
2012-08-22 08:56:38 -07:00
for ( uint32_t argCtr = 0 ; argCtr < argCount & & NS_SUCCEEDED ( rv ) ; argCtr + + ) {
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsISupports > arg ;
2014-02-11 02:59:15 -08:00
JS : : MutableHandle < JS : : Value > thisVal = aArgsOut . handleAt ( argCtr ) ;
2007-03-22 10:30:00 -07:00
argsArray - > QueryElementAt ( argCtr , NS_GET_IID ( nsISupports ) ,
getter_AddRefs ( arg ) ) ;
if ( ! arg ) {
2014-02-11 02:59:15 -08:00
thisVal . setNull ( ) ;
2007-03-22 10:30:00 -07:00
continue ;
}
nsCOMPtr < nsIVariant > variant ( do_QueryInterface ( arg ) ) ;
2012-07-30 07:20:58 -07:00
if ( variant ! = nullptr ) {
2014-02-11 02:59:15 -08:00
rv = xpc - > VariantToJS ( cx , aScope , variant , thisVal ) ;
2007-03-22 10:30:00 -07:00
} else {
// And finally, support the nsISupportsPrimitives supplied
// by the AppShell. It generally will pass only strings, but
// as we have code for handling all, we may as well use it.
2014-02-11 02:59:15 -08:00
rv = AddSupportsPrimitiveTojsvals ( arg , thisVal . address ( ) ) ;
2007-03-22 10:30:00 -07:00
if ( rv = = NS_ERROR_NO_INTERFACE ) {
2007-07-26 10:52:26 -07:00
// something else - probably an event object or similar -
2007-03-22 10:30:00 -07:00
// just wrap it.
2012-06-25 12:59:42 -07:00
# ifdef DEBUG
2007-03-22 10:30:00 -07:00
// but first, check its not another nsISupportsPrimitive, as
// these are now deprecated for use with script contexts.
nsCOMPtr < nsISupportsPrimitive > prim ( do_QueryInterface ( arg ) ) ;
2012-07-30 07:20:58 -07:00
NS_ASSERTION ( prim = = nullptr ,
2007-03-22 10:30:00 -07:00
" Don't pass nsISupportsPrimitives - use nsIVariant! " ) ;
# endif
2014-02-11 02:59:15 -08:00
rv = nsContentUtils : : WrapNative ( cx , aScope , arg , thisVal ) ;
2007-03-22 10:30:00 -07:00
}
}
}
} else {
2011-10-29 13:06:17 -07:00
nsCOMPtr < nsIVariant > variant = do_QueryInterface ( aArgs ) ;
if ( variant ) {
2014-02-11 02:59:15 -08:00
rv = xpc - > VariantToJS ( cx , aScope , variant , aArgsOut . handleAt ( 0 ) ) ;
2011-10-29 13:06:17 -07:00
} else {
2007-03-22 10:30:00 -07:00
NS_ERROR ( " Not an array, not an interface? " ) ;
rv = NS_ERROR_UNEXPECTED ;
}
}
2014-02-11 02:59:15 -08:00
return rv ;
2007-03-22 10:30:00 -07:00
}
// This really should go into xpconnect somewhere...
nsresult
2013-04-11 15:52:10 -07:00
nsJSContext : : AddSupportsPrimitiveTojsvals ( nsISupports * aArg , JS : : Value * aArgv )
2007-03-22 10:30:00 -07:00
{
NS_PRECONDITION ( aArg , " Empty arg " ) ;
nsCOMPtr < nsISupportsPrimitive > argPrimitive ( do_QueryInterface ( aArg ) ) ;
if ( ! argPrimitive )
return NS_ERROR_NO_INTERFACE ;
2013-05-22 09:05:24 -07:00
AutoJSContext cx ;
2012-08-22 08:56:38 -07:00
uint16_t type ;
2007-03-22 10:30:00 -07:00
argPrimitive - > GetType ( & type ) ;
switch ( type ) {
case nsISupportsPrimitive : : TYPE_CSTRING : {
nsCOMPtr < nsISupportsCString > p ( do_QueryInterface ( argPrimitive ) ) ;
NS_ENSURE_TRUE ( p , NS_ERROR_UNEXPECTED ) ;
2012-09-01 19:35:17 -07:00
nsAutoCString data ;
2007-03-22 10:30:00 -07:00
p - > GetData ( data ) ;
2008-07-26 16:17:12 -07:00
2007-03-22 10:30:00 -07:00
JSString * str = : : JS_NewStringCopyN ( cx , data . get ( ) , data . Length ( ) ) ;
NS_ENSURE_TRUE ( str , NS_ERROR_OUT_OF_MEMORY ) ;
* aArgv = STRING_TO_JSVAL ( str ) ;
break ;
}
case nsISupportsPrimitive : : TYPE_STRING : {
nsCOMPtr < nsISupportsString > p ( do_QueryInterface ( argPrimitive ) ) ;
NS_ENSURE_TRUE ( p , NS_ERROR_UNEXPECTED ) ;
nsAutoString data ;
p - > GetData ( data ) ;
// cast is probably safe since wchar_t and jschar are expected
// to be equivalent; both unsigned 16-bit entities
JSString * str =
2013-12-04 04:19:38 -08:00
: : JS_NewUCStringCopyN ( cx , data . get ( ) , data . Length ( ) ) ;
2007-03-22 10:30:00 -07:00
NS_ENSURE_TRUE ( str , NS_ERROR_OUT_OF_MEMORY ) ;
* aArgv = STRING_TO_JSVAL ( str ) ;
break ;
}
case nsISupportsPrimitive : : TYPE_PRBOOL : {
nsCOMPtr < nsISupportsPRBool > p ( do_QueryInterface ( argPrimitive ) ) ;
NS_ENSURE_TRUE ( p , NS_ERROR_UNEXPECTED ) ;
2011-09-28 23:19:26 -07:00
bool data ;
2007-03-22 10:30:00 -07:00
p - > GetData ( & data ) ;
* aArgv = BOOLEAN_TO_JSVAL ( data ) ;
break ;
}
case nsISupportsPrimitive : : TYPE_PRUINT8 : {
nsCOMPtr < nsISupportsPRUint8 > p ( do_QueryInterface ( argPrimitive ) ) ;
NS_ENSURE_TRUE ( p , NS_ERROR_UNEXPECTED ) ;
2012-08-22 08:56:38 -07:00
uint8_t data ;
2007-03-22 10:30:00 -07:00
p - > GetData ( & data ) ;
* aArgv = INT_TO_JSVAL ( data ) ;
break ;
}
case nsISupportsPrimitive : : TYPE_PRUINT16 : {
nsCOMPtr < nsISupportsPRUint16 > p ( do_QueryInterface ( argPrimitive ) ) ;
NS_ENSURE_TRUE ( p , NS_ERROR_UNEXPECTED ) ;
2012-08-22 08:56:38 -07:00
uint16_t data ;
2007-03-22 10:30:00 -07:00
p - > GetData ( & data ) ;
* aArgv = INT_TO_JSVAL ( data ) ;
break ;
}
case nsISupportsPrimitive : : TYPE_PRUINT32 : {
nsCOMPtr < nsISupportsPRUint32 > p ( do_QueryInterface ( argPrimitive ) ) ;
NS_ENSURE_TRUE ( p , NS_ERROR_UNEXPECTED ) ;
2012-08-22 08:56:38 -07:00
uint32_t data ;
2007-03-22 10:30:00 -07:00
p - > GetData ( & data ) ;
* aArgv = INT_TO_JSVAL ( data ) ;
break ;
}
case nsISupportsPrimitive : : TYPE_CHAR : {
nsCOMPtr < nsISupportsChar > p ( do_QueryInterface ( argPrimitive ) ) ;
NS_ENSURE_TRUE ( p , NS_ERROR_UNEXPECTED ) ;
char data ;
p - > GetData ( & data ) ;
JSString * str = : : JS_NewStringCopyN ( cx , & data , 1 ) ;
NS_ENSURE_TRUE ( str , NS_ERROR_OUT_OF_MEMORY ) ;
* aArgv = STRING_TO_JSVAL ( str ) ;
break ;
}
case nsISupportsPrimitive : : TYPE_PRINT16 : {
nsCOMPtr < nsISupportsPRInt16 > p ( do_QueryInterface ( argPrimitive ) ) ;
NS_ENSURE_TRUE ( p , NS_ERROR_UNEXPECTED ) ;
2012-08-22 08:56:38 -07:00
int16_t data ;
2007-03-22 10:30:00 -07:00
p - > GetData ( & data ) ;
* aArgv = INT_TO_JSVAL ( data ) ;
break ;
}
case nsISupportsPrimitive : : TYPE_PRINT32 : {
nsCOMPtr < nsISupportsPRInt32 > p ( do_QueryInterface ( argPrimitive ) ) ;
NS_ENSURE_TRUE ( p , NS_ERROR_UNEXPECTED ) ;
2012-08-22 08:56:38 -07:00
int32_t data ;
2007-03-22 10:30:00 -07:00
p - > GetData ( & data ) ;
* aArgv = INT_TO_JSVAL ( data ) ;
break ;
}
case nsISupportsPrimitive : : TYPE_FLOAT : {
nsCOMPtr < nsISupportsFloat > p ( do_QueryInterface ( argPrimitive ) ) ;
NS_ENSURE_TRUE ( p , NS_ERROR_UNEXPECTED ) ;
float data ;
p - > GetData ( & data ) ;
2012-08-01 17:59:47 -07:00
* aArgv = : : JS_NumberValue ( data ) ;
2007-03-22 10:30:00 -07:00
break ;
}
case nsISupportsPrimitive : : TYPE_DOUBLE : {
nsCOMPtr < nsISupportsDouble > p ( do_QueryInterface ( argPrimitive ) ) ;
NS_ENSURE_TRUE ( p , NS_ERROR_UNEXPECTED ) ;
double data ;
p - > GetData ( & data ) ;
2012-08-01 17:59:47 -07:00
* aArgv = : : JS_NumberValue ( data ) ;
2007-03-22 10:30:00 -07:00
break ;
}
case nsISupportsPrimitive : : TYPE_INTERFACE_POINTER : {
nsCOMPtr < nsISupportsInterfacePointer > p ( do_QueryInterface ( argPrimitive ) ) ;
NS_ENSURE_TRUE ( p , NS_ERROR_UNEXPECTED ) ;
nsCOMPtr < nsISupports > data ;
2012-07-30 07:20:58 -07:00
nsIID * iid = nullptr ;
2007-03-22 10:30:00 -07:00
p - > GetData ( getter_AddRefs ( data ) ) ;
p - > GetDataIID ( & iid ) ;
NS_ENSURE_TRUE ( iid , NS_ERROR_UNEXPECTED ) ;
AutoFree iidGuard ( iid ) ; // Free iid upon destruction.
2013-09-04 14:06:57 -07:00
JS : : Rooted < JSObject * > global ( cx , GetWindowProxy ( ) ) ;
2013-05-02 02:12:46 -07:00
JS : : Rooted < JS : : Value > v ( cx ) ;
2012-03-20 21:29:47 -07:00
nsresult rv = nsContentUtils : : WrapNative ( cx , global ,
2014-01-06 11:54:43 -08:00
data , iid , & v ) ;
2007-03-22 10:30:00 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2009-08-14 12:00:24 -07:00
* aArgv = v ;
2007-03-22 10:30:00 -07:00
break ;
}
case nsISupportsPrimitive : : TYPE_ID :
case nsISupportsPrimitive : : TYPE_PRUINT64 :
case nsISupportsPrimitive : : TYPE_PRINT64 :
case nsISupportsPrimitive : : TYPE_PRTIME :
case nsISupportsPrimitive : : TYPE_VOID : {
NS_WARNING ( " Unsupported primitive type used " ) ;
* aArgv = JSVAL_NULL ;
break ;
}
default : {
NS_WARNING ( " Unknown primitive type used " ) ;
* aArgv = JSVAL_NULL ;
break ;
}
}
return NS_OK ;
}
# ifdef NS_TRACE_MALLOC
# include <errno.h> // XXX assume Linux if NS_TRACE_MALLOC
# include <fcntl.h>
# ifdef XP_UNIX
# include <unistd.h>
# endif
# ifdef XP_WIN32
# include <io.h>
# endif
# include "nsTraceMalloc.h"
2013-08-02 00:41:57 -07:00
static bool
2010-10-17 19:36:25 -07:00
CheckUniversalXPConnectForTraceMalloc ( JSContext * cx )
{
2012-10-21 23:29:55 -07:00
if ( nsContentUtils : : IsCallerChrome ( ) )
2013-08-02 00:41:57 -07:00
return true ;
2010-10-17 19:36:25 -07:00
JS_ReportError ( cx , " trace-malloc functions require UniversalXPConnect " ) ;
2013-08-02 00:41:57 -07:00
return false ;
2010-10-17 19:36:25 -07:00
}
2013-08-02 00:41:57 -07:00
static bool
2013-04-11 15:52:10 -07:00
TraceMallocDisable ( JSContext * cx , unsigned argc , JS : : Value * vp )
2007-03-22 10:30:00 -07:00
{
2014-03-19 10:05:04 -07:00
JS : : CallArgs args = JS : : CallArgsFromVp ( argc , vp ) ;
2010-10-17 19:36:25 -07:00
if ( ! CheckUniversalXPConnectForTraceMalloc ( cx ) )
2013-08-02 00:41:57 -07:00
return false ;
2010-10-17 19:36:25 -07:00
2007-03-22 10:30:00 -07:00
NS_TraceMallocDisable ( ) ;
2014-03-19 10:05:04 -07:00
args . rval ( ) . setUndefined ( ) ;
2013-08-02 00:41:57 -07:00
return true ;
2007-03-22 10:30:00 -07:00
}
2013-08-02 00:41:57 -07:00
static bool
2013-04-11 15:52:10 -07:00
TraceMallocEnable ( JSContext * cx , unsigned argc , JS : : Value * vp )
2007-03-22 10:30:00 -07:00
{
2014-03-19 10:05:04 -07:00
JS : : CallArgs args = JS : : CallArgsFromVp ( argc , vp ) ;
2010-10-17 19:36:25 -07:00
if ( ! CheckUniversalXPConnectForTraceMalloc ( cx ) )
2013-08-02 00:41:57 -07:00
return false ;
2010-10-17 19:36:25 -07:00
2007-03-22 10:30:00 -07:00
NS_TraceMallocEnable ( ) ;
2014-03-19 10:05:04 -07:00
args . rval ( ) . setUndefined ( ) ;
2013-08-02 00:41:57 -07:00
return true ;
2007-03-22 10:30:00 -07:00
}
2013-08-02 00:41:57 -07:00
static bool
2013-04-11 15:52:10 -07:00
TraceMallocOpenLogFile ( JSContext * cx , unsigned argc , JS : : Value * vp )
2007-03-22 10:30:00 -07:00
{
2013-11-16 04:31:36 -08:00
JS : : CallArgs args = JS : : CallArgsFromVp ( argc , vp ) ;
2007-03-22 10:30:00 -07:00
2010-10-17 19:36:25 -07:00
if ( ! CheckUniversalXPConnectForTraceMalloc ( cx ) )
2013-08-02 00:41:57 -07:00
return false ;
2010-10-17 19:36:25 -07:00
2013-11-16 04:31:36 -08:00
int fd ;
2007-03-22 10:30:00 -07:00
if ( argc = = 0 ) {
fd = - 1 ;
} else {
2013-11-16 04:31:36 -08:00
JSString * str = JS : : ToString ( cx , args [ 0 ] ) ;
2007-03-22 10:30:00 -07:00
if ( ! str )
2013-08-02 00:41:57 -07:00
return false ;
2010-11-11 12:40:29 -08:00
JSAutoByteString filename ( cx , str ) ;
if ( ! filename )
2013-08-02 00:41:57 -07:00
return false ;
2010-11-11 12:40:29 -08:00
fd = open ( filename . ptr ( ) , O_CREAT | O_WRONLY | O_TRUNC , 0644 ) ;
2007-03-22 10:30:00 -07:00
if ( fd < 0 ) {
2010-11-11 12:40:29 -08:00
JS_ReportError ( cx , " can't open %s: %s " , filename . ptr ( ) , strerror ( errno ) ) ;
2013-08-02 00:41:57 -07:00
return false ;
2007-03-22 10:30:00 -07:00
}
}
2013-11-16 04:31:36 -08:00
args . rval ( ) . setInt32 ( fd ) ;
2013-08-02 00:41:57 -07:00
return true ;
2007-03-22 10:30:00 -07:00
}
2013-08-02 00:41:57 -07:00
static bool
2013-04-11 15:52:10 -07:00
TraceMallocChangeLogFD ( JSContext * cx , unsigned argc , JS : : Value * vp )
2007-03-22 10:30:00 -07:00
{
2013-08-15 14:41:51 -07:00
JS : : CallArgs args = CallArgsFromVp ( argc , vp ) ;
2010-10-17 19:36:25 -07:00
if ( ! CheckUniversalXPConnectForTraceMalloc ( cx ) )
2013-08-02 00:41:57 -07:00
return false ;
2010-10-17 19:36:25 -07:00
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
int32_t fd , oldfd ;
2013-08-15 14:41:51 -07:00
if ( args . length ( ) = = 0 ) {
2007-03-22 10:30:00 -07:00
oldfd = - 1 ;
} else {
2013-08-15 14:41:51 -07:00
if ( ! JS : : ToInt32 ( cx , args [ 0 ] , & fd ) )
2013-08-02 00:41:57 -07:00
return false ;
2007-03-22 10:30:00 -07:00
oldfd = NS_TraceMallocChangeLogFD ( fd ) ;
if ( oldfd = = - 2 ) {
JS_ReportOutOfMemory ( cx ) ;
2013-08-02 00:41:57 -07:00
return false ;
2007-03-22 10:30:00 -07:00
}
}
2013-08-15 14:41:51 -07:00
args . rval ( ) . setInt32 ( oldfd ) ;
2013-08-02 00:41:57 -07:00
return true ;
2007-03-22 10:30:00 -07:00
}
2013-08-02 00:41:57 -07:00
static bool
2013-04-11 15:52:10 -07:00
TraceMallocCloseLogFD ( JSContext * cx , unsigned argc , JS : : Value * vp )
2007-03-22 10:30:00 -07:00
{
2013-08-15 14:41:51 -07:00
JS : : CallArgs args = CallArgsFromVp ( argc , vp ) ;
2010-10-17 19:36:25 -07:00
if ( ! CheckUniversalXPConnectForTraceMalloc ( cx ) )
2013-08-02 00:41:57 -07:00
return false ;
2010-10-17 19:36:25 -07:00
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
int32_t fd ;
2013-08-15 14:41:51 -07:00
if ( args . length ( ) = = 0 ) {
args . rval ( ) . setUndefined ( ) ;
2013-08-02 00:41:57 -07:00
return true ;
2013-08-15 14:41:51 -07:00
}
if ( ! JS : : ToInt32 ( cx , args [ 0 ] , & fd ) )
2013-08-02 00:41:57 -07:00
return false ;
2007-03-22 10:30:00 -07:00
NS_TraceMallocCloseLogFD ( ( int ) fd ) ;
2013-08-15 14:41:51 -07:00
args . rval ( ) . setInt32 ( fd ) ;
2013-08-02 00:41:57 -07:00
return true ;
2007-03-22 10:30:00 -07:00
}
2013-08-02 00:41:57 -07:00
static bool
2013-04-11 15:52:10 -07:00
TraceMallocLogTimestamp ( JSContext * cx , unsigned argc , JS : : Value * vp )
2007-03-22 10:30:00 -07:00
{
2013-11-16 04:31:36 -08:00
JS : : CallArgs args = JS : : CallArgsFromVp ( argc , vp ) ;
2010-10-17 19:36:25 -07:00
if ( ! CheckUniversalXPConnectForTraceMalloc ( cx ) )
2013-08-02 00:41:57 -07:00
return false ;
2010-10-17 19:36:25 -07:00
2013-11-16 04:31:36 -08:00
JSString * str = JS : : ToString ( cx , args . get ( 0 ) ) ;
2007-03-22 10:30:00 -07:00
if ( ! str )
2013-08-02 00:41:57 -07:00
return false ;
2010-11-11 12:40:29 -08:00
JSAutoByteString caption ( cx , str ) ;
if ( ! caption )
2013-08-02 00:41:57 -07:00
return false ;
2010-11-11 12:40:29 -08:00
NS_TraceMallocLogTimestamp ( caption . ptr ( ) ) ;
2013-11-16 04:31:36 -08:00
args . rval ( ) . setUndefined ( ) ;
2013-08-02 00:41:57 -07:00
return true ;
2007-03-22 10:30:00 -07:00
}
2013-08-02 00:41:57 -07:00
static bool
2013-04-11 15:52:10 -07:00
TraceMallocDumpAllocations ( JSContext * cx , unsigned argc , JS : : Value * vp )
2007-03-22 10:30:00 -07:00
{
2013-11-16 04:31:36 -08:00
JS : : CallArgs args = JS : : CallArgsFromVp ( argc , vp ) ;
2010-10-17 19:36:25 -07:00
if ( ! CheckUniversalXPConnectForTraceMalloc ( cx ) )
2013-08-02 00:41:57 -07:00
return false ;
2010-10-17 19:36:25 -07:00
2013-11-16 04:31:36 -08:00
JSString * str = JS : : ToString ( cx , args . get ( 0 ) ) ;
2007-03-22 10:30:00 -07:00
if ( ! str )
2013-08-02 00:41:57 -07:00
return false ;
2010-11-11 12:40:29 -08:00
JSAutoByteString pathname ( cx , str ) ;
if ( ! pathname )
2013-08-02 00:41:57 -07:00
return false ;
2010-11-11 12:40:29 -08:00
if ( NS_TraceMallocDumpAllocations ( pathname . ptr ( ) ) < 0 ) {
JS_ReportError ( cx , " can't dump to %s: %s " , pathname . ptr ( ) , strerror ( errno ) ) ;
2013-08-02 00:41:57 -07:00
return false ;
2007-03-22 10:30:00 -07:00
}
2013-11-16 04:31:36 -08:00
args . rval ( ) . setUndefined ( ) ;
2013-08-02 00:41:57 -07:00
return true ;
2007-03-22 10:30:00 -07:00
}
2013-04-22 14:15:49 -07:00
static const JSFunctionSpec TraceMallocFunctions [ ] = {
2012-08-07 22:26:19 -07:00
JS_FS ( " TraceMallocDisable " , TraceMallocDisable , 0 , 0 ) ,
JS_FS ( " TraceMallocEnable " , TraceMallocEnable , 0 , 0 ) ,
JS_FS ( " TraceMallocOpenLogFile " , TraceMallocOpenLogFile , 1 , 0 ) ,
JS_FS ( " TraceMallocChangeLogFD " , TraceMallocChangeLogFD , 1 , 0 ) ,
JS_FS ( " TraceMallocCloseLogFD " , TraceMallocCloseLogFD , 1 , 0 ) ,
JS_FS ( " TraceMallocLogTimestamp " , TraceMallocLogTimestamp , 1 , 0 ) ,
JS_FS ( " TraceMallocDumpAllocations " , TraceMallocDumpAllocations , 1 , 0 ) ,
JS_FS_END
2007-03-22 10:30:00 -07:00
} ;
# endif /* NS_TRACE_MALLOC */
2012-12-10 16:05:07 -08:00
# ifdef MOZ_DMD
# include <errno.h>
namespace mozilla {
namespace dmd {
// See https://wiki.mozilla.org/Performance/MemShrink/DMD for instructions on
// how to use DMD.
2013-08-02 00:41:57 -07:00
static bool
2013-04-11 15:52:10 -07:00
ReportAndDump ( JSContext * cx , unsigned argc , JS : : Value * vp )
2012-12-10 16:05:07 -08:00
{
2013-11-16 04:31:36 -08:00
JS : : CallArgs args = JS : : CallArgsFromVp ( argc , vp ) ;
JSString * str = JS : : ToString ( cx , args . get ( 0 ) ) ;
2012-12-10 16:05:07 -08:00
if ( ! str )
2013-08-02 00:41:57 -07:00
return false ;
2012-12-10 16:05:07 -08:00
JSAutoByteString pathname ( cx , str ) ;
if ( ! pathname )
2013-08-02 00:41:57 -07:00
return false ;
2012-12-10 16:05:07 -08:00
FILE * fp = fopen ( pathname . ptr ( ) , " w " ) ;
if ( ! fp ) {
JS_ReportError ( cx , " DMD can't open %s: %s " ,
pathname . ptr ( ) , strerror ( errno ) ) ;
2013-08-02 00:41:57 -07:00
return false ;
2012-12-10 16:05:07 -08:00
}
2013-01-06 13:34:39 -08:00
dmd : : ClearReports ( ) ;
fprintf ( stderr , " DMD: running reporters... \n " ) ;
2013-12-01 16:29:37 -08:00
dmd : : RunReportersForThisProcess ( ) ;
2012-12-10 16:05:07 -08:00
dmd : : Writer writer ( FpWrite , fp ) ;
dmd : : Dump ( writer ) ;
fclose ( fp ) ;
2013-11-16 04:31:36 -08:00
args . rval ( ) . setUndefined ( ) ;
2013-08-02 00:41:57 -07:00
return true ;
2012-12-10 16:05:07 -08:00
}
} // namespace dmd
} // namespace mozilla
2013-04-22 14:15:49 -07:00
static const JSFunctionSpec DMDFunctions [ ] = {
2012-12-10 16:05:07 -08:00
JS_FS ( " DMDReportAndDump " , dmd : : ReportAndDump , 1 , 0 ) ,
JS_FS_END
} ;
# endif // defined(MOZ_DMD)
2007-03-22 10:30:00 -07:00
# ifdef MOZ_JPROF
# include <signal.h>
2011-09-28 23:19:26 -07:00
inline bool
2007-03-22 10:30:00 -07:00
IsJProfAction ( struct sigaction * action )
{
return ( action - > sa_sigaction & &
2011-11-07 21:34:40 -08:00
( action - > sa_flags & ( SA_RESTART | SA_SIGINFO ) ) = = ( SA_RESTART | SA_SIGINFO ) ) ;
2007-03-22 10:30:00 -07:00
}
void NS_JProfStartProfiling ( ) ;
void NS_JProfStopProfiling ( ) ;
2011-11-07 21:34:40 -08:00
void NS_JProfClearCircular ( ) ;
2007-03-22 10:30:00 -07:00
2013-08-02 00:41:57 -07:00
static bool
2013-04-11 15:52:10 -07:00
JProfStartProfilingJS ( JSContext * cx , unsigned argc , JS : : Value * vp )
2007-03-22 10:30:00 -07:00
{
NS_JProfStartProfiling ( ) ;
2013-08-02 00:41:57 -07:00
return true ;
2007-03-22 10:30:00 -07:00
}
void NS_JProfStartProfiling ( )
{
// Figure out whether we're dealing with SIGPROF, SIGALRM, or
// SIGPOLL profiling (SIGALRM for JP_REALTIME, SIGPOLL for
// JP_RTC_HZ)
struct sigaction action ;
2011-11-07 21:34:40 -08:00
// Must check ALRM before PROF since both are enabled for real-time
2012-07-30 07:20:58 -07:00
sigaction ( SIGALRM , nullptr , & action ) ;
2011-11-07 21:34:40 -08:00
//printf("SIGALRM: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
2007-03-22 10:30:00 -07:00
if ( IsJProfAction ( & action ) ) {
2011-11-07 21:34:40 -08:00
//printf("Beginning real-time jprof profiling.\n");
2007-03-22 10:30:00 -07:00
raise ( SIGALRM ) ;
return ;
}
2012-07-30 07:20:58 -07:00
sigaction ( SIGPROF , nullptr , & action ) ;
2011-11-07 21:34:40 -08:00
//printf("SIGPROF: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
2007-03-22 10:30:00 -07:00
if ( IsJProfAction ( & action ) ) {
2011-11-07 21:34:40 -08:00
//printf("Beginning process-time jprof profiling.\n");
2007-03-22 10:30:00 -07:00
raise ( SIGPROF ) ;
return ;
}
2012-07-30 07:20:58 -07:00
sigaction ( SIGPOLL , nullptr , & action ) ;
2011-11-07 21:34:40 -08:00
//printf("SIGPOLL: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
2007-03-22 10:30:00 -07:00
if ( IsJProfAction ( & action ) ) {
2011-11-07 21:34:40 -08:00
//printf("Beginning rtc-based jprof profiling.\n");
2007-03-22 10:30:00 -07:00
raise ( SIGPOLL ) ;
return ;
}
printf ( " Could not start jprof-profiling since JPROF_FLAGS was not set. \n " ) ;
}
2013-08-02 00:41:57 -07:00
static bool
2013-04-11 15:52:10 -07:00
JProfStopProfilingJS ( JSContext * cx , unsigned argc , JS : : Value * vp )
2007-03-22 10:30:00 -07:00
{
NS_JProfStopProfiling ( ) ;
2013-08-02 00:41:57 -07:00
return true ;
2007-03-22 10:30:00 -07:00
}
void
NS_JProfStopProfiling ( )
{
raise ( SIGUSR1 ) ;
2011-11-07 21:34:40 -08:00
//printf("Stopped jprof profiling.\n");
}
2013-08-02 00:41:57 -07:00
static bool
2013-04-11 15:52:10 -07:00
JProfClearCircularJS ( JSContext * cx , unsigned argc , JS : : Value * vp )
2011-11-07 21:34:40 -08:00
{
NS_JProfClearCircular ( ) ;
2013-08-02 00:41:57 -07:00
return true ;
2011-11-07 21:34:40 -08:00
}
void
NS_JProfClearCircular ( )
{
raise ( SIGUSR2 ) ;
//printf("cleared jprof buffer\n");
}
2013-08-02 00:41:57 -07:00
static bool
2013-04-11 15:52:10 -07:00
JProfSaveCircularJS ( JSContext * cx , unsigned argc , JS : : Value * vp )
2011-11-07 21:34:40 -08:00
{
// Not ideal...
NS_JProfStopProfiling ( ) ;
NS_JProfStartProfiling ( ) ;
2013-08-02 00:41:57 -07:00
return true ;
2007-03-22 10:30:00 -07:00
}
2013-04-22 14:15:49 -07:00
static const JSFunctionSpec JProfFunctions [ ] = {
2012-10-04 16:01:32 -07:00
JS_FS ( " JProfStartProfiling " , JProfStartProfilingJS , 0 , 0 ) ,
JS_FS ( " JProfStopProfiling " , JProfStopProfilingJS , 0 , 0 ) ,
JS_FS ( " JProfClearCircular " , JProfClearCircularJS , 0 , 0 ) ,
JS_FS ( " JProfSaveCircular " , JProfSaveCircularJS , 0 , 0 ) ,
JS_FS_END
2007-03-22 10:30:00 -07:00
} ;
# endif /* defined(MOZ_JPROF) */
nsresult
2013-05-11 22:17:42 -07:00
nsJSContext : : InitClasses ( JS : : Handle < JSObject * > aGlobalObj )
2007-03-22 10:30:00 -07:00
{
2011-11-26 02:19:45 -08:00
nsresult rv = InitializeExternalClasses ( ) ;
2007-03-22 10:30:00 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2012-03-28 04:09:33 -07:00
JSOptionChangedCallback ( js_options_dot_str , this ) ;
2013-05-22 09:05:24 -07:00
AutoPushJSContext cx ( mContext ) ;
2007-03-22 10:30:00 -07:00
2011-01-14 17:58:40 -08:00
// Attempt to initialize profiling functions
2013-05-22 09:05:24 -07:00
: : JS_DefineProfilingFunctions ( cx , aGlobalObj ) ;
2011-01-14 17:58:40 -08:00
2007-03-22 10:30:00 -07:00
# ifdef NS_TRACE_MALLOC
2013-08-28 15:48:43 -07:00
if ( nsContentUtils : : IsCallerChrome ( ) ) {
// Attempt to initialize TraceMalloc functions
: : JS_DefineFunctions ( cx , aGlobalObj , TraceMallocFunctions ) ;
}
2007-03-22 10:30:00 -07:00
# endif
2012-12-10 16:05:07 -08:00
# ifdef MOZ_DMD
// Attempt to initialize DMD functions
2013-05-22 09:05:24 -07:00
: : JS_DefineFunctions ( cx , aGlobalObj , DMDFunctions ) ;
2012-12-10 16:05:07 -08:00
# endif
2007-03-22 10:30:00 -07:00
# ifdef MOZ_JPROF
// Attempt to initialize JProf functions
2013-05-22 09:05:24 -07:00
: : JS_DefineFunctions ( cx , aGlobalObj , JProfFunctions ) ;
2007-03-22 10:30:00 -07:00
# endif
return rv ;
}
void
nsJSContext : : WillInitializeContext ( )
{
2011-10-17 07:59:28 -07:00
mIsInitialized = false ;
2007-03-22 10:30:00 -07:00
}
void
nsJSContext : : DidInitializeContext ( )
{
2011-10-17 07:59:28 -07:00
mIsInitialized = true ;
2007-03-22 10:30:00 -07:00
}
2011-09-28 23:19:26 -07:00
bool
2007-03-22 10:30:00 -07:00
nsJSContext : : IsContextInitialized ( )
{
return mIsInitialized ;
}
2013-01-15 03:46:35 -08:00
bool
nsJSContext : : GetProcessingScriptTag ( )
{
return mProcessingScriptTag ;
}
void
nsJSContext : : SetProcessingScriptTag ( bool aFlag )
{
mProcessingScriptTag = aFlag ;
}
2012-05-09 11:53:23 -07:00
void
FullGCTimerFired ( nsITimer * aTimer , void * aClosure )
{
NS_RELEASE ( sFullGCTimer ) ;
uintptr_t reason = reinterpret_cast < uintptr_t > ( aClosure ) ;
2013-01-27 12:35:12 -08:00
nsJSContext : : GarbageCollectNow ( static_cast < JS : : gcreason : : Reason > ( reason ) ,
2012-06-30 14:16:32 -07:00
nsJSContext : : IncrementalGC ) ;
2012-05-09 11:53:23 -07:00
}
2007-10-22 14:42:25 -07:00
//static
void
2013-01-27 12:35:12 -08:00
nsJSContext : : GarbageCollectNow ( JS : : gcreason : : Reason aReason ,
2012-06-30 14:16:32 -07:00
IsIncremental aIncremental ,
IsCompartment aCompartment ,
2012-07-31 18:39:39 -07:00
IsShrinking aShrinking ,
int64_t aSliceMillis )
2007-10-22 14:42:25 -07:00
{
2013-03-15 21:47:02 -07:00
PROFILER_LABEL ( " GC " , " GarbageCollectNow " ) ;
2010-05-19 16:22:19 -07:00
2012-07-31 18:39:39 -07:00
MOZ_ASSERT_IF ( aSliceMillis , aIncremental = = IncrementalGC ) ;
2011-02-16 15:47:12 -08:00
KillGCTimer ( ) ;
2011-12-27 03:59:29 -08:00
KillShrinkGCBuffersTimer ( ) ;
2008-02-25 09:47:25 -08:00
2011-02-16 15:47:12 -08:00
// Reset sPendingLoadCount in case the timer that fired was a
// timer we scheduled due to a normal GC timer firing while
// documents were loading. If this happens we're waiting for a
// document that is taking a long time to load, and we effectively
// ignore the fact that the currently loading documents are still
// loading and move on as if they weren't.
sPendingLoadCount = 0 ;
2011-10-17 07:59:28 -07:00
sLoadingInProgress = false ;
2007-10-22 14:42:25 -07:00
2013-08-19 16:24:29 -07:00
if ( ! nsContentUtils : : XPConnect ( ) | | ! sRuntime ) {
2012-05-09 11:53:23 -07:00
return ;
2011-02-18 15:14:21 -08:00
}
2012-06-30 14:16:32 -07:00
2012-06-30 14:18:10 -07:00
if ( sCCLockedOut & & aIncremental = = IncrementalGC ) {
// We're in the middle of incremental GC. Do another slice.
2013-08-19 16:24:29 -07:00
JS : : PrepareForIncrementalGC ( sRuntime ) ;
JS : : IncrementalGC ( sRuntime , aReason , aSliceMillis ) ;
2012-06-30 14:18:10 -07:00
return ;
}
2013-08-19 16:24:29 -07:00
JS : : PrepareForFullGC ( sRuntime ) ;
2012-06-30 14:16:32 -07:00
if ( aIncremental = = IncrementalGC ) {
2014-01-10 14:44:28 -08:00
MOZ_ASSERT ( aShrinking = = NonShrinkingGC ) ;
2013-08-19 16:24:29 -07:00
JS : : IncrementalGC ( sRuntime , aReason , aSliceMillis ) ;
2014-01-10 14:44:28 -08:00
} else if ( aShrinking = = ShrinkingGC ) {
JS : : ShrinkingGC ( sRuntime , aReason ) ;
2012-06-30 14:16:32 -07:00
} else {
2013-08-19 16:24:29 -07:00
JS : : GCForReason ( sRuntime , aReason ) ;
2012-06-30 14:16:32 -07:00
}
2007-10-22 14:42:25 -07:00
}
2011-12-27 03:59:29 -08:00
//static
void
nsJSContext : : ShrinkGCBuffersNow ( )
{
2013-03-15 21:47:02 -07:00
PROFILER_LABEL ( " GC " , " ShrinkGCBuffersNow " ) ;
2011-12-27 03:59:29 -08:00
KillShrinkGCBuffersTimer ( ) ;
2013-08-19 16:24:29 -07:00
JS : : ShrinkGCBuffers ( sRuntime ) ;
2011-12-27 03:59:29 -08:00
}
2012-12-31 12:54:37 -08:00
static void
FinishAnyIncrementalGC ( )
{
if ( sCCLockedOut ) {
// We're in the middle of an incremental GC, so finish it.
2013-08-19 16:24:29 -07:00
JS : : PrepareForIncrementalGC ( sRuntime ) ;
JS : : FinishIncrementalGC ( sRuntime , JS : : gcreason : : CC_FORCED ) ;
2012-12-31 12:54:37 -08:00
}
}
2012-07-15 03:30:39 -07:00
static void
2012-08-22 08:56:38 -07:00
FireForgetSkippable ( uint32_t aSuspected , bool aRemoveChildless )
2012-07-15 03:30:39 -07:00
{
PRTime startTime = PR_Now ( ) ;
2012-12-31 12:54:37 -08:00
FinishAnyIncrementalGC ( ) ;
2013-07-27 03:48:45 -07:00
bool earlyForgetSkippable =
sCleanupsSinceLastGC < NS_MAJOR_FORGET_SKIPPABLE_CALLS ;
nsCycleCollector_forgetSkippable ( aRemoveChildless , earlyForgetSkippable ) ;
2012-07-15 03:30:39 -07:00
sPreviousSuspectedCount = nsCycleCollector_suspectedCount ( ) ;
+ + sCleanupsSinceLastGC ;
PRTime delta = PR_Now ( ) - startTime ;
if ( sMinForgetSkippableTime > delta ) {
sMinForgetSkippableTime = delta ;
}
if ( sMaxForgetSkippableTime < delta ) {
sMaxForgetSkippableTime = delta ;
}
sTotalForgetSkippableTime + = delta ;
sRemovedPurples + = ( aSuspected - sPreviousSuspectedCount ) ;
+ + sForgetSkippableBeforeCC ;
}
2012-12-31 12:55:07 -08:00
MOZ_ALWAYS_INLINE
static uint32_t
2013-12-31 09:20:21 -08:00
TimeBetween ( TimeStamp start , TimeStamp end )
2012-12-31 12:55:07 -08:00
{
MOZ_ASSERT ( end > = start ) ;
2013-12-31 09:20:21 -08:00
return ( uint32_t ) ( ( end - start ) . ToMilliseconds ( ) ) ;
}
static uint32_t
TimeUntilNow ( TimeStamp start )
{
if ( start . IsNull ( ) ) {
return 0 ;
}
return TimeBetween ( start , TimeStamp : : Now ( ) ) ;
2012-12-31 12:55:07 -08:00
}
2013-11-20 14:35:16 -08:00
struct CycleCollectorStats
{
void Clear ( )
{
2013-12-31 09:20:21 -08:00
mBeginSliceTime = TimeStamp ( ) ;
2014-03-06 10:54:37 -08:00
mEndSliceTime = TimeStamp ( ) ;
2013-12-31 09:20:21 -08:00
mBeginTime = TimeStamp ( ) ;
2013-11-20 14:35:16 -08:00
mMaxGCDuration = 0 ;
mRanSyncForgetSkippable = false ;
mSuspected = 0 ;
mMaxSkippableDuration = 0 ;
2013-12-31 09:20:21 -08:00
mMaxSliceTime = 0 ;
2014-01-07 17:33:47 -08:00
mTotalSliceTime = 0 ;
2013-11-20 14:35:16 -08:00
mAnyLockedOut = false ;
2014-01-01 11:00:35 -08:00
mExtraForgetSkippableCalls = 0 ;
2013-11-20 14:35:16 -08:00
}
2013-12-31 09:20:21 -08:00
void PrepareForCycleCollectionSlice ( int32_t aExtraForgetSkippableCalls = 0 ) ;
2013-12-31 09:20:21 -08:00
void FinishCycleCollectionSlice ( )
{
2014-03-04 16:21:48 -08:00
if ( mBeginSliceTime . IsNull ( ) ) {
// We already called this method from EndCycleCollectionCallback for this slice.
return ;
}
2014-03-06 10:54:37 -08:00
mEndSliceTime = TimeStamp : : Now ( ) ;
uint32_t sliceTime = TimeBetween ( mBeginSliceTime , mEndSliceTime ) ;
2013-12-31 09:20:21 -08:00
mMaxSliceTime = std : : max ( mMaxSliceTime , sliceTime ) ;
2014-01-07 17:33:47 -08:00
mTotalSliceTime + = sliceTime ;
2014-03-04 16:21:48 -08:00
mBeginSliceTime = TimeStamp ( ) ;
2014-01-01 11:00:35 -08:00
MOZ_ASSERT ( mExtraForgetSkippableCalls = = 0 , " Forget to reset extra forget skippable calls? " ) ;
2013-12-31 09:20:21 -08:00
}
2014-01-01 11:00:35 -08:00
void RunForgetSkippable ( ) ;
2013-11-20 14:35:16 -08:00
// Time the current slice began, including any GC finishing.
2013-12-31 09:20:21 -08:00
TimeStamp mBeginSliceTime ;
2013-11-20 14:35:16 -08:00
2014-03-06 10:54:37 -08:00
// Time the previous slice of the current CC ended.
TimeStamp mEndSliceTime ;
2013-11-20 14:35:16 -08:00
// Time the current cycle collection began.
2013-12-31 09:20:21 -08:00
TimeStamp mBeginTime ;
2013-11-20 14:35:16 -08:00
// The longest GC finishing duration for any slice of the current CC.
uint32_t mMaxGCDuration ;
// True if we ran sync forget skippable in any slice of the current CC.
bool mRanSyncForgetSkippable ;
// Number of suspected objects at the start of the current CC.
uint32_t mSuspected ;
// The longest duration spent on sync forget skippable in any slice of the
2013-12-31 09:20:21 -08:00
// current CC.
2013-11-20 14:35:16 -08:00
uint32_t mMaxSkippableDuration ;
2013-12-31 09:20:21 -08:00
// The longest pause of any slice in the current CC.
uint32_t mMaxSliceTime ;
2014-01-07 17:33:47 -08:00
// The total amount of time spent actually running the current CC.
uint32_t mTotalSliceTime ;
2013-11-20 14:35:16 -08:00
// True if we were locked out by the GC in any slice of the current CC.
bool mAnyLockedOut ;
2014-01-01 11:00:35 -08:00
int32_t mExtraForgetSkippableCalls ;
2013-11-20 14:35:16 -08:00
} ;
CycleCollectorStats gCCStats ;
2013-12-31 09:20:21 -08:00
void
CycleCollectorStats : : PrepareForCycleCollectionSlice ( int32_t aExtraForgetSkippableCalls )
2013-11-20 14:35:17 -08:00
{
2013-12-31 09:20:21 -08:00
mBeginSliceTime = TimeStamp : : Now ( ) ;
2011-02-16 15:47:12 -08:00
2012-12-31 12:55:07 -08:00
// Before we begin the cycle collection, make sure there is no active GC.
2013-11-20 14:35:16 -08:00
if ( sCCLockedOut ) {
2013-12-31 09:20:21 -08:00
mAnyLockedOut = true ;
2013-11-20 14:35:16 -08:00
FinishAnyIncrementalGC ( ) ;
2014-03-04 16:21:48 -08:00
uint32_t gcTime = TimeBetween ( mBeginSliceTime , TimeStamp : : Now ( ) ) ;
2013-12-31 09:20:21 -08:00
mMaxGCDuration = std : : max ( mMaxGCDuration , gcTime ) ;
2013-11-20 14:35:16 -08:00
}
2012-01-30 12:06:18 -08:00
2014-01-01 11:00:35 -08:00
mExtraForgetSkippableCalls = aExtraForgetSkippableCalls ;
}
void
CycleCollectorStats : : RunForgetSkippable ( )
{
2012-12-31 12:55:07 -08:00
// Run forgetSkippable synchronously to reduce the size of the CC graph. This
// is particularly useful if we recently finished a GC.
2014-01-01 11:00:35 -08:00
if ( mExtraForgetSkippableCalls > = 0 ) {
TimeStamp beginForgetSkippable = TimeStamp : : Now ( ) ;
2013-11-20 14:35:16 -08:00
bool ranSyncForgetSkippable = false ;
2013-07-27 03:48:45 -07:00
while ( sCleanupsSinceLastGC < NS_MAJOR_FORGET_SKIPPABLE_CALLS ) {
2012-07-15 03:30:39 -07:00
FireForgetSkippable ( nsCycleCollector_suspectedCount ( ) , false ) ;
2012-12-31 12:55:07 -08:00
ranSyncForgetSkippable = true ;
2012-05-03 09:17:01 -07:00
}
2012-01-30 12:06:18 -08:00
2014-01-01 11:00:35 -08:00
for ( int32_t i = 0 ; i < mExtraForgetSkippableCalls ; + + i ) {
2013-11-20 14:35:16 -08:00
FireForgetSkippable ( nsCycleCollector_suspectedCount ( ) , false ) ;
ranSyncForgetSkippable = true ;
}
if ( ranSyncForgetSkippable ) {
2013-12-31 09:20:21 -08:00
mMaxSkippableDuration =
2014-01-01 11:00:35 -08:00
std : : max ( mMaxSkippableDuration , TimeUntilNow ( beginForgetSkippable ) ) ;
2013-12-31 09:20:21 -08:00
mRanSyncForgetSkippable = true ;
2013-11-20 14:35:16 -08:00
}
2012-01-30 12:06:18 -08:00
}
2014-01-01 11:00:35 -08:00
mExtraForgetSkippableCalls = 0 ;
2013-11-20 14:35:17 -08:00
}
2012-05-03 09:17:01 -07:00
2013-11-20 14:35:17 -08:00
//static
void
nsJSContext : : CycleCollectNow ( nsICycleCollectorListener * aListener ,
int32_t aExtraForgetSkippableCalls )
{
if ( ! NS_IsMainThread ( ) ) {
return ;
}
PROFILER_LABEL ( " CC " , " CycleCollectNow " ) ;
2013-12-31 09:20:21 -08:00
gCCStats . PrepareForCycleCollectionSlice ( aExtraForgetSkippableCalls ) ;
2013-11-20 14:35:17 -08:00
nsCycleCollector_collect ( aListener ) ;
2013-12-31 09:20:21 -08:00
gCCStats . FinishCycleCollectionSlice ( ) ;
2013-11-20 14:35:17 -08:00
}
//static
void
2014-03-04 16:21:48 -08:00
nsJSContext : : RunCycleCollectorSlice ( )
2013-11-20 14:35:17 -08:00
{
if ( ! NS_IsMainThread ( ) ) {
return ;
}
2013-11-20 14:35:16 -08:00
2014-01-01 11:00:35 -08:00
PROFILER_LABEL ( " CC " , " RunCycleCollectorSlice " ) ;
2013-12-22 06:58:19 -08:00
2013-12-31 09:20:21 -08:00
gCCStats . PrepareForCycleCollectionSlice ( ) ;
2014-03-06 10:54:37 -08:00
// Decide how long we want to budget for this slice. By default,
// use an unlimited budget.
int64_t sliceBudget = - 1 ;
if ( sIncrementalCC ) {
if ( gCCStats . mBeginTime . IsNull ( ) ) {
// If no CC is in progress, use the standard slice time.
sliceBudget = kICCSliceBudget ;
} else {
TimeStamp now = TimeStamp : : Now ( ) ;
// Only run a limited slice if we're within the max running time.
if ( TimeBetween ( gCCStats . mBeginTime , now ) < kMaxICCDuration ) {
float sliceMultiplier = std : : max ( TimeBetween ( gCCStats . mEndSliceTime , now ) / ( float ) kICCIntersliceDelay , 1.0f ) ;
sliceBudget = kICCSliceBudget * sliceMultiplier ;
}
}
}
nsCycleCollector_collectSlice ( sliceBudget ) ;
2013-12-31 09:20:21 -08:00
gCCStats . FinishCycleCollectionSlice ( ) ;
2013-12-18 21:22:55 -08:00
}
2013-12-21 06:35:08 -08:00
static void
ICCTimerFired ( nsITimer * aTimer , void * aClosure )
{
if ( sDidShutdown ) {
return ;
}
// Ignore ICC timer fires during IGC. Running ICC during an IGC will cause us
// to synchronously finish the GC, which is bad.
if ( sCCLockedOut ) {
PRTime now = PR_Now ( ) ;
if ( sCCLockedOutTime = = 0 ) {
sCCLockedOutTime = now ;
return ;
}
if ( now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME ) {
return ;
}
}
2014-03-04 16:21:48 -08:00
nsJSContext : : RunCycleCollectorSlice ( ) ;
2013-12-21 06:35:08 -08:00
}
2013-11-20 14:35:16 -08:00
//static
void
nsJSContext : : BeginCycleCollectionCallback ( )
{
MOZ_ASSERT ( NS_IsMainThread ( ) ) ;
2013-12-31 09:20:21 -08:00
gCCStats . mBeginTime = gCCStats . mBeginSliceTime . IsNull ( ) ? TimeStamp : : Now ( ) : gCCStats . mBeginSliceTime ;
2013-11-20 14:35:16 -08:00
gCCStats . mSuspected = nsCycleCollector_suspectedCount ( ) ;
KillCCTimer ( ) ;
2013-12-21 06:35:08 -08:00
2014-01-01 11:00:35 -08:00
gCCStats . RunForgetSkippable ( ) ;
2013-12-21 06:35:08 -08:00
MOZ_ASSERT ( ! sICCTimer , " Tried to create a new ICC timer when one already existed. " ) ;
if ( ! sIncrementalCC ) {
return ;
}
CallCreateInstance ( " @mozilla.org/timer;1 " , & sICCTimer ) ;
if ( sICCTimer ) {
sICCTimer - > InitWithFuncCallback ( ICCTimerFired ,
nullptr ,
kICCIntersliceDelay ,
nsITimer : : TYPE_REPEATING_SLACK ) ;
}
2013-11-20 14:35:16 -08:00
}
//static
void
nsJSContext : : EndCycleCollectionCallback ( CycleCollectorResults & aResults )
{
MOZ_ASSERT ( NS_IsMainThread ( ) ) ;
2012-06-27 08:10:09 -07:00
2013-12-21 06:35:08 -08:00
nsJSContext : : KillICCTimer ( ) ;
2014-03-04 16:21:48 -08:00
// Update timing information for the current slice before we log it, if
// we previously called PrepareForCycleCollectionSlice(). During shutdown
// CCs, this won't happen.
2013-12-31 09:20:21 -08:00
gCCStats . FinishCycleCollectionSlice ( ) ;
2013-11-20 14:35:16 -08:00
sCCollectedWaitingForGC + = aResults . mFreedRefCounted + aResults . mFreedGCed ;
2011-02-16 15:47:12 -08:00
2014-02-03 07:31:11 -08:00
if ( NeedsGCAfterCC ( ) ) {
2013-01-27 12:35:12 -08:00
PokeGC ( JS : : gcreason : : CC_WAITING ) ;
2010-11-07 11:07:59 -08:00
}
2014-02-18 06:58:40 -08:00
TimeStamp endCCTimeStamp = TimeStamp : : Now ( ) ;
PRTime endCCTime ;
if ( sPostGCEventsToObserver ) {
endCCTime = PR_Now ( ) ;
}
2012-12-31 12:55:07 -08:00
// Log information about the CC via telemetry, JSON and the console.
2014-02-18 06:58:40 -08:00
uint32_t ccNowDuration = TimeBetween ( gCCStats . mBeginTime , endCCTimeStamp ) ;
2013-11-20 14:35:16 -08:00
Telemetry : : Accumulate ( Telemetry : : CYCLE_COLLECTOR_FINISH_IGC , gCCStats . mAnyLockedOut ) ;
Telemetry : : Accumulate ( Telemetry : : CYCLE_COLLECTOR_SYNC_SKIPPABLE , gCCStats . mRanSyncForgetSkippable ) ;
2012-12-31 12:55:07 -08:00
Telemetry : : Accumulate ( Telemetry : : CYCLE_COLLECTOR_FULL , ccNowDuration ) ;
2013-12-31 09:20:21 -08:00
Telemetry : : Accumulate ( Telemetry : : CYCLE_COLLECTOR_MAX_PAUSE , gCCStats . mMaxSliceTime ) ;
2012-01-20 12:02:18 -08:00
2013-12-31 09:20:21 -08:00
if ( ! sLastCCEndTime . IsNull ( ) ) {
2013-11-20 14:35:16 -08:00
uint32_t timeBetween = TimeBetween ( sLastCCEndTime , gCCStats . mBeginTime ) ;
2012-01-20 12:02:18 -08:00
Telemetry : : Accumulate ( Telemetry : : CYCLE_COLLECTOR_TIME_BETWEEN , timeBetween ) ;
}
2014-02-18 06:58:40 -08:00
sLastCCEndTime = endCCTimeStamp ;
2012-01-20 12:02:18 -08:00
2012-02-10 15:30:20 -08:00
Telemetry : : Accumulate ( Telemetry : : FORGET_SKIPPABLE_MAX ,
sMaxForgetSkippableTime / PR_USEC_PER_MSEC ) ;
2012-08-22 11:28:34 -07:00
PRTime delta = GetCollectionTimeDelta ( ) ;
2011-11-09 13:32:17 -08:00
2012-08-22 08:56:38 -07:00
uint32_t cleanups = sForgetSkippableBeforeCC ? sForgetSkippableBeforeCC : 1 ;
2012-09-27 23:57:33 -07:00
uint32_t minForgetSkippableTime = ( sMinForgetSkippableTime = = UINT32_MAX )
2012-07-13 12:13:52 -07:00
? 0 : sMinForgetSkippableTime ;
2011-11-09 13:32:17 -08:00
2012-07-13 12:13:52 -07:00
if ( sPostGCEventsToConsole ) {
2012-06-27 08:10:09 -07:00
nsCString mergeMsg ;
2013-11-20 14:35:16 -08:00
if ( aResults . mMergedZones ) {
2012-06-27 08:10:09 -07:00
mergeMsg . AssignLiteral ( " merged " ) ;
}
2012-05-22 13:10:37 -07:00
nsCString gcMsg ;
2013-11-20 14:35:16 -08:00
if ( aResults . mForcedGC ) {
2012-05-22 13:10:37 -07:00
gcMsg . AssignLiteral ( " , forced a GC " ) ;
2012-02-23 20:16:37 -08:00
}
2012-01-30 12:06:18 -08:00
NS_NAMED_MULTILINE_LITERAL_STRING ( kFmt ,
2013-12-31 09:20:21 -08:00
MOZ_UTF16 ( " CC(T+%.1f) max pause: %lums, total time: %lums, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu|%lu waiting for GC)%s \n " )
2013-11-20 14:35:16 -08:00
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 " ) ) ;
2011-02-16 15:47:12 -08:00
nsString msg ;
2011-11-09 13:32:17 -08:00
msg . Adopt ( nsTextFormatter : : smprintf ( kFmt . get ( ) , double ( delta ) / PR_USEC_PER_SEC ,
2014-01-07 17:33:47 -08:00
gCCStats . mMaxSliceTime , gCCStats . mTotalSliceTime ,
gCCStats . mSuspected ,
2013-11-20 14:35:16 -08:00
aResults . mVisitedRefCounted , aResults . mVisitedGCed , mergeMsg . get ( ) ,
aResults . mFreedRefCounted , aResults . mFreedGCed ,
2013-03-07 10:53:19 -08:00
sCCollectedWaitingForGC , sLikelyShortLivingObjectsNeedingGC ,
gcMsg . get ( ) ,
2012-01-30 12:06:18 -08:00
sForgetSkippableBeforeCC ,
2012-07-13 12:13:52 -07:00
minForgetSkippableTime / PR_USEC_PER_MSEC ,
2012-01-30 12:06:18 -08:00
sMaxForgetSkippableTime / PR_USEC_PER_MSEC ,
( sTotalForgetSkippableTime / cleanups ) /
PR_USEC_PER_MSEC ,
sTotalForgetSkippableTime / PR_USEC_PER_MSEC ,
2013-11-20 14:35:16 -08:00
gCCStats . mMaxSkippableDuration , sRemovedPurples ) ) ;
2011-02-16 15:47:12 -08:00
nsCOMPtr < nsIConsoleService > cs =
do_GetService ( NS_CONSOLESERVICE_CONTRACTID ) ;
if ( cs ) {
cs - > LogStringMessage ( msg . get ( ) ) ;
}
2012-07-13 12:13:52 -07:00
}
2012-03-05 15:33:24 -08:00
2012-10-02 12:27:31 -07:00
if ( sPostGCEventsToObserver ) {
2012-03-05 15:33:24 -08:00
NS_NAMED_MULTILINE_LITERAL_STRING ( kJSONFmt ,
2013-09-17 20:43:21 -07:00
MOZ_UTF16 ( " { \" timestamp \" : %llu, " )
2014-02-17 04:16:23 -08:00
MOZ_UTF16 ( " \" duration \" : %lu, " )
MOZ_UTF16 ( " \" max_slice_pause \" : %lu, " )
MOZ_UTF16 ( " \" total_slice_pause \" : %lu, " )
MOZ_UTF16 ( " \" max_finish_gc_duration \" : %lu, " )
MOZ_UTF16 ( " \" max_sync_skippable_duration \" : %lu, " )
2013-09-17 20:43:21 -07:00
MOZ_UTF16 ( " \" suspected \" : %lu, " )
MOZ_UTF16 ( " \" visited \" : { " )
MOZ_UTF16 ( " \" RCed \" : %lu, " )
MOZ_UTF16 ( " \" GCed \" : %lu }, " )
MOZ_UTF16 ( " \" collected \" : { " )
MOZ_UTF16 ( " \" RCed \" : %lu, " )
MOZ_UTF16 ( " \" GCed \" : %lu }, " )
MOZ_UTF16 ( " \" waiting_for_gc \" : %lu, " )
MOZ_UTF16 ( " \" short_living_objects_waiting_for_gc \" : %lu, " )
MOZ_UTF16 ( " \" forced_gc \" : %d, " )
MOZ_UTF16 ( " \" forget_skippable \" : { " )
MOZ_UTF16 ( " \" times_before_cc \" : %lu, " )
MOZ_UTF16 ( " \" min \" : %lu, " )
MOZ_UTF16 ( " \" max \" : %lu, " )
MOZ_UTF16 ( " \" avg \" : %lu, " )
MOZ_UTF16 ( " \" total \" : %lu, " )
MOZ_UTF16 ( " \" removed \" : %lu } " )
MOZ_UTF16 ( " } " ) ) ;
2012-03-05 15:33:24 -08:00
nsString json ;
2013-12-31 09:20:21 -08:00
json . Adopt ( nsTextFormatter : : smprintf ( kJSONFmt . get ( ) , endCCTime , ccNowDuration ,
2014-01-07 17:33:47 -08:00
gCCStats . mMaxSliceTime ,
gCCStats . mTotalSliceTime ,
gCCStats . mMaxGCDuration ,
2013-11-20 14:35:16 -08:00
gCCStats . mMaxSkippableDuration ,
gCCStats . mSuspected ,
2013-11-20 14:35:16 -08:00
aResults . mVisitedRefCounted , aResults . mVisitedGCed ,
aResults . mFreedRefCounted , aResults . mFreedGCed ,
2012-03-16 16:36:26 -07:00
sCCollectedWaitingForGC ,
2013-03-07 10:53:19 -08:00
sLikelyShortLivingObjectsNeedingGC ,
2013-11-20 14:35:16 -08:00
aResults . mForcedGC ,
2012-03-16 16:36:26 -07:00
sForgetSkippableBeforeCC ,
2012-07-13 12:13:52 -07:00
minForgetSkippableTime / PR_USEC_PER_MSEC ,
2012-03-16 16:36:26 -07:00
sMaxForgetSkippableTime / PR_USEC_PER_MSEC ,
( sTotalForgetSkippableTime / cleanups ) /
PR_USEC_PER_MSEC ,
sTotalForgetSkippableTime / PR_USEC_PER_MSEC ,
sRemovedPurples ) ) ;
2012-03-05 15:33:24 -08:00
nsCOMPtr < nsIObserverService > observerService = mozilla : : services : : GetObserverService ( ) ;
if ( observerService ) {
2012-07-30 07:20:58 -07:00
observerService - > NotifyObservers ( nullptr , " cycle-collection-statistics " , json . get ( ) ) ;
2012-03-05 15:33:24 -08:00
}
2009-07-08 08:08:22 -07:00
}
2012-12-31 12:55:07 -08:00
// Update global state to indicate we have just run a cycle collection.
2012-09-27 23:57:33 -07:00
sMinForgetSkippableTime = UINT32_MAX ;
2012-01-30 12:06:18 -08:00
sMaxForgetSkippableTime = 0 ;
sTotalForgetSkippableTime = 0 ;
sRemovedPurples = 0 ;
sForgetSkippableBeforeCC = 0 ;
2012-02-27 06:49:59 -08:00
sNeedsFullCC = false ;
2013-08-21 14:02:12 -07:00
sNeedsGCAfterCC = false ;
2013-11-20 14:35:16 -08:00
gCCStats . Clear ( ) ;
2009-07-08 08:08:22 -07:00
}
2012-07-31 18:39:39 -07:00
// static
void
InterSliceGCTimerFired ( nsITimer * aTimer , void * aClosure )
{
NS_RELEASE ( sInterSliceGCTimer ) ;
2013-01-27 12:35:12 -08:00
nsJSContext : : GarbageCollectNow ( JS : : gcreason : : INTER_SLICE_GC ,
2012-07-31 18:39:39 -07:00
nsJSContext : : IncrementalGC ,
nsJSContext : : CompartmentGC ,
nsJSContext : : NonShrinkingGC ,
NS_INTERSLICE_GC_BUDGET ) ;
}
2009-02-12 04:06:59 -08:00
// static
void
GCTimerFired ( nsITimer * aTimer , void * aClosure )
2007-03-22 10:30:00 -07:00
{
2012-07-31 18:39:39 -07:00
NS_RELEASE ( sGCTimer ) ;
2007-03-22 10:30:00 -07:00
2012-01-25 10:59:55 -08:00
uintptr_t reason = reinterpret_cast < uintptr_t > ( aClosure ) ;
2013-01-27 12:35:12 -08:00
nsJSContext : : GarbageCollectNow ( static_cast < JS : : gcreason : : Reason > ( reason ) ,
2012-06-30 14:16:32 -07:00
nsJSContext : : IncrementalGC ,
nsJSContext : : CompartmentGC ) ;
2011-02-16 15:47:12 -08:00
}
2007-03-22 10:30:00 -07:00
2011-12-27 03:59:29 -08:00
void
ShrinkGCBuffersTimerFired ( nsITimer * aTimer , void * aClosure )
{
NS_RELEASE ( sShrinkGCBuffersTimer ) ;
nsJSContext : : ShrinkGCBuffersNow ( ) ;
}
2012-03-05 13:48:33 -08:00
static bool
2012-08-22 08:56:38 -07:00
ShouldTriggerCC ( uint32_t aSuspected )
2011-02-16 15:47:12 -08:00
{
2012-03-05 13:48:33 -08:00
return sNeedsFullCC | |
aSuspected > NS_CC_PURPLE_LIMIT | |
2012-07-15 03:30:39 -07:00
( aSuspected > NS_CC_FORCED_PURPLE_LIMIT & &
2013-12-31 09:20:21 -08:00
TimeUntilNow ( sLastCCEndTime ) > NS_CC_FORCED ) ;
2012-03-05 13:48:33 -08:00
}
2013-12-22 06:58:20 -08:00
static uint32_t
TimeToNextCC ( )
{
if ( sIncrementalCC ) {
return NS_CC_DELAY - kMaxICCDuration ;
}
return NS_CC_DELAY ;
}
static_assert ( NS_CC_DELAY > kMaxICCDuration , " ICC shouldn't reduce CC delay to 0 " ) ;
2012-03-05 13:48:33 -08:00
static void
CCTimerFired ( nsITimer * aTimer , void * aClosure )
{
2012-03-08 15:37:13 -08:00
if ( sDidShutdown ) {
2012-02-17 14:35:20 -08:00
return ;
}
2012-03-08 15:37:13 -08:00
2012-08-22 08:56:38 -07:00
static uint32_t ccDelay = NS_CC_DELAY ;
2012-03-08 15:37:13 -08:00
if ( sCCLockedOut ) {
2013-12-22 06:58:20 -08:00
ccDelay = TimeToNextCC ( ) / 3 ;
2012-07-15 14:37:09 -07:00
2012-03-08 15:37:13 -08:00
PRTime now = PR_Now ( ) ;
if ( sCCLockedOutTime = = 0 ) {
2013-01-08 03:11:01 -08:00
// Reset sCCTimerFireCount so that we run forgetSkippable
// often enough before CC. Because of reduced ccDelay
// forgetSkippable will be called just a few times.
// NS_MAX_CC_LOCKEDOUT_TIME limit guarantees that we end up calling
// forgetSkippable and CycleCollectNow eventually.
sCCTimerFireCount = 0 ;
2012-03-08 15:37:13 -08:00
sCCLockedOutTime = now ;
return ;
}
if ( now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME ) {
return ;
}
}
2012-01-30 12:06:18 -08:00
+ + sCCTimerFireCount ;
2012-03-05 13:48:33 -08:00
// During early timer fires, we only run forgetSkippable. During the first
// late timer fire, we decide if we are going to have a second and final
2014-03-04 16:21:48 -08:00
// late timer fire, where we may begin to run the CC. Should run at least one
// early timer fire to allow cleanup before the CC.
int32_t numEarlyTimerFires = std : : max ( ( int32_t ) ccDelay / NS_CC_SKIPPABLE_DELAY - 2 , 1 ) ;
2012-03-05 13:48:33 -08:00
bool isLateTimerFire = sCCTimerFireCount > numEarlyTimerFires ;
2012-08-22 08:56:38 -07:00
uint32_t suspected = nsCycleCollector_suspectedCount ( ) ;
2012-03-05 13:48:33 -08:00
if ( isLateTimerFire & & ShouldTriggerCC ( suspected ) ) {
if ( sCCTimerFireCount = = numEarlyTimerFires + 1 ) {
2012-07-15 03:30:39 -07:00
FireForgetSkippable ( suspected , true ) ;
2012-03-05 13:48:33 -08:00
if ( ShouldTriggerCC ( nsCycleCollector_suspectedCount ( ) ) ) {
// Our efforts to avoid a CC have failed, so we return to let the
// timer fire once more to trigger a CC.
return ;
}
} else {
// We are in the final timer fire and still meet the conditions for
2014-01-01 11:00:35 -08:00
// triggering a CC. Let RunCycleCollectorSlice finish the current IGC, if
// any because that will allow us to include the GC time in the CC pause.
2014-03-04 16:21:48 -08:00
nsJSContext : : RunCycleCollectorSlice ( ) ;
2012-01-30 12:06:18 -08:00
}
2012-03-05 13:48:33 -08:00
} else if ( ( sPreviousSuspectedCount + 100 ) < = suspected ) {
2012-12-31 12:54:37 -08:00
// Only do a forget skippable if there are more than a few new objects.
FireForgetSkippable ( suspected , false ) ;
2012-03-05 13:48:33 -08:00
}
if ( isLateTimerFire ) {
2013-12-22 06:58:20 -08:00
ccDelay = TimeToNextCC ( ) ;
2012-07-15 14:37:09 -07:00
2012-03-05 13:48:33 -08:00
// We have either just run the CC or decided we don't want to run the CC
// next time, so kill the timer.
sPreviousSuspectedCount = 0 ;
nsJSContext : : KillCCTimer ( ) ;
2012-01-30 12:06:18 -08:00
}
}
2007-03-22 10:30:00 -07:00
2012-01-30 12:06:18 -08:00
// static
2012-08-22 08:56:38 -07:00
uint32_t
2012-05-03 09:17:01 -07:00
nsJSContext : : CleanupsSinceLastGC ( )
2012-01-30 12:06:18 -08:00
{
2012-05-03 09:17:01 -07:00
return sCleanupsSinceLastGC ;
2007-03-22 10:30:00 -07:00
}
// static
void
nsJSContext : : LoadStart ( )
{
2011-10-17 07:59:28 -07:00
sLoadingInProgress = true ;
2007-03-22 10:30:00 -07:00
+ + sPendingLoadCount ;
}
// static
void
2007-10-21 09:46:54 -07:00
nsJSContext : : LoadEnd ( )
2007-03-22 10:30:00 -07:00
{
2011-02-16 15:47:12 -08:00
if ( ! sLoadingInProgress )
return ;
2007-03-22 10:30:00 -07:00
// sPendingLoadCount is not a well managed load counter (and doesn't
// need to be), so make sure we don't make it wrap backwards here.
if ( sPendingLoadCount > 0 ) {
- - sPendingLoadCount ;
2011-02-16 15:47:12 -08:00
return ;
2007-03-22 10:30:00 -07:00
}
2011-02-16 15:47:12 -08:00
// Its probably a good idea to GC soon since we have finished loading.
2011-10-17 07:59:28 -07:00
sLoadingInProgress = false ;
2013-01-27 12:35:12 -08:00
PokeGC ( JS : : gcreason : : LOAD_END ) ;
2007-03-22 10:30:00 -07:00
}
2009-02-12 04:06:59 -08:00
// static
2007-03-22 10:30:00 -07:00
void
2013-01-27 12:35:12 -08:00
nsJSContext : : PokeGC ( JS : : gcreason : : Reason aReason , int aDelay )
2007-03-22 10:30:00 -07:00
{
2013-09-12 16:07:02 -07:00
if ( sGCTimer | | sInterSliceGCTimer | | sShuttingDown ) {
2007-03-22 10:30:00 -07:00
// There's already a timer for GC'ing, just return
return ;
}
2013-08-21 14:02:12 -07:00
if ( sCCTimer ) {
// Make sure CC is called...
sNeedsFullCC = true ;
// and GC after it.
sNeedsGCAfterCC = true ;
return ;
}
2014-03-04 16:21:48 -08:00
if ( sICCTimer ) {
// Make sure GC is called after the current CC completes.
// No need to set sNeedsFullCC because we are currently running a CC.
sNeedsGCAfterCC = true ;
return ;
}
2007-03-22 10:30:00 -07:00
CallCreateInstance ( " @mozilla.org/timer;1 " , & sGCTimer ) ;
if ( ! sGCTimer ) {
2011-05-27 16:53:01 -07:00
// Failed to create timer (probably because we're in XPCOM shutdown)
2007-03-22 10:30:00 -07:00
return ;
}
2011-09-28 23:19:26 -07:00
static bool first = true ;
2007-03-22 10:30:00 -07:00
2012-01-25 10:59:55 -08:00
sGCTimer - > InitWithFuncCallback ( GCTimerFired , reinterpret_cast < void * > ( aReason ) ,
2012-02-17 14:35:20 -08:00
aDelay
? aDelay
: ( first
? NS_FIRST_GC_DELAY
: NS_GC_DELAY ) ,
2009-02-12 04:06:59 -08:00
nsITimer : : TYPE_ONE_SHOT ) ;
2007-03-22 10:30:00 -07:00
2011-10-17 07:59:28 -07:00
first = false ;
2007-03-22 10:30:00 -07:00
}
2011-12-27 03:59:29 -08:00
// static
void
nsJSContext : : PokeShrinkGCBuffers ( )
{
2013-01-22 11:17:48 -08:00
if ( sShrinkGCBuffersTimer | | sShuttingDown ) {
2011-12-27 03:59:29 -08:00
return ;
}
CallCreateInstance ( " @mozilla.org/timer;1 " , & sShrinkGCBuffersTimer ) ;
if ( ! sShrinkGCBuffersTimer ) {
// Failed to create timer (probably because we're in XPCOM shutdown)
return ;
}
2012-07-30 07:20:58 -07:00
sShrinkGCBuffersTimer - > InitWithFuncCallback ( ShrinkGCBuffersTimerFired , nullptr ,
2011-12-27 03:59:29 -08:00
NS_SHRINK_GC_BUFFERS_DELAY ,
nsITimer : : TYPE_ONE_SHOT ) ;
}
2011-02-16 15:47:12 -08:00
// static
void
nsJSContext : : MaybePokeCC ( )
{
2013-12-21 06:35:08 -08:00
if ( sCCTimer | | sICCTimer | | sShuttingDown | | ! sHasRunGC ) {
2011-02-16 15:47:12 -08:00
return ;
}
2012-07-15 03:30:39 -07:00
if ( ShouldTriggerCC ( nsCycleCollector_suspectedCount ( ) ) ) {
2012-01-30 12:06:18 -08:00
sCCTimerFireCount = 0 ;
CallCreateInstance ( " @mozilla.org/timer;1 " , & sCCTimer ) ;
if ( ! sCCTimer ) {
return ;
}
2013-07-09 10:30:58 -07:00
// We can kill some objects before running forgetSkippable.
nsCycleCollector_dispatchDeferredDeletion ( ) ;
2012-07-30 07:20:58 -07:00
sCCTimer - > InitWithFuncCallback ( CCTimerFired , nullptr ,
2012-01-30 12:06:18 -08:00
NS_CC_SKIPPABLE_DELAY ,
nsITimer : : TYPE_REPEATING_SLACK ) ;
2011-02-16 15:47:12 -08:00
}
}
//static
void
nsJSContext : : KillGCTimer ( )
{
if ( sGCTimer ) {
sGCTimer - > Cancel ( ) ;
NS_RELEASE ( sGCTimer ) ;
}
}
2012-05-09 11:53:23 -07:00
void
nsJSContext : : KillFullGCTimer ( )
{
if ( sFullGCTimer ) {
sFullGCTimer - > Cancel ( ) ;
NS_RELEASE ( sFullGCTimer ) ;
}
}
2012-06-10 21:27:59 -07:00
void
nsJSContext : : KillInterSliceGCTimer ( )
{
if ( sInterSliceGCTimer ) {
sInterSliceGCTimer - > Cancel ( ) ;
NS_RELEASE ( sInterSliceGCTimer ) ;
}
}
2011-12-27 03:59:29 -08:00
//static
void
nsJSContext : : KillShrinkGCBuffersTimer ( )
{
if ( sShrinkGCBuffersTimer ) {
sShrinkGCBuffersTimer - > Cancel ( ) ;
NS_RELEASE ( sShrinkGCBuffersTimer ) ;
}
}
2011-02-16 15:47:12 -08:00
//static
void
nsJSContext : : KillCCTimer ( )
{
2012-03-08 15:37:13 -08:00
sCCLockedOutTime = 0 ;
2011-02-16 15:47:12 -08:00
if ( sCCTimer ) {
sCCTimer - > Cancel ( ) ;
NS_RELEASE ( sCCTimer ) ;
}
}
2013-12-21 06:35:08 -08:00
//static
void
nsJSContext : : KillICCTimer ( )
{
sCCLockedOutTime = 0 ;
if ( sICCTimer ) {
sICCTimer - > Cancel ( ) ;
NS_RELEASE ( sICCTimer ) ;
}
}
2011-02-16 15:47:12 -08:00
void
2013-01-27 12:35:12 -08:00
nsJSContext : : GC ( JS : : gcreason : : Reason aReason )
2011-02-16 15:47:12 -08:00
{
2012-01-25 10:59:55 -08:00
PokeGC ( aReason ) ;
2011-02-16 15:47:12 -08:00
}
2012-03-05 15:33:24 -08:00
class NotifyGCEndRunnable : public nsRunnable
{
nsString mMessage ;
public :
NotifyGCEndRunnable ( const nsString & aMessage ) : mMessage ( aMessage ) { }
NS_DECL_NSIRUNNABLE
} ;
NS_IMETHODIMP
NotifyGCEndRunnable : : Run ( )
{
MOZ_ASSERT ( NS_IsMainThread ( ) ) ;
nsCOMPtr < nsIObserverService > observerService = mozilla : : services : : GetObserverService ( ) ;
if ( ! observerService ) {
return NS_OK ;
}
const jschar oomMsg [ 3 ] = { ' { ' , ' } ' , 0 } ;
const jschar * toSend = mMessage . get ( ) ? mMessage . get ( ) : oomMsg ;
2012-07-30 07:20:58 -07:00
observerService - > NotifyObservers ( nullptr , " garbage-collection-statistics " , toSend ) ;
2012-03-05 15:33:24 -08:00
return NS_OK ;
}
2012-02-03 06:01:35 -08:00
static void
2013-01-27 12:35:12 -08:00
DOMGCSliceCallback ( JSRuntime * aRt , JS : : GCProgress aProgress , const JS : : GCDescription & aDesc )
2011-11-09 13:32:17 -08:00
{
NS_ASSERTION ( NS_IsMainThread ( ) , " GCs must run on the main thread " ) ;
2011-02-16 15:47:12 -08:00
2013-01-27 12:35:12 -08:00
if ( aProgress = = JS : : GC_CYCLE_END ) {
2012-08-22 11:28:34 -07:00
PRTime delta = GetCollectionTimeDelta ( ) ;
2011-02-19 22:59:49 -08:00
2012-07-13 12:13:52 -07:00
if ( sPostGCEventsToConsole ) {
NS_NAMED_LITERAL_STRING ( kFmt , " GC(T+%.1f) " ) ;
nsString prefix , gcstats ;
gcstats . Adopt ( aDesc . formatMessage ( aRt ) ) ;
prefix . Adopt ( nsTextFormatter : : smprintf ( kFmt . get ( ) ,
double ( delta ) / PR_USEC_PER_SEC ) ) ;
nsString msg = prefix + gcstats ;
nsCOMPtr < nsIConsoleService > cs = do_GetService ( NS_CONSOLESERVICE_CONTRACTID ) ;
if ( cs ) {
cs - > LogStringMessage ( msg . get ( ) ) ;
}
2011-02-19 22:59:49 -08:00
}
2012-03-16 16:36:26 -07:00
2012-10-02 12:27:31 -07:00
if ( sPostGCEventsToObserver ) {
2012-07-13 12:13:52 -07:00
nsString json ;
2012-08-22 11:28:34 -07:00
json . Adopt ( aDesc . formatJSON ( aRt , PR_Now ( ) ) ) ;
2012-07-13 12:13:52 -07:00
nsRefPtr < NotifyGCEndRunnable > notify = new NotifyGCEndRunnable ( json ) ;
NS_DispatchToMainThread ( notify ) ;
}
2011-02-16 15:47:12 -08:00
}
2012-03-08 15:37:13 -08:00
// Prevent cycle collections and shrinking during incremental GC.
2013-01-27 12:35:12 -08:00
if ( aProgress = = JS : : GC_CYCLE_BEGIN ) {
2012-02-17 14:35:20 -08:00
sCCLockedOut = true ;
2012-03-08 15:37:13 -08:00
nsJSContext : : KillShrinkGCBuffersTimer ( ) ;
2013-01-27 12:35:12 -08:00
} else if ( aProgress = = JS : : GC_CYCLE_END ) {
2012-02-17 14:35:20 -08:00
sCCLockedOut = false ;
}
2012-01-30 12:06:18 -08:00
2012-02-17 14:35:20 -08:00
// The GC has more work to do, so schedule another GC slice.
2013-01-27 12:35:12 -08:00
if ( aProgress = = JS : : GC_SLICE_END ) {
2012-06-10 21:27:59 -07:00
nsJSContext : : KillInterSliceGCTimer ( ) ;
2013-01-22 11:17:48 -08:00
if ( ! sShuttingDown ) {
CallCreateInstance ( " @mozilla.org/timer;1 " , & sInterSliceGCTimer ) ;
sInterSliceGCTimer - > InitWithFuncCallback ( InterSliceGCTimerFired ,
2013-10-28 07:04:12 -07:00
nullptr ,
2013-01-22 11:17:48 -08:00
NS_INTERSLICE_GC_DELAY ,
nsITimer : : TYPE_ONE_SHOT ) ;
}
2012-02-17 14:35:20 -08:00
}
2013-01-27 12:35:12 -08:00
if ( aProgress = = JS : : GC_CYCLE_END ) {
2012-03-08 15:37:13 -08:00
// May need to kill the inter-slice GC timer
2012-06-10 21:27:59 -07:00
nsJSContext : : KillInterSliceGCTimer ( ) ;
2012-03-08 15:37:13 -08:00
2012-02-17 14:35:20 -08:00
sCCollectedWaitingForGC = 0 ;
2013-03-07 10:53:19 -08:00
sLikelyShortLivingObjectsNeedingGC = 0 ;
2012-05-03 09:17:01 -07:00
sCleanupsSinceLastGC = 0 ;
2012-03-08 15:37:13 -08:00
sNeedsFullCC = true ;
2013-01-30 14:46:37 -08:00
sHasRunGC = true ;
2012-03-08 15:37:13 -08:00
nsJSContext : : MaybePokeCC ( ) ;
2013-02-17 22:56:32 -08:00
if ( aDesc . isCompartment_ ) {
2013-01-22 11:17:48 -08:00
if ( ! sFullGCTimer & & ! sShuttingDown ) {
2012-05-09 11:53:23 -07:00
CallCreateInstance ( " @mozilla.org/timer;1 " , & sFullGCTimer ) ;
2013-01-27 12:35:12 -08:00
JS : : gcreason : : Reason reason = JS : : gcreason : : FULL_GC_TIMER ;
2012-05-09 11:53:23 -07:00
sFullGCTimer - > InitWithFuncCallback ( FullGCTimerFired ,
reinterpret_cast < void * > ( reason ) ,
NS_FULL_GC_DELAY ,
nsITimer : : TYPE_ONE_SHOT ) ;
}
} else {
nsJSContext : : KillFullGCTimer ( ) ;
2012-03-08 15:37:13 -08:00
// Avoid shrinking during heavy activity, which is suggested by
// compartment GC.
2012-02-17 14:35:20 -08:00
nsJSContext : : PokeShrinkGCBuffers ( ) ;
2011-11-09 13:32:17 -08:00
}
}
2007-03-22 10:30:00 -07:00
2013-07-27 03:48:45 -07:00
if ( ( aProgress = = JS : : GC_SLICE_END | | aProgress = = JS : : GC_CYCLE_END ) & &
ShouldTriggerCC ( nsCycleCollector_suspectedCount ( ) ) ) {
nsCycleCollector_dispatchDeferredDeletion ( ) ;
}
2012-02-17 14:35:20 -08:00
if ( sPrevGCSliceCallback )
( * sPrevGCSliceCallback ) ( aRt , aProgress , aDesc ) ;
2007-03-22 10:30:00 -07:00
}
2008-03-19 17:42:47 -07:00
void
2009-05-19 19:11:01 -07:00
nsJSContext : : ReportPendingException ( )
2008-03-19 17:42:47 -07:00
{
2012-11-09 07:43:57 -08:00
if ( mIsInitialized ) {
nsJSUtils : : ReportPendingException ( mContext ) ;
2008-12-12 17:46:43 -08:00
}
2008-03-19 17:42:47 -07:00
}
2013-09-04 14:06:55 -07:00
void
nsJSContext : : SetWindowProxy ( JS : : Handle < JSObject * > aWindowProxy )
{
2013-09-04 14:06:56 -07:00
mWindowProxy = aWindowProxy ;
2013-09-04 14:06:55 -07:00
}
JSObject *
nsJSContext : : GetWindowProxy ( )
{
2013-09-08 20:28:48 -07:00
JSObject * windowProxy = GetWindowProxyPreserveColor ( ) ;
if ( windowProxy ) {
JS : : ExposeObjectToActiveJS ( windowProxy ) ;
}
return windowProxy ;
2013-09-04 14:06:55 -07:00
}
JSObject *
nsJSContext : : GetWindowProxyPreserveColor ( )
{
2013-09-04 14:06:56 -07:00
return mWindowProxy ;
2013-09-04 14:06:55 -07:00
}
2013-03-07 10:53:19 -08:00
void
nsJSContext : : LikelyShortLivingObjectCreated ( )
{
+ + sLikelyShortLivingObjectsNeedingGC ;
}
2007-03-22 10:30:00 -07:00
void
2013-08-19 16:24:29 -07:00
mozilla : : dom : : StartupJSEnvironment ( )
2007-03-22 10:30:00 -07:00
{
// initialize all our statics, so that we can restart XPCOM
2013-12-21 06:35:08 -08:00
sGCTimer = sFullGCTimer = sCCTimer = sICCTimer = nullptr ;
2012-02-17 14:35:20 -08:00
sCCLockedOut = false ;
2012-03-08 15:37:13 -08:00
sCCLockedOutTime = 0 ;
2013-12-31 09:20:21 -08:00
sLastCCEndTime = TimeStamp ( ) ;
2013-01-30 14:46:37 -08:00
sHasRunGC = false ;
2007-03-22 10:30:00 -07:00
sPendingLoadCount = 0 ;
2011-10-17 07:59:28 -07:00
sLoadingInProgress = false ;
2011-02-28 14:44:22 -08:00
sCCollectedWaitingForGC = 0 ;
2013-03-07 10:53:19 -08:00
sLikelyShortLivingObjectsNeedingGC = 0 ;
2011-10-17 07:59:28 -07:00
sPostGCEventsToConsole = false ;
2012-02-27 06:49:59 -08:00
sNeedsFullCC = false ;
2013-08-21 14:02:12 -07:00
sNeedsGCAfterCC = false ;
2012-07-30 07:20:58 -07:00
gNameSpaceManager = nullptr ;
sRuntimeService = nullptr ;
sRuntime = nullptr ;
2011-10-17 07:59:28 -07:00
sIsInitialized = false ;
sDidShutdown = false ;
2013-01-22 11:17:48 -08:00
sShuttingDown = false ;
2007-03-22 10:30:00 -07:00
sContextCount = 0 ;
2012-07-30 07:20:58 -07:00
sSecurityManager = nullptr ;
2013-11-20 14:35:16 -08:00
gCCStats . Clear ( ) ;
2007-03-22 10:30:00 -07:00
}
2013-12-10 15:10:01 -08:00
static void
2008-04-10 10:35:56 -07:00
ReportAllJSExceptionsPrefChangedCallback ( const char * aPrefName , void * aClosure )
{
2011-09-28 23:19:26 -07:00
bool reportAll = Preferences : : GetBool ( aPrefName , false ) ;
2008-04-10 10:35:56 -07:00
nsContentUtils : : XPConnect ( ) - > SetReportAllJSExceptions ( reportAll ) ;
}
2013-12-10 15:10:01 -08:00
static void
2009-07-09 05:16:26 -07:00
SetMemoryHighWaterMarkPrefChangedCallback ( const char * aPrefName , void * aClosure )
{
2012-08-22 08:56:38 -07:00
int32_t highwatermark = Preferences : : GetInt ( aPrefName , 128 ) ;
2010-12-02 14:38:00 -08:00
2013-08-19 16:24:29 -07:00
JS_SetGCParameter ( sRuntime , JSGC_MAX_MALLOC_BYTES ,
2010-12-02 14:38:00 -08:00
highwatermark * 1024L * 1024L ) ;
}
2013-12-10 15:10:01 -08:00
static void
2010-12-02 14:38:00 -08:00
SetMemoryMaxPrefChangedCallback ( const char * aPrefName , void * aClosure )
{
2012-08-22 08:56:38 -07:00
int32_t pref = Preferences : : GetInt ( aPrefName , - 1 ) ;
2011-01-12 09:35:36 -08:00
// handle overflow and negative pref values
2012-08-22 08:56:38 -07:00
uint32_t max = ( pref < = 0 | | pref > = 0x1000 ) ? - 1 : ( uint32_t ) pref * 1024 * 1024 ;
2013-08-19 16:24:29 -07:00
JS_SetGCParameter ( sRuntime , JSGC_MAX_BYTES , max ) ;
2009-07-09 05:16:26 -07:00
}
2013-12-10 15:10:01 -08:00
static void
2011-01-09 22:57:21 -08:00
SetMemoryGCModePrefChangedCallback ( const char * aPrefName , void * aClosure )
{
2012-04-04 02:15:10 -07:00
bool enableCompartmentGC = Preferences : : GetBool ( " javascript.options.mem.gc_per_compartment " ) ;
bool enableIncrementalGC = Preferences : : GetBool ( " javascript.options.mem.gc_incremental " ) ;
2012-02-17 14:35:20 -08:00
JSGCMode mode ;
if ( enableIncrementalGC ) {
mode = JSGC_MODE_INCREMENTAL ;
} else if ( enableCompartmentGC ) {
mode = JSGC_MODE_COMPARTMENT ;
} else {
mode = JSGC_MODE_GLOBAL ;
}
2013-08-19 16:24:29 -07:00
JS_SetGCParameter ( sRuntime , JSGC_MODE , mode ) ;
2012-02-17 14:35:20 -08:00
}
2013-12-10 15:10:01 -08:00
static void
2012-02-17 14:35:20 -08:00
SetMemoryGCSliceTimePrefChangedCallback ( const char * aPrefName , void * aClosure )
{
2012-08-22 08:56:38 -07:00
int32_t pref = Preferences : : GetInt ( aPrefName , - 1 ) ;
2012-02-17 14:35:20 -08:00
// handle overflow and negative pref values
if ( pref > 0 & & pref < 100000 )
2013-08-19 16:24:29 -07:00
JS_SetGCParameter ( sRuntime , JSGC_SLICE_TIME_BUDGET , pref ) ;
2011-01-09 22:57:21 -08:00
}
2013-12-10 15:10:01 -08:00
static void
2012-07-11 11:09:53 -07:00
SetMemoryGCPrefChangedCallback ( const char * aPrefName , void * aClosure )
{
2012-08-22 08:56:38 -07:00
int32_t pref = Preferences : : GetInt ( aPrefName , - 1 ) ;
2012-07-11 11:09:53 -07:00
// handle overflow and negative pref values
2013-06-26 23:40:17 -07:00
if ( pref > = 0 & & pref < 10000 )
2013-08-19 16:24:29 -07:00
JS_SetGCParameter ( sRuntime , ( JSGCParamKey ) ( intptr_t ) aClosure , pref ) ;
2012-07-11 11:09:53 -07:00
}
2013-12-10 15:10:01 -08:00
static void
2012-07-11 11:09:53 -07:00
SetMemoryGCDynamicHeapGrowthPrefChangedCallback ( const char * aPrefName , void * aClosure )
{
bool pref = Preferences : : GetBool ( aPrefName ) ;
2013-08-19 16:24:29 -07:00
JS_SetGCParameter ( sRuntime , JSGC_DYNAMIC_HEAP_GROWTH , pref ) ;
2012-07-11 11:09:53 -07:00
}
2013-12-10 15:10:01 -08:00
static void
2012-07-11 11:09:53 -07:00
SetMemoryGCDynamicMarkSlicePrefChangedCallback ( const char * aPrefName , void * aClosure )
{
bool pref = Preferences : : GetBool ( aPrefName ) ;
2013-08-19 16:24:29 -07:00
JS_SetGCParameter ( sRuntime , JSGC_DYNAMIC_MARK_SLICE , pref ) ;
2012-07-11 11:09:53 -07:00
}
2013-12-22 07:14:36 -08:00
static void
SetIncrementalCCPrefChangedCallback ( const char * aPrefName , void * aClosure )
{
bool pref = Preferences : : GetBool ( aPrefName ) ;
sIncrementalCC = pref ;
}
2011-07-17 12:09:13 -07:00
JSObject *
NS_DOMReadStructuredClone ( JSContext * cx ,
JSStructuredCloneReader * reader ,
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
uint32_t tag ,
uint32_t data ,
2011-07-17 12:09:13 -07:00
void * closure )
2010-10-10 15:39:11 -07:00
{
2012-04-24 03:58:07 -07:00
if ( tag = = SCTAG_DOM_IMAGEDATA ) {
// Read the information out of the stream.
uint32_t width , height ;
2013-05-02 02:12:46 -07:00
JS : : Rooted < JS : : Value > dataArray ( cx ) ;
2012-04-24 03:58:07 -07:00
if ( ! JS_ReadUint32Pair ( reader , & width , & height ) | |
2014-03-20 02:32:37 -07:00
! JS_ReadTypedArray ( reader , & dataArray ) ) {
2012-07-30 07:20:58 -07:00
return nullptr ;
2012-04-24 03:58:07 -07:00
}
MOZ_ASSERT ( dataArray . isObject ( ) ) ;
// Construct the ImageData.
2012-10-22 10:08:52 -07:00
nsRefPtr < ImageData > imageData = new ImageData ( width , height ,
dataArray . toObject ( ) ) ;
2013-04-11 15:52:10 -07:00
// Wrap it in a JS::Value.
2013-07-29 16:45:27 -07:00
JS : : Rooted < JSObject * > global ( cx , JS : : CurrentGlobalOrNull ( cx ) ) ;
2012-04-24 03:58:07 -07:00
if ( ! global ) {
2012-07-30 07:20:58 -07:00
return nullptr ;
2012-04-24 03:58:07 -07:00
}
2012-10-22 10:08:52 -07:00
return imageData - > WrapObject ( cx , global ) ;
2012-04-24 03:58:07 -07:00
}
// Don't know what this is. Bail.
2012-06-19 16:01:10 -07:00
xpc : : Throw ( cx , NS_ERROR_DOM_DATA_CLONE_ERR ) ;
2012-07-30 07:20:58 -07:00
return nullptr ;
2010-10-10 15:39:11 -07:00
}
2013-08-08 15:53:04 -07:00
bool
2011-07-17 12:09:13 -07:00
NS_DOMWriteStructuredClone ( JSContext * cx ,
JSStructuredCloneWriter * writer ,
2013-05-09 00:27:40 -07:00
JS : : Handle < JSObject * > obj ,
2011-07-17 12:09:13 -07:00
void * closure )
2010-10-10 15:39:11 -07:00
{
2012-10-22 10:08:52 -07:00
ImageData * imageData ;
2013-11-21 04:51:16 -08:00
nsresult rv = UNWRAP_OBJECT ( ImageData , obj , imageData ) ;
2012-10-22 10:08:52 -07:00
if ( NS_FAILED ( rv ) ) {
// Don't know what this is. Bail.
xpc : : Throw ( cx , NS_ERROR_DOM_DATA_CLONE_ERR ) ;
2013-08-06 23:59:54 -07:00
return false ;
2012-04-24 03:58:07 -07:00
}
2012-10-22 10:08:52 -07:00
// Prepare the ImageData internals.
uint32_t width = imageData - > Width ( ) ;
uint32_t height = imageData - > Height ( ) ;
2013-05-11 22:17:42 -07:00
JS : : Rooted < JSObject * > dataArray ( cx , imageData - > GetDataObject ( ) ) ;
2012-10-22 10:08:52 -07:00
// Write the internals to the stream.
2013-02-22 13:43:28 -08:00
JSAutoCompartment ac ( cx , dataArray ) ;
2014-04-02 07:28:03 -07:00
JS : : Rooted < JS : : Value > arrayValue ( cx , JS : : ObjectValue ( * dataArray ) ) ;
2012-10-22 10:08:52 -07:00
return JS_WriteUint32Pair ( writer , SCTAG_DOM_IMAGEDATA , 0 ) & &
JS_WriteUint32Pair ( writer , width , height ) & &
2014-04-02 07:28:03 -07:00
JS_WriteTypedArray ( writer , arrayValue ) ;
2010-10-10 15:39:11 -07:00
}
2011-07-17 12:09:13 -07:00
void
NS_DOMStructuredCloneError ( JSContext * cx ,
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
uint32_t errorid )
2010-10-10 15:39:11 -07:00
{
// We don't currently support any extensions to structured cloning.
2012-06-19 16:01:10 -07:00
xpc : : Throw ( cx , NS_ERROR_DOM_DATA_CLONE_ERR ) ;
2010-10-10 15:39:11 -07:00
}
2013-12-03 11:31:30 -08:00
static bool
AsmJSCacheOpenEntryForRead ( JS : : Handle < JSObject * > aGlobal ,
const jschar * aBegin ,
const jschar * aLimit ,
size_t * aSize ,
const uint8_t * * aMemory ,
intptr_t * aHandle )
{
nsIPrincipal * principal = nsContentUtils : : GetObjectPrincipal ( aGlobal ) ;
return asmjscache : : OpenEntryForRead ( principal , aBegin , aLimit , aSize , aMemory ,
aHandle ) ;
}
static bool
AsmJSCacheOpenEntryForWrite ( JS : : Handle < JSObject * > aGlobal ,
2014-03-05 12:47:10 -08:00
bool aInstalled ,
2013-12-03 11:31:30 -08:00
const jschar * aBegin ,
const jschar * aEnd ,
size_t aSize ,
uint8_t * * aMemory ,
intptr_t * aHandle )
{
nsIPrincipal * principal = nsContentUtils : : GetObjectPrincipal ( aGlobal ) ;
2014-03-05 12:47:10 -08:00
return asmjscache : : OpenEntryForWrite ( principal , aInstalled , aBegin , aEnd ,
aSize , aMemory , aHandle ) ;
2013-12-03 11:31:30 -08:00
}
2014-02-12 20:50:15 -08:00
static void
OnLargeAllocationFailure ( )
{
nsCOMPtr < nsIObserverService > os =
mozilla : : services : : GetObserverService ( ) ;
if ( os ) {
os - > NotifyObservers ( nullptr , " memory-pressure " , MOZ_UTF16 ( " heap-minimize " ) ) ;
}
}
2013-08-19 16:24:28 -07:00
static NS_DEFINE_CID ( kDOMScriptObjectFactoryCID , NS_DOM_SCRIPT_OBJECT_FACTORY_CID ) ;
2013-08-19 16:24:29 -07:00
void
nsJSContext : : EnsureStatics ( )
2007-03-22 10:30:00 -07:00
{
if ( sIsInitialized ) {
2013-08-19 16:24:29 -07:00
if ( ! nsContentUtils : : XPConnect ( ) ) {
MOZ_CRASH ( ) ;
}
return ;
2007-03-22 10:30:00 -07:00
}
2008-09-05 16:26:04 -07:00
nsresult rv = CallGetService ( NS_SCRIPTSECURITYMANAGER_CONTRACTID ,
& sSecurityManager ) ;
2013-08-19 16:24:29 -07:00
if ( NS_FAILED ( rv ) ) {
MOZ_CRASH ( ) ;
}
2008-09-05 16:26:04 -07:00
rv = CallGetService ( kJSRuntimeServiceContractID , & sRuntimeService ) ;
2013-08-19 16:24:29 -07:00
if ( NS_FAILED ( rv ) ) {
MOZ_CRASH ( ) ;
}
2007-03-22 10:30:00 -07:00
rv = sRuntimeService - > GetRuntime ( & sRuntime ) ;
2013-08-19 16:24:29 -07:00
if ( NS_FAILED ( rv ) ) {
MOZ_CRASH ( ) ;
}
2007-03-22 10:30:00 -07:00
// Let's make sure that our main thread is the same as the xpcom main thread.
2013-08-19 16:24:29 -07:00
MOZ_ASSERT ( NS_IsMainThread ( ) ) ;
2007-03-22 10:30:00 -07:00
2013-01-27 12:35:12 -08:00
sPrevGCSliceCallback = JS : : SetGCSliceCallback ( sRuntime , DOMGCSliceCallback ) ;
2007-03-22 10:30:00 -07:00
2010-10-10 15:39:11 -07:00
// Set up the structured clone callbacks.
static JSStructuredCloneCallbacks cloneCallbacks = {
2011-07-17 12:09:13 -07:00
NS_DOMReadStructuredClone ,
NS_DOMWriteStructuredClone ,
NS_DOMStructuredCloneError
2010-10-10 15:39:11 -07:00
} ;
JS_SetStructuredCloneCallbacks ( sRuntime , & cloneCallbacks ) ;
2012-08-07 22:26:18 -07:00
static js : : DOMCallbacks DOMcallbacks = {
InstanceClassHasProtoAtDepth
} ;
SetDOMCallbacks ( sRuntime , & DOMcallbacks ) ;
2013-11-18 13:49:53 -08:00
// Set up the asm.js cache callbacks
static JS : : AsmJSCacheOps asmJSCacheOps = {
2013-12-03 11:31:30 -08:00
AsmJSCacheOpenEntryForRead ,
2013-11-18 13:49:53 -08:00
asmjscache : : CloseEntryForRead ,
2013-12-03 11:31:30 -08:00
AsmJSCacheOpenEntryForWrite ,
2013-11-18 13:49:53 -08:00
asmjscache : : CloseEntryForWrite ,
asmjscache : : GetBuildId
} ;
JS : : SetAsmJSCacheOps ( sRuntime , & asmJSCacheOps ) ;
2014-02-12 20:50:15 -08:00
JS : : SetLargeAllocationFailureCallback ( sRuntime , OnLargeAllocationFailure ) ;
2007-03-22 10:30:00 -07:00
// Set these global xpconnect options...
2013-02-20 11:49:51 -08:00
Preferences : : RegisterCallbackAndCall ( ReportAllJSExceptionsPrefChangedCallback ,
" dom.report_all_js_exceptions " ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryHighWaterMarkPrefChangedCallback ,
" javascript.options.mem.high_water_mark " ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryMaxPrefChangedCallback ,
" javascript.options.mem.max " ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryGCModePrefChangedCallback ,
" javascript.options.mem.gc_per_compartment " ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryGCModePrefChangedCallback ,
" javascript.options.mem.gc_incremental " ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryGCSliceTimePrefChangedCallback ,
" javascript.options.mem.gc_incremental_slice_ms " ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryGCPrefChangedCallback ,
" javascript.options.mem.gc_high_frequency_time_limit_ms " ,
( void * ) JSGC_HIGH_FREQUENCY_TIME_LIMIT ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryGCDynamicMarkSlicePrefChangedCallback ,
" javascript.options.mem.gc_dynamic_mark_slice " ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryGCDynamicHeapGrowthPrefChangedCallback ,
" javascript.options.mem.gc_dynamic_heap_growth " ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryGCPrefChangedCallback ,
" javascript.options.mem.gc_low_frequency_heap_growth " ,
( void * ) JSGC_LOW_FREQUENCY_HEAP_GROWTH ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryGCPrefChangedCallback ,
" javascript.options.mem.gc_high_frequency_heap_growth_min " ,
( void * ) JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryGCPrefChangedCallback ,
" javascript.options.mem.gc_high_frequency_heap_growth_max " ,
( void * ) JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryGCPrefChangedCallback ,
" javascript.options.mem.gc_high_frequency_low_limit_mb " ,
( void * ) JSGC_HIGH_FREQUENCY_LOW_LIMIT ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryGCPrefChangedCallback ,
" javascript.options.mem.gc_high_frequency_high_limit_mb " ,
( void * ) JSGC_HIGH_FREQUENCY_HIGH_LIMIT ) ;
Preferences : : RegisterCallbackAndCall ( SetMemoryGCPrefChangedCallback ,
" javascript.options.mem.gc_allocation_threshold_mb " ,
( void * ) JSGC_ALLOCATION_THRESHOLD ) ;
2013-06-20 18:06:53 -07:00
Preferences : : RegisterCallbackAndCall ( SetMemoryGCPrefChangedCallback ,
" javascript.options.mem.gc_decommit_threshold_mb " ,
( void * ) JSGC_DECOMMIT_THRESHOLD ) ;
2013-12-22 07:14:36 -08:00
Preferences : : RegisterCallbackAndCall ( SetIncrementalCCPrefChangedCallback ,
" dom.cycle_collector.incremental " ) ;
Bug 560095 - Use mozilla::services::GetObserverService(). r=biesi,dveditz,gavin,josh,jst,mrbkap,roc,sdwilsh,shaver,sicking,smontagu,surkov
2010-04-29 09:59:13 -07:00
nsCOMPtr < nsIObserverService > obs = mozilla : : services : : GetObserverService ( ) ;
2013-08-19 16:24:29 -07:00
if ( ! obs ) {
MOZ_CRASH ( ) ;
}
2007-10-22 14:42:25 -07:00
2011-07-07 11:27:07 -07:00
Preferences : : AddBoolVarCache ( & sGCOnMemoryPressure ,
" javascript.options.gc_on_memory_pressure " ,
2011-10-17 07:59:28 -07:00
true ) ;
2011-07-07 11:27:07 -07:00
2013-01-22 11:17:48 -08:00
nsIObserver * observer = new nsJSEnvironmentObserver ( ) ;
obs - > AddObserver ( observer , " memory-pressure " , false ) ;
obs - > AddObserver ( observer , " quit-application " , false ) ;
2007-11-06 13:47:35 -08:00
2013-08-21 23:56:02 -07:00
// Bug 907848 - We need to explicitly get the nsIDOMScriptObjectFactory
// service in order to force its constructor to run, which registers a
// shutdown observer. It would be nice to make this more explicit and less
// side-effect-y.
2013-08-19 16:24:28 -07:00
nsCOMPtr < nsIDOMScriptObjectFactory > factory = do_GetService ( kDOMScriptObjectFactoryCID ) ;
if ( ! factory ) {
MOZ_CRASH ( ) ;
}
2011-10-17 07:59:28 -07:00
sIsInitialized = true ;
2007-03-22 10:30:00 -07:00
}
2007-11-13 02:35:49 -08:00
nsScriptNameSpaceManager *
2013-08-19 16:24:29 -07:00
mozilla : : dom : : GetNameSpaceManager ( )
2007-11-13 02:35:49 -08:00
{
if ( sDidShutdown )
2012-07-30 07:20:58 -07:00
return nullptr ;
2007-11-13 02:35:49 -08:00
if ( ! gNameSpaceManager ) {
gNameSpaceManager = new nsScriptNameSpaceManager ;
2010-11-16 14:09:50 -08:00
NS_ADDREF ( gNameSpaceManager ) ;
2007-11-13 02:35:49 -08:00
nsresult rv = gNameSpaceManager - > Init ( ) ;
2012-07-30 07:20:58 -07:00
NS_ENSURE_SUCCESS ( rv , nullptr ) ;
2007-11-13 02:35:49 -08:00
}
return gNameSpaceManager ;
}
2008-09-11 06:20:56 -07:00
void
2013-08-19 16:24:29 -07:00
mozilla : : dom : : ShutdownJSEnvironment ( )
2007-03-22 10:30:00 -07:00
{
2013-01-22 11:17:48 -08:00
KillTimers ( ) ;
2007-03-22 10:30:00 -07:00
2010-11-16 14:09:50 -08:00
NS_IF_RELEASE ( gNameSpaceManager ) ;
2007-03-22 10:30:00 -07:00
if ( ! sContextCount ) {
// We're being shutdown, and there are no more contexts
// alive, release the JS runtime service and the security manager.
NS_IF_RELEASE ( sRuntimeService ) ;
NS_IF_RELEASE ( sSecurityManager ) ;
}
2013-01-22 11:17:48 -08:00
sShuttingDown = true ;
2011-10-17 07:59:28 -07:00
sDidShutdown = true ;
2007-03-22 10:30:00 -07:00
}
// A fast-array class for JS. This class supports both nsIJSScriptArray and
// nsIArray. If it is JS itself providing and consuming this class, all work
// can be done via nsIJSScriptArray, and avoid the conversion of elements
// to/from nsISupports.
// When consumed by non-JS (eg, another script language), conversion is done
// on-the-fly.
2012-06-14 19:31:55 -07:00
class nsJSArgArray MOZ_FINAL : public nsIJSArgArray {
2007-03-22 10:30:00 -07:00
public :
2013-04-11 15:52:10 -07:00
nsJSArgArray ( JSContext * aContext , uint32_t argc , JS : : Value * argv ,
nsresult * prv ) ;
2007-03-22 10:30:00 -07:00
~ nsJSArgArray ( ) ;
// nsISupports
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
2007-10-29 06:45:07 -07:00
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS ( nsJSArgArray ,
nsIJSArgArray )
2007-03-22 10:30:00 -07:00
// nsIArray
NS_DECL_NSIARRAY
// nsIJSArgArray
2012-08-22 08:56:38 -07:00
nsresult GetArgs ( uint32_t * argc , void * * argv ) ;
2007-03-22 10:30:00 -07:00
void ReleaseJSObjects ( ) ;
protected :
JSContext * mContext ;
2013-06-18 03:00:37 -07:00
JS : : Heap < JS : : Value > * mArgv ;
2012-12-05 01:19:33 -08:00
uint32_t mArgc ;
2007-03-22 10:30:00 -07:00
} ;
2013-04-11 15:52:10 -07:00
nsJSArgArray : : nsJSArgArray ( JSContext * aContext , uint32_t argc , JS : : Value * argv ,
2007-03-22 10:30:00 -07:00
nsresult * prv ) :
2012-12-05 01:19:33 -08:00
mContext ( aContext ) ,
mArgv ( nullptr ) ,
mArgc ( argc )
2007-03-22 10:30:00 -07:00
{
// copy the array - we don't know its lifetime, and ours is tied to xpcom
2013-06-18 03:00:37 -07:00
// refcounting.
2012-12-05 01:19:33 -08:00
if ( argc ) {
2013-06-18 03:00:37 -07:00
static const fallible_t fallible = fallible_t ( ) ;
mArgv = new ( fallible ) JS : : Heap < JS : : Value > [ argc ] ;
2012-12-05 01:19:33 -08:00
if ( ! mArgv ) {
* prv = NS_ERROR_OUT_OF_MEMORY ;
return ;
}
2007-03-22 10:30:00 -07:00
}
2007-09-18 17:26:39 -07:00
2007-10-29 06:45:07 -07:00
// Callers are allowed to pass in a null argv even for argc > 0. They can
// then use GetArgs to initialize the values.
if ( argv ) {
2012-08-22 08:56:38 -07:00
for ( uint32_t i = 0 ; i < argc ; + + i )
2007-03-22 10:30:00 -07:00
mArgv [ i ] = argv [ i ] ;
}
2007-10-31 03:52:22 -07:00
2012-11-12 17:15:00 -08:00
if ( argc > 0 ) {
2013-08-16 13:10:17 -07:00
mozilla : : HoldJSObjects ( this ) ;
2012-11-12 17:15:00 -08:00
}
* prv = NS_OK ;
2007-03-22 10:30:00 -07:00
}
nsJSArgArray : : ~ nsJSArgArray ( )
{
ReleaseJSObjects ( ) ;
}
void
nsJSArgArray : : ReleaseJSObjects ( )
{
2012-12-05 01:19:33 -08:00
if ( mArgv ) {
2013-06-18 03:00:37 -07:00
delete [ ] mArgv ;
2012-12-05 01:19:33 -08:00
}
if ( mArgc > 0 ) {
mArgc = 0 ;
2013-08-16 13:10:17 -07:00
mozilla : : DropJSObjects ( this ) ;
2012-12-05 01:19:33 -08:00
}
2007-03-22 10:30:00 -07:00
}
// QueryInterface implementation for nsJSArgArray
2013-08-01 18:29:05 -07:00
NS_IMPL_CYCLE_COLLECTION_CLASS ( nsJSArgArray )
2010-11-08 07:02:49 -08:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN ( nsJSArgArray )
2007-03-22 10:30:00 -07:00
tmp - > ReleaseJSObjects ( ) ;
2010-11-08 07:02:49 -08:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2007-03-22 10:30:00 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN ( nsJSArgArray )
2007-10-29 06:45:07 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN ( nsJSArgArray )
2013-05-27 04:50:49 -07:00
if ( tmp - > mArgv ) {
for ( uint32_t i = 0 ; i < tmp - > mArgc ; + + i ) {
NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK ( mArgv [ i ] )
}
2007-03-22 10:30:00 -07:00
}
2007-10-29 06:45:07 -07:00
NS_IMPL_CYCLE_COLLECTION_TRACE_END
2007-03-22 10:30:00 -07:00
2007-04-25 09:35:27 -07:00
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION ( nsJSArgArray )
2007-03-22 10:30:00 -07:00
NS_INTERFACE_MAP_ENTRY ( nsIArray )
NS_INTERFACE_MAP_ENTRY ( nsIJSArgArray )
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS ( nsISupports , nsIJSArgArray )
NS_INTERFACE_MAP_END
2011-03-06 03:11:31 -08:00
NS_IMPL_CYCLE_COLLECTING_ADDREF ( nsJSArgArray )
NS_IMPL_CYCLE_COLLECTING_RELEASE ( nsJSArgArray )
2007-03-22 10:30:00 -07:00
nsresult
2012-08-22 08:56:38 -07:00
nsJSArgArray : : GetArgs ( uint32_t * argc , void * * argv )
2007-03-22 10:30:00 -07:00
{
2012-12-05 01:19:33 -08:00
* argv = ( void * ) mArgv ;
* argc = mArgc ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
// nsIArray impl
2012-08-22 08:56:38 -07:00
NS_IMETHODIMP nsJSArgArray : : GetLength ( uint32_t * aLength )
2007-03-22 10:30:00 -07:00
{
2012-12-05 01:19:33 -08:00
* aLength = mArgc ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
/* void queryElementAt (in unsigned long index, in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
2012-08-22 08:56:38 -07:00
NS_IMETHODIMP nsJSArgArray : : QueryElementAt ( uint32_t index , const nsIID & uuid , void * * result )
2007-03-22 10:30:00 -07:00
{
2012-07-30 07:20:58 -07:00
* result = nullptr ;
2012-12-05 01:19:33 -08:00
if ( index > = mArgc )
2007-03-22 10:30:00 -07:00
return NS_ERROR_INVALID_ARG ;
if ( uuid . Equals ( NS_GET_IID ( nsIVariant ) ) | | uuid . Equals ( NS_GET_IID ( nsISupports ) ) ) {
2014-01-15 11:39:08 -08:00
// Have to copy a Heap into a Rooted to work with it.
JS : : Rooted < JS : : Value > val ( mContext , mArgv [ index ] ) ;
return nsContentUtils : : XPConnect ( ) - > JSToVariant ( mContext , val ,
2007-03-22 10:30:00 -07:00
( nsIVariant * * ) result ) ;
}
NS_WARNING ( " nsJSArgArray only handles nsIVariant " ) ;
return NS_ERROR_NO_INTERFACE ;
}
/* unsigned long indexOf (in unsigned long startIndex, in nsISupports element); */
2012-08-22 08:56:38 -07:00
NS_IMETHODIMP nsJSArgArray : : IndexOf ( uint32_t startIndex , nsISupports * element , uint32_t * _retval )
2007-03-22 10:30:00 -07:00
{
return NS_ERROR_NOT_IMPLEMENTED ;
}
/* nsISimpleEnumerator enumerate (); */
NS_IMETHODIMP nsJSArgArray : : Enumerate ( nsISimpleEnumerator * * _retval )
{
return NS_ERROR_NOT_IMPLEMENTED ;
}
// The factory function
2012-08-22 08:56:38 -07:00
nsresult NS_CreateJSArgv ( JSContext * aContext , uint32_t argc , void * argv ,
2012-03-11 00:53:05 -08:00
nsIJSArgArray * * aArray )
2007-03-22 10:30:00 -07:00
{
nsresult rv ;
nsJSArgArray * ret = new nsJSArgArray ( aContext , argc ,
2013-04-11 15:52:10 -07:00
static_cast < JS : : Value * > ( argv ) , & rv ) ;
2012-07-30 07:20:58 -07:00
if ( ret = = nullptr )
2007-03-22 10:30:00 -07:00
return NS_ERROR_OUT_OF_MEMORY ;
if ( NS_FAILED ( rv ) ) {
delete ret ;
return rv ;
}
return ret - > QueryInterface ( NS_GET_IID ( nsIArray ) , ( void * * ) aArray ) ;
}