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