michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #ifndef nsJSEnvironment_h michael@0: #define nsJSEnvironment_h michael@0: michael@0: #include "nsIScriptContext.h" michael@0: #include "nsIScriptGlobalObject.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIObserver.h" michael@0: #include "prtime.h" michael@0: #include "nsCycleCollectionParticipant.h" michael@0: #include "nsIXPConnect.h" michael@0: #include "nsIArray.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: class nsICycleCollectorListener; michael@0: class nsIXPConnectJSObjectHolder; michael@0: class nsScriptNameSpaceManager; michael@0: class nsCycleCollectionNoteRootCallback; michael@0: michael@0: namespace JS { michael@0: class AutoValueVector; michael@0: } michael@0: michael@0: namespace mozilla { michael@0: template class Maybe; michael@0: struct CycleCollectorResults; michael@0: } michael@0: michael@0: // The amount of time we wait between a request to GC (due to leaving michael@0: // a page) and doing the actual GC. michael@0: #define NS_GC_DELAY 4000 // ms michael@0: michael@0: class nsJSContext : public nsIScriptContext michael@0: { michael@0: public: michael@0: nsJSContext(bool aGCOnDestruction, nsIScriptGlobalObject* aGlobalObject); michael@0: virtual ~nsJSContext(); michael@0: michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSContext, michael@0: nsIScriptContext) michael@0: michael@0: virtual nsIScriptGlobalObject *GetGlobalObject() MOZ_OVERRIDE; michael@0: inline nsIScriptGlobalObject *GetGlobalObjectRef() { return mGlobalObjectRef; } michael@0: michael@0: virtual JSContext* GetNativeContext() MOZ_OVERRIDE; michael@0: virtual nsresult InitContext() MOZ_OVERRIDE; michael@0: virtual bool IsContextInitialized() MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult SetProperty(JS::Handle aTarget, const char* aPropName, nsISupports* aVal) MOZ_OVERRIDE; michael@0: michael@0: virtual bool GetProcessingScriptTag() MOZ_OVERRIDE; michael@0: virtual void SetProcessingScriptTag(bool aResult) MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult InitClasses(JS::Handle aGlobalObj) MOZ_OVERRIDE; michael@0: michael@0: virtual void WillInitializeContext() MOZ_OVERRIDE; michael@0: virtual void DidInitializeContext() MOZ_OVERRIDE; michael@0: michael@0: virtual void SetWindowProxy(JS::Handle aWindowProxy) MOZ_OVERRIDE; michael@0: virtual JSObject* GetWindowProxy() MOZ_OVERRIDE; michael@0: virtual JSObject* GetWindowProxyPreserveColor() MOZ_OVERRIDE; michael@0: michael@0: static void LoadStart(); michael@0: static void LoadEnd(); michael@0: michael@0: enum IsCompartment { michael@0: CompartmentGC, michael@0: NonCompartmentGC michael@0: }; michael@0: michael@0: enum IsShrinking { michael@0: ShrinkingGC, michael@0: NonShrinkingGC michael@0: }; michael@0: michael@0: enum IsIncremental { michael@0: IncrementalGC, michael@0: NonIncrementalGC michael@0: }; michael@0: michael@0: // Setup all the statics etc - safe to call multiple times after Startup(). michael@0: void EnsureStatics(); michael@0: michael@0: static void GarbageCollectNow(JS::gcreason::Reason reason, michael@0: IsIncremental aIncremental = NonIncrementalGC, michael@0: IsCompartment aCompartment = NonCompartmentGC, michael@0: IsShrinking aShrinking = NonShrinkingGC, michael@0: int64_t aSliceMillis = 0); michael@0: static void ShrinkGCBuffersNow(); michael@0: michael@0: // If aExtraForgetSkippableCalls is -1, forgetSkippable won't be michael@0: // called even if the previous collection was GC. michael@0: static void CycleCollectNow(nsICycleCollectorListener *aListener = nullptr, michael@0: int32_t aExtraForgetSkippableCalls = 0); michael@0: michael@0: // Run a cycle collector slice, using a heuristic to decide how long to run it. michael@0: static void RunCycleCollectorSlice(); michael@0: michael@0: static void BeginCycleCollectionCallback(); michael@0: static void EndCycleCollectionCallback(mozilla::CycleCollectorResults &aResults); michael@0: michael@0: static void RunNextCollectorTimer(); michael@0: michael@0: static void PokeGC(JS::gcreason::Reason aReason, int aDelay = 0); michael@0: static void KillGCTimer(); michael@0: michael@0: static void PokeShrinkGCBuffers(); michael@0: static void KillShrinkGCBuffersTimer(); michael@0: michael@0: static void MaybePokeCC(); michael@0: static void KillCCTimer(); michael@0: static void KillICCTimer(); michael@0: static void KillFullGCTimer(); michael@0: static void KillInterSliceGCTimer(); michael@0: michael@0: // Calling LikelyShortLivingObjectCreated() makes a GC more likely. michael@0: static void LikelyShortLivingObjectCreated(); michael@0: michael@0: virtual void GC(JS::gcreason::Reason aReason) MOZ_OVERRIDE; michael@0: michael@0: static uint32_t CleanupsSinceLastGC(); michael@0: michael@0: nsIScriptGlobalObject* GetCachedGlobalObject() michael@0: { michael@0: // Verify that we have a global so that this michael@0: // does always return a null when GetGlobalObject() is null. michael@0: JSObject* global = GetWindowProxy(); michael@0: return global ? mGlobalObjectRef.get() : nullptr; michael@0: } michael@0: protected: michael@0: nsresult InitializeExternalClasses(); michael@0: michael@0: // Helper to convert xpcom datatypes to jsvals. michael@0: nsresult ConvertSupportsTojsvals(nsISupports *aArgs, michael@0: JS::Handle aScope, michael@0: JS::AutoValueVector &aArgsOut); michael@0: michael@0: nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv); michael@0: michael@0: // Report the pending exception on our mContext, if any. This michael@0: // function will set aside the frame chain on mContext before michael@0: // reporting. michael@0: void ReportPendingException(); michael@0: michael@0: private: michael@0: void DestroyJSContext(); michael@0: michael@0: nsrefcnt GetCCRefcnt(); michael@0: michael@0: JSContext *mContext; michael@0: JS::Heap mWindowProxy; michael@0: michael@0: bool mIsInitialized; michael@0: bool mGCOnDestruction; michael@0: bool mProcessingScriptTag; michael@0: michael@0: PRTime mModalStateTime; michael@0: uint32_t mModalStateDepth; michael@0: michael@0: // mGlobalObjectRef ensures that the outer window stays alive as long as the michael@0: // context does. It is eventually collected by the cycle collector. michael@0: nsCOMPtr mGlobalObjectRef; michael@0: michael@0: static void JSOptionChangedCallback(const char *pref, void *data); michael@0: michael@0: static bool DOMOperationCallback(JSContext *cx); michael@0: }; michael@0: michael@0: class nsIJSRuntimeService; michael@0: class nsIPrincipal; michael@0: class nsPIDOMWindow; michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: void StartupJSEnvironment(); michael@0: void ShutdownJSEnvironment(); michael@0: michael@0: // Get the NameSpaceManager, creating if necessary michael@0: nsScriptNameSpaceManager* GetNameSpaceManager(); michael@0: michael@0: // Runnable that's used to do async error reporting michael@0: class AsyncErrorReporter : public nsRunnable michael@0: { michael@0: public: michael@0: // aWindow may be null if this error report is not associated with a window michael@0: AsyncErrorReporter(JSRuntime* aRuntime, michael@0: JSErrorReport* aErrorReport, michael@0: const char* aFallbackMessage, michael@0: bool aIsChromeError, // To determine category michael@0: nsPIDOMWindow* aWindow); michael@0: michael@0: NS_IMETHOD Run() michael@0: { michael@0: ReportError(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: protected: michael@0: // Do the actual error reporting michael@0: void ReportError(); michael@0: michael@0: nsString mErrorMsg; michael@0: nsString mFileName; michael@0: nsString mSourceLine; michael@0: nsCString mCategory; michael@0: uint32_t mLineNumber; michael@0: uint32_t mColumn; michael@0: uint32_t mFlags; michael@0: uint64_t mInnerWindowID; michael@0: }; michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla michael@0: michael@0: // An interface for fast and native conversion to/from nsIArray. If an object michael@0: // supports this interface, JS can reach directly in for the argv, and avoid michael@0: // nsISupports conversion. If this interface is not supported, the object will michael@0: // be queried for nsIArray, and everything converted via xpcom objects. michael@0: #define NS_IJSARGARRAY_IID \ michael@0: { 0xb6acdac8, 0xf5c6, 0x432c, \ michael@0: { 0xa8, 0x6e, 0x33, 0xee, 0xb1, 0xb0, 0xcd, 0xdc } } michael@0: michael@0: class nsIJSArgArray : public nsIArray michael@0: { michael@0: public: michael@0: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSARGARRAY_IID) michael@0: // Bug 312003 describes why this must be "void **", but after calling argv michael@0: // may be cast to JS::Value* and the args found at: michael@0: // ((JS::Value*)argv)[0], ..., ((JS::Value*)argv)[argc - 1] michael@0: virtual nsresult GetArgs(uint32_t *argc, void **argv) = 0; michael@0: }; michael@0: michael@0: NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSArgArray, NS_IJSARGARRAY_IID) michael@0: michael@0: /* prototypes */ michael@0: void NS_ScriptErrorReporter(JSContext *cx, const char *message, JSErrorReport *report); michael@0: michael@0: JSObject* NS_DOMReadStructuredClone(JSContext* cx, michael@0: JSStructuredCloneReader* reader, uint32_t tag, michael@0: uint32_t data, void* closure); michael@0: michael@0: bool NS_DOMWriteStructuredClone(JSContext* cx, michael@0: JSStructuredCloneWriter* writer, michael@0: JS::Handle obj, void *closure); michael@0: michael@0: void NS_DOMStructuredCloneError(JSContext* cx, uint32_t errorid); michael@0: michael@0: #endif /* nsJSEnvironment_h */