1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 #ifndef nsJSEnvironment_h 7 #define nsJSEnvironment_h 8 9 #include "nsIScriptContext.h" 10 #include "nsIScriptGlobalObject.h" 11 #include "nsCOMPtr.h" 12 #include "nsIObserver.h" 13 #include "prtime.h" 14 #include "nsCycleCollectionParticipant.h" 15 #include "nsIXPConnect.h" 16 #include "nsIArray.h" 17 #include "mozilla/Attributes.h" 18 #include "mozilla/TimeStamp.h" 19 #include "nsThreadUtils.h" 20 #include "xpcpublic.h" 21 22 class nsICycleCollectorListener; 23 class nsScriptNameSpaceManager; 24 class nsIDocShell; 25 26 namespace mozilla { 27 template <class> 28 class Maybe; 29 struct CycleCollectorResults; 30 } // namespace mozilla 31 32 // The amount of time we wait between a request to GC (due to leaving 33 // a page) and doing the actual GC. 34 #define NS_GC_DELAY 4000 // ms 35 36 #define NS_MAJOR_FORGET_SKIPPABLE_CALLS 5 37 38 class nsJSContext : public nsIScriptContext { 39 public: 40 nsJSContext(bool aGCOnDestruction, nsIScriptGlobalObject* aGlobalObject); 41 42 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 43 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSContext, 44 nsIScriptContext) 45 46 virtual nsIScriptGlobalObject* GetGlobalObject() override; GetGlobalObjectRef()47 inline nsIScriptGlobalObject* GetGlobalObjectRef() { 48 return mGlobalObjectRef; 49 } 50 51 virtual nsresult InitContext() override; 52 virtual bool IsContextInitialized() override; 53 54 virtual nsresult SetProperty(JS::Handle<JSObject*> aTarget, 55 const char* aPropName, 56 nsISupports* aVal) override; 57 58 virtual bool GetProcessingScriptTag() override; 59 virtual void SetProcessingScriptTag(bool aResult) override; 60 61 virtual nsresult InitClasses(JS::Handle<JSObject*> aGlobalObj) override; 62 63 virtual void WillInitializeContext() override; 64 virtual void DidInitializeContext() override; 65 66 virtual void SetWindowProxy(JS::Handle<JSObject*> aWindowProxy) override; 67 virtual JSObject* GetWindowProxy() override; 68 69 static void LoadStart(); 70 static void LoadEnd(); 71 72 enum IsShrinking { ShrinkingGC, NonShrinkingGC }; 73 74 enum IsIncremental { IncrementalGC, NonIncrementalGC }; 75 76 // Setup all the statics etc - safe to call multiple times after Startup(). 77 void EnsureStatics(); 78 79 static void GarbageCollectNow(JS::gcreason::Reason reason, 80 IsIncremental aIncremental = NonIncrementalGC, 81 IsShrinking aShrinking = NonShrinkingGC, 82 int64_t aSliceMillis = 0); 83 84 static void CycleCollectNow(nsICycleCollectorListener* aListener = nullptr); 85 86 // Run a cycle collector slice, using a heuristic to decide how long to run 87 // it. 88 static void RunCycleCollectorSlice(mozilla::TimeStamp aDeadline); 89 90 // Run a cycle collector slice, using the given work budget. 91 static void RunCycleCollectorWorkSlice(int64_t aWorkBudget); 92 93 static void BeginCycleCollectionCallback(); 94 static void EndCycleCollectionCallback( 95 mozilla::CycleCollectorResults& aResults); 96 97 // Return the longest CC slice time since ClearMaxCCSliceTime() was last 98 // called. 99 static uint32_t GetMaxCCSliceTimeSinceClear(); 100 static void ClearMaxCCSliceTime(); 101 102 // If there is some pending CC or GC timer/runner, this will run it. 103 static void RunNextCollectorTimer( 104 JS::gcreason::Reason aReason, 105 mozilla::TimeStamp aDeadline = mozilla::TimeStamp()); 106 // If user has been idle and aDocShell is for an iframe being loaded in an 107 // already loaded top level docshell, this will run a CC or GC 108 // timer/runner if there is such pending. 109 static void MaybeRunNextCollectorSlice(nsIDocShell* aDocShell, 110 JS::gcreason::Reason aReason); 111 112 // The GC should probably run soon, in the zone of object aObj (if given). 113 static void PokeGC(JS::gcreason::Reason aReason, JSObject* aObj, 114 int aDelay = 0); 115 static void KillGCTimer(); 116 117 static void PokeShrinkingGC(); 118 static void KillShrinkingGCTimer(); 119 120 static void MaybePokeCC(); 121 static void KillCCRunner(); 122 static void KillICCRunner(); 123 static void KillFullGCTimer(); 124 static void KillInterSliceGCRunner(); 125 126 // Calling LikelyShortLivingObjectCreated() makes a GC more likely. 127 static void LikelyShortLivingObjectCreated(); 128 129 static uint32_t CleanupsSinceLastGC(); 130 GetCachedGlobalObject()131 nsIScriptGlobalObject* GetCachedGlobalObject() { 132 // Verify that we have a global so that this 133 // does always return a null when GetGlobalObject() is null. 134 JSObject* global = GetWindowProxy(); 135 return global ? mGlobalObjectRef.get() : nullptr; 136 } 137 138 protected: 139 virtual ~nsJSContext(); 140 141 // Helper to convert xpcom datatypes to jsvals. 142 nsresult ConvertSupportsTojsvals(nsISupports* aArgs, 143 JS::Handle<JSObject*> aScope, 144 JS::AutoValueVector& aArgsOut); 145 146 nsresult AddSupportsPrimitiveTojsvals(nsISupports* aArg, JS::Value* aArgv); 147 148 private: 149 void Destroy(); 150 151 JS::Heap<JSObject*> mWindowProxy; 152 153 bool mIsInitialized; 154 bool mGCOnDestruction; 155 bool mProcessingScriptTag; 156 157 PRTime mModalStateTime; 158 uint32_t mModalStateDepth; 159 160 // mGlobalObjectRef ensures that the outer window stays alive as long as the 161 // context does. It is eventually collected by the cycle collector. 162 nsCOMPtr<nsIScriptGlobalObject> mGlobalObjectRef; 163 164 static bool DOMOperationCallback(JSContext* cx); 165 }; 166 167 namespace mozilla { 168 namespace dom { 169 170 void StartupJSEnvironment(); 171 void ShutdownJSEnvironment(); 172 173 // Get the NameSpaceManager, creating if necessary 174 nsScriptNameSpaceManager* GetNameSpaceManager(); 175 176 // Peek the NameSpaceManager, without creating it. 177 nsScriptNameSpaceManager* PeekNameSpaceManager(); 178 179 // Runnable that's used to do async error reporting 180 class AsyncErrorReporter final : public mozilla::Runnable { 181 public: 182 // aWindow may be null if this error report is not associated with a window AsyncErrorReporter(xpc::ErrorReport * aReport)183 explicit AsyncErrorReporter(xpc::ErrorReport* aReport) 184 : Runnable("dom::AsyncErrorReporter"), mReport(aReport) {} 185 Run()186 NS_IMETHOD Run() override { 187 mReport->LogToConsole(); 188 return NS_OK; 189 } 190 191 protected: 192 RefPtr<xpc::ErrorReport> mReport; 193 }; 194 195 } // namespace dom 196 } // namespace mozilla 197 198 // An interface for fast and native conversion to/from nsIArray. If an object 199 // supports this interface, JS can reach directly in for the argv, and avoid 200 // nsISupports conversion. If this interface is not supported, the object will 201 // be queried for nsIArray, and everything converted via xpcom objects. 202 #define NS_IJSARGARRAY_IID \ 203 { \ 204 0xb6acdac8, 0xf5c6, 0x432c, { \ 205 0xa8, 0x6e, 0x33, 0xee, 0xb1, 0xb0, 0xcd, 0xdc \ 206 } \ 207 } 208 209 class nsIJSArgArray : public nsIArray { 210 public: 211 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSARGARRAY_IID) 212 // Bug 312003 describes why this must be "void **", but after calling argv 213 // may be cast to JS::Value* and the args found at: 214 // ((JS::Value*)argv)[0], ..., ((JS::Value*)argv)[argc - 1] 215 virtual nsresult GetArgs(uint32_t* argc, void** argv) = 0; 216 }; 217 218 NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSArgArray, NS_IJSARGARRAY_IID) 219 220 #endif /* nsJSEnvironment_h */ 221