nsJSEnvironment.h (7681B)
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 "mozilla/TimeStamp.h" 10 #include "nsCOMPtr.h" 11 #include "nsCycleCollectionParticipant.h" 12 #include "nsIArray.h" 13 #include "nsIScriptContext.h" 14 #include "nsIScriptGlobalObject.h" 15 #include "nsThreadUtils.h" 16 #include "prtime.h" 17 #include "xpcpublic.h" 18 19 class nsICycleCollectorListener; 20 class nsIDocShell; 21 22 namespace mozilla { 23 24 template <class> 25 class Maybe; 26 struct CycleCollectorResults; 27 28 static const uint32_t kMajorForgetSkippableCalls = 5; 29 30 } // namespace mozilla 31 32 class nsJSContext : public nsIScriptContext { 33 public: 34 nsJSContext(bool aGCOnDestruction, nsIScriptGlobalObject* aGlobalObject); 35 36 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 37 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSContext, 38 nsIScriptContext) 39 40 virtual nsIScriptGlobalObject* GetGlobalObject() override; 41 inline nsIScriptGlobalObject* GetGlobalObjectRef() { 42 return mGlobalObjectRef; 43 } 44 45 virtual nsresult SetProperty(JS::Handle<JSObject*> aTarget, 46 const char* aPropName, 47 nsISupports* aVal) override; 48 49 virtual bool GetProcessingScriptTag() override; 50 virtual void SetProcessingScriptTag(bool aResult) override; 51 52 virtual nsresult InitClasses(JS::Handle<JSObject*> aGlobalObj) override; 53 54 virtual void SetWindowProxy(JS::Handle<JSObject*> aWindowProxy) override; 55 virtual JSObject* GetWindowProxy() override; 56 57 enum IsShrinking { ShrinkingGC, NonShrinkingGC }; 58 59 // Setup all the statics etc - safe to call multiple times after Startup(). 60 static void EnsureStatics(); 61 62 static void SetLowMemoryState(bool aState); 63 64 static void GarbageCollectNow(JS::GCReason reason, 65 IsShrinking aShrinking = NonShrinkingGC); 66 67 static void RunIncrementalGCSlice(JS::GCReason aReason, 68 IsShrinking aShrinking, 69 JS::SliceBudget& aBudget); 70 71 static void CycleCollectNow(mozilla::CCReason aReason, 72 nsICycleCollectorListener* aListener = nullptr); 73 74 // Finish up any in-progress incremental GC. 75 static void PrepareForCycleCollectionSlice(mozilla::CCReason aReason, 76 mozilla::TimeStamp aDeadline); 77 78 // Run a cycle collector slice, using a heuristic to decide how long to run 79 // it. 80 static void RunCycleCollectorSlice(mozilla::CCReason aReason, 81 mozilla::TimeStamp aDeadline); 82 83 // Run a cycle collector slice, using the given work budget. 84 static void RunCycleCollectorWorkSlice(int64_t aWorkBudget); 85 86 static void BeginCycleCollectionCallback(mozilla::CCReason aReason); 87 static void EndCycleCollectionCallback( 88 const mozilla::CycleCollectorResults& aResults); 89 90 // Return the longest CC slice time since ClearMaxCCSliceTime() was last 91 // called. 92 static uint32_t GetMaxCCSliceTimeSinceClear(); 93 static void ClearMaxCCSliceTime(); 94 95 // If there is some pending CC or GC timer/runner, this will run it. 96 static void RunNextCollectorTimer( 97 JS::GCReason aReason, 98 mozilla::TimeStamp aDeadline = mozilla::TimeStamp()); 99 // If user has been idle and aDocShell is for an iframe being loaded in an 100 // already loaded top level docshell, this will run a CC or GC 101 // timer/runner if there is such pending. 102 static void MaybeRunNextCollectorSlice(nsIDocShell* aDocShell, 103 JS::GCReason aReason); 104 105 // The GC should run soon, in the zone of aObj if given. If aObj is 106 // nullptr, collect all Zones. 107 static void PokeGC(JS::GCReason aReason, JSObject* aObj, 108 mozilla::TimeDuration aDelay = 0); 109 110 // If usage is nearing a threshold, request idle-only GC work. (This is called 111 // when a collection would be relatively convenient.) 112 static void MaybePokeGC(); 113 114 // Immediately perform a non-incremental shrinking GC and CC. 115 static void DoLowMemoryGC(); 116 117 // Perform a non-incremental shrinking GC and CC according to 118 // IdleScheduler. 119 static void LowMemoryGC(); 120 121 static void MaybePokeCC(); 122 123 // Calling LikelyShortLivingObjectCreated() makes a GC more likely. 124 static void LikelyShortLivingObjectCreated(); 125 126 static bool HasHadCleanupSinceLastGC(); 127 128 nsIScriptGlobalObject* GetCachedGlobalObject() { 129 // Verify that we have a global so that this 130 // does always return a null when GetGlobalObject() is null. 131 JSObject* global = GetWindowProxy(); 132 return global ? mGlobalObjectRef.get() : nullptr; 133 } 134 135 protected: 136 virtual ~nsJSContext(); 137 138 // Helper to convert xpcom datatypes to jsvals. 139 nsresult ConvertSupportsTojsvals(JSContext* aCx, nsISupports* aArgs, 140 JS::Handle<JSObject*> aScope, 141 JS::MutableHandleVector<JS::Value> aArgsOut); 142 143 nsresult AddSupportsPrimitiveTojsvals(JSContext* aCx, nsISupports* aArg, 144 JS::Value* aArgv); 145 146 private: 147 void Destroy(); 148 149 JS::Heap<JSObject*> mWindowProxy; 150 151 bool mGCOnDestruction; 152 bool mProcessingScriptTag; 153 154 // mGlobalObjectRef ensures that the outer window stays alive as long as the 155 // context does. It is eventually collected by the cycle collector. 156 nsCOMPtr<nsIScriptGlobalObject> mGlobalObjectRef; 157 158 static bool DOMOperationCallback(JSContext* cx); 159 }; 160 161 namespace mozilla::dom { 162 163 class SerializedStackHolder; 164 165 void StartupJSEnvironment(); 166 void ShutdownJSEnvironment(); 167 168 // Runnable that's used to do async error reporting 169 class AsyncErrorReporter final : public mozilla::Runnable { 170 public: 171 explicit AsyncErrorReporter(xpc::ErrorReport* aReport); 172 // SerializeStack is suitable for main or worklet thread use. 173 // Stacks from worker threads are not supported. 174 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1578968 175 void SerializeStack(JSContext* aCx, JS::Handle<JSObject*> aStack); 176 177 // Set the exception value associated with this error report. 178 // Should only be called from the main thread. 179 void SetException(JSContext* aCx, JS::Handle<JS::Value> aException); 180 181 protected: 182 NS_IMETHOD Run() override; 183 184 // This is only used on main thread! 185 JS::PersistentRooted<JS::Value> mException; 186 bool mHasException = false; 187 188 RefPtr<xpc::ErrorReport> mReport; 189 // This may be used to marshal a stack from an arbitrary thread/runtime into 190 // the main thread/runtime where the console service runs. 191 UniquePtr<SerializedStackHolder> mStackHolder; 192 }; 193 194 } // namespace mozilla::dom 195 196 // An interface for fast and native conversion to/from nsIArray. If an object 197 // supports this interface, JS can reach directly in for the argv, and avoid 198 // nsISupports conversion. If this interface is not supported, the object will 199 // be queried for nsIArray, and everything converted via xpcom objects. 200 #define NS_IJSARGARRAY_IID \ 201 {0xb6acdac8, 0xf5c6, 0x432c, {0xa8, 0x6e, 0x33, 0xee, 0xb1, 0xb0, 0xcd, 0xdc}} 202 203 class nsIJSArgArray : public nsIArray { 204 public: 205 NS_INLINE_DECL_STATIC_IID(NS_IJSARGARRAY_IID) 206 // Bug 312003 describes why this must be "void **", but after calling argv 207 // may be cast to JS::Value* and the args found at: 208 // ((JS::Value*)argv)[0], ..., ((JS::Value*)argv)[argc - 1] 209 virtual nsresult GetArgs(uint32_t* argc, void** argv) = 0; 210 }; 211 212 #endif /* nsJSEnvironment_h */