1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 : #ifndef nsJSEnvironment_h
38 : #define nsJSEnvironment_h
39 :
40 : #include "nsIScriptContext.h"
41 : #include "nsIScriptRuntime.h"
42 : #include "nsCOMPtr.h"
43 : #include "jsapi.h"
44 : #include "jsfriendapi.h"
45 : #include "nsIObserver.h"
46 : #include "nsIXPCScriptNotify.h"
47 : #include "prtime.h"
48 : #include "nsCycleCollectionParticipant.h"
49 : #include "nsIXPConnect.h"
50 : #include "nsIArray.h"
51 :
52 : class nsIXPConnectJSObjectHolder;
53 : class nsRootedJSValueArray;
54 : class nsScriptNameSpaceManager;
55 : namespace mozilla {
56 : template <class> class Maybe;
57 : }
58 :
59 : // The amount of time we wait between a request to GC (due to leaving
60 : // a page) and doing the actual GC.
61 : #define NS_GC_DELAY 4000 // ms
62 :
63 : class nsJSContext : public nsIScriptContext,
64 : public nsIXPCScriptNotify
65 : {
66 : public:
67 : nsJSContext(JSRuntime *aRuntime);
68 : virtual ~nsJSContext();
69 :
70 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
71 1464 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSContext,
72 : nsIScriptContext)
73 :
74 : virtual nsIScriptObjectPrincipal* GetObjectPrincipal();
75 :
76 0 : virtual PRUint32 GetScriptTypeID()
77 0 : { return nsIProgrammingLanguage::JAVASCRIPT; }
78 :
79 : virtual nsresult EvaluateString(const nsAString& aScript,
80 : JSObject* aScopeObject,
81 : nsIPrincipal *principal,
82 : nsIPrincipal *originPrincipal,
83 : const char *aURL,
84 : PRUint32 aLineNo,
85 : PRUint32 aVersion,
86 : nsAString *aRetValue,
87 : bool* aIsUndefined);
88 : virtual nsresult EvaluateStringWithValue(const nsAString& aScript,
89 : JSObject* aScopeObject,
90 : nsIPrincipal* aPrincipal,
91 : const char* aURL,
92 : PRUint32 aLineNo,
93 : PRUint32 aVersion,
94 : JS::Value* aRetValue,
95 : bool* aIsUndefined);
96 :
97 : virtual nsresult CompileScript(const PRUnichar* aText,
98 : PRInt32 aTextLength,
99 : nsIPrincipal *principal,
100 : const char *aURL,
101 : PRUint32 aLineNo,
102 : PRUint32 aVersion,
103 : nsScriptObjectHolder<JSScript>& aScriptObject);
104 : virtual nsresult ExecuteScript(JSScript* aScriptObject,
105 : JSObject* aScopeObject,
106 : nsAString* aRetValue,
107 : bool* aIsUndefined);
108 :
109 : virtual nsresult CompileEventHandler(nsIAtom *aName,
110 : PRUint32 aArgCount,
111 : const char** aArgNames,
112 : const nsAString& aBody,
113 : const char *aURL, PRUint32 aLineNo,
114 : PRUint32 aVersion,
115 : nsScriptObjectHolder<JSObject>& aHandler);
116 : virtual nsresult CallEventHandler(nsISupports* aTarget, JSObject* aScope,
117 : JSObject* aHandler,
118 : nsIArray *argv, nsIVariant **rv);
119 : virtual nsresult BindCompiledEventHandler(nsISupports *aTarget,
120 : JSObject *aScope,
121 : JSObject* aHandler,
122 : nsScriptObjectHolder<JSObject>& aBoundHandler);
123 : virtual nsresult CompileFunction(JSObject* aTarget,
124 : const nsACString& aName,
125 : PRUint32 aArgCount,
126 : const char** aArgArray,
127 : const nsAString& aBody,
128 : const char* aURL,
129 : PRUint32 aLineNo,
130 : PRUint32 aVersion,
131 : bool aShared,
132 : JSObject** aFunctionObject);
133 :
134 : virtual nsIScriptGlobalObject *GetGlobalObject();
135 : virtual JSContext* GetNativeContext();
136 : virtual JSObject* GetNativeGlobal();
137 : virtual nsresult CreateNativeGlobalForInner(
138 : nsIScriptGlobalObject *aGlobal,
139 : bool aIsChrome,
140 : nsIPrincipal *aPrincipal,
141 : JSObject** aNativeGlobal,
142 : nsISupports **aHolder);
143 : virtual nsresult ConnectToInner(nsIScriptGlobalObject *aNewInner,
144 : JSObject *aOuterGlobal);
145 : virtual nsresult InitContext();
146 : virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
147 : nsIScriptGlobalObject *aCurrentInner);
148 : virtual nsresult SetOuterObject(JSObject* aOuterObject);
149 : virtual nsresult InitOuterWindow();
150 : virtual bool IsContextInitialized();
151 :
152 : virtual void ScriptEvaluated(bool aTerminated);
153 : virtual void SetTerminationFunction(nsScriptTerminationFunc aFunc,
154 : nsIDOMWindow* aRef);
155 : virtual bool GetScriptsEnabled();
156 : virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts);
157 :
158 : virtual nsresult SetProperty(JSObject* aTarget, const char* aPropName, nsISupports* aVal);
159 :
160 : virtual bool GetProcessingScriptTag();
161 : virtual void SetProcessingScriptTag(bool aResult);
162 :
163 : virtual bool GetExecutingScript();
164 :
165 : virtual void SetGCOnDestruction(bool aGCOnDestruction);
166 :
167 : virtual nsresult InitClasses(JSObject* aGlobalObj);
168 :
169 : virtual void WillInitializeContext();
170 : virtual void DidInitializeContext();
171 :
172 : virtual nsresult Serialize(nsIObjectOutputStream* aStream, JSScript* aScriptObject);
173 : virtual nsresult Deserialize(nsIObjectInputStream* aStream,
174 : nsScriptObjectHolder<JSScript>& aResult);
175 :
176 : virtual nsresult DropScriptObject(void *object);
177 : virtual nsresult HoldScriptObject(void *object);
178 :
179 : virtual void EnterModalState();
180 : virtual void LeaveModalState();
181 :
182 : NS_DECL_NSIXPCSCRIPTNOTIFY
183 :
184 : static void LoadStart();
185 : static void LoadEnd();
186 :
187 : static void GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind = nsGCNormal);
188 : static void ShrinkGCBuffersNow();
189 : // If aExtraForgetSkippableCalls is -1, forgetSkippable won't be
190 : // called even if the previous collection was GC.
191 : static void CycleCollectNow(nsICycleCollectorListener *aListener = nsnull,
192 : PRInt32 aExtraForgetSkippableCalls = 0);
193 :
194 : static void PokeGC(js::gcreason::Reason aReason, int aDelay = 0);
195 : static void KillGCTimer();
196 :
197 : static void PokeShrinkGCBuffers();
198 : static void KillShrinkGCBuffersTimer();
199 :
200 : static void MaybePokeCC();
201 : static void KillCCTimer();
202 :
203 : virtual void GC(js::gcreason::Reason aReason);
204 :
205 : static bool CleanupSinceLastGC();
206 :
207 0 : nsIScriptGlobalObject* GetCachedGlobalObject()
208 : {
209 : // Verify that we have a global so that this
210 : // does always return a null when GetGlobalObject() is null.
211 0 : JSObject* global = JS_GetGlobalObject(mContext);
212 0 : return global ? mGlobalObjectRef.get() : nsnull;
213 : }
214 : protected:
215 : nsresult InitializeExternalClasses();
216 :
217 : // Helper to convert xpcom datatypes to jsvals.
218 : nsresult ConvertSupportsTojsvals(nsISupports *aArgs,
219 : JSObject *aScope,
220 : PRUint32 *aArgc,
221 : jsval **aArgv,
222 : mozilla::Maybe<nsRootedJSValueArray> &aPoolRelease);
223 :
224 : nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv);
225 :
226 : // given an nsISupports object (presumably an event target or some other
227 : // DOM object), get (or create) the JSObject wrapping it.
228 : nsresult JSObjectFromInterface(nsISupports *aSup, JSObject *aScript,
229 : JSObject **aRet);
230 :
231 : // Report the pending exception on our mContext, if any. This
232 : // function will set aside the frame chain on mContext before
233 : // reporting.
234 : void ReportPendingException();
235 : private:
236 : void DestroyJSContext();
237 :
238 : nsrefcnt GetCCRefcnt();
239 :
240 : JSContext *mContext;
241 : PRUint32 mNumEvaluations;
242 :
243 : protected:
244 : struct TerminationFuncHolder;
245 : friend struct TerminationFuncHolder;
246 :
247 : struct TerminationFuncClosure
248 : {
249 0 : TerminationFuncClosure(nsScriptTerminationFunc aFunc,
250 : nsISupports* aArg,
251 : TerminationFuncClosure* aNext) :
252 : mTerminationFunc(aFunc),
253 : mTerminationFuncArg(aArg),
254 0 : mNext(aNext)
255 : {
256 0 : }
257 0 : ~TerminationFuncClosure()
258 0 : {
259 0 : delete mNext;
260 0 : }
261 :
262 : nsScriptTerminationFunc mTerminationFunc;
263 : nsCOMPtr<nsISupports> mTerminationFuncArg;
264 : TerminationFuncClosure* mNext;
265 : };
266 :
267 : struct TerminationFuncHolder
268 : {
269 0 : TerminationFuncHolder(nsJSContext* aContext)
270 : : mContext(aContext),
271 0 : mTerminations(aContext->mTerminations)
272 : {
273 0 : aContext->mTerminations = nsnull;
274 0 : }
275 0 : ~TerminationFuncHolder()
276 : {
277 : // Have to be careful here. mContext might have picked up new
278 : // termination funcs while the script was evaluating. Prepend whatever
279 : // we have to the current termination funcs on the context (since our
280 : // termination funcs were posted first).
281 0 : if (mTerminations) {
282 0 : TerminationFuncClosure* cur = mTerminations;
283 0 : while (cur->mNext) {
284 0 : cur = cur->mNext;
285 : }
286 0 : cur->mNext = mContext->mTerminations;
287 0 : mContext->mTerminations = mTerminations;
288 : }
289 0 : }
290 :
291 : nsJSContext* mContext;
292 : TerminationFuncClosure* mTerminations;
293 : };
294 :
295 : TerminationFuncClosure* mTerminations;
296 :
297 : private:
298 : bool mIsInitialized;
299 : bool mScriptsEnabled;
300 : bool mGCOnDestruction;
301 : bool mProcessingScriptTag;
302 :
303 : PRUint32 mExecuteDepth;
304 : PRUint32 mDefaultJSOptions;
305 : PRTime mOperationCallbackTime;
306 :
307 : PRTime mModalStateTime;
308 : PRUint32 mModalStateDepth;
309 :
310 : // mGlobalObjectRef ensures that the outer window stays alive as long as the
311 : // context does. It is eventually collected by the cycle collector.
312 : nsCOMPtr<nsIScriptGlobalObject> mGlobalObjectRef;
313 :
314 : static int JSOptionChangedCallback(const char *pref, void *data);
315 :
316 : static JSBool DOMOperationCallback(JSContext *cx);
317 : };
318 :
319 : class nsIJSRuntimeService;
320 :
321 : class nsJSRuntime : public nsIScriptRuntime
322 50 : {
323 : public:
324 : // let people who can see us use our runtime for convenience.
325 : static JSRuntime *sRuntime;
326 :
327 : public:
328 : // nsISupports
329 : NS_DECL_ISUPPORTS
330 :
331 0 : virtual PRUint32 GetScriptTypeID() {
332 0 : return nsIProgrammingLanguage::JAVASCRIPT;
333 : }
334 :
335 : virtual already_AddRefed<nsIScriptContext> CreateContext();
336 :
337 : virtual nsresult ParseVersion(const nsString &aVersionStr, PRUint32 *flags);
338 :
339 : virtual nsresult DropScriptObject(void *object);
340 : virtual nsresult HoldScriptObject(void *object);
341 :
342 : static void Startup();
343 : static void Shutdown();
344 : // Setup all the statics etc - safe to call multiple times after Startup()
345 : static nsresult Init();
346 : // Get the NameSpaceManager, creating if necessary
347 : static nsScriptNameSpaceManager* GetNameSpaceManager();
348 : };
349 :
350 : // An interface for fast and native conversion to/from nsIArray. If an object
351 : // supports this interface, JS can reach directly in for the argv, and avoid
352 : // nsISupports conversion. If this interface is not supported, the object will
353 : // be queried for nsIArray, and everything converted via xpcom objects.
354 : #define NS_IJSARGARRAY_IID \
355 : { 0xb6acdac8, 0xf5c6, 0x432c, \
356 : { 0xa8, 0x6e, 0x33, 0xee, 0xb1, 0xb0, 0xcd, 0xdc } }
357 :
358 : class nsIJSArgArray : public nsIArray
359 0 : {
360 : public:
361 : NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSARGARRAY_IID)
362 : // Bug 312003 describes why this must be "void **", but after calling argv
363 : // may be cast to jsval* and the args found at:
364 : // ((jsval*)argv)[0], ..., ((jsval*)argv)[argc - 1]
365 : virtual nsresult GetArgs(PRUint32 *argc, void **argv) = 0;
366 : };
367 :
368 : NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSArgArray, NS_IJSARGARRAY_IID)
369 :
370 : /* factory functions */
371 : nsresult NS_CreateJSRuntime(nsIScriptRuntime **aRuntime);
372 :
373 : /* prototypes */
374 : void NS_ScriptErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);
375 :
376 : JSObject* NS_DOMReadStructuredClone(JSContext* cx,
377 : JSStructuredCloneReader* reader, uint32_t tag,
378 : uint32_t data, void* closure);
379 :
380 : JSBool NS_DOMWriteStructuredClone(JSContext* cx,
381 : JSStructuredCloneWriter* writer,
382 : JSObject* obj, void *closure);
383 :
384 : void NS_DOMStructuredCloneError(JSContext* cx, uint32_t errorid);
385 :
386 : #endif /* nsJSEnvironment_h */
|