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