|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */ |
|
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 |
|
7 #ifndef xpcpublic_h |
|
8 #define xpcpublic_h |
|
9 |
|
10 #include "jsapi.h" |
|
11 #include "jsproxy.h" |
|
12 #include "js/HeapAPI.h" |
|
13 #include "js/GCAPI.h" |
|
14 |
|
15 #include "nsISupports.h" |
|
16 #include "nsIURI.h" |
|
17 #include "nsIPrincipal.h" |
|
18 #include "nsWrapperCache.h" |
|
19 #include "nsStringGlue.h" |
|
20 #include "nsTArray.h" |
|
21 #include "mozilla/dom/JSSlots.h" |
|
22 #include "nsMathUtils.h" |
|
23 #include "nsStringBuffer.h" |
|
24 #include "mozilla/dom/BindingDeclarations.h" |
|
25 |
|
26 class nsGlobalWindow; |
|
27 class nsIPrincipal; |
|
28 class nsScriptNameSpaceManager; |
|
29 class nsIGlobalObject; |
|
30 class nsIMemoryReporterCallback; |
|
31 |
|
32 #ifndef BAD_TLS_INDEX |
|
33 #define BAD_TLS_INDEX ((uint32_t) -1) |
|
34 #endif |
|
35 |
|
36 namespace xpc { |
|
37 |
|
38 class Scriptability { |
|
39 public: |
|
40 Scriptability(JSCompartment *c); |
|
41 bool Allowed(); |
|
42 bool IsImmuneToScriptPolicy(); |
|
43 |
|
44 void Block(); |
|
45 void Unblock(); |
|
46 void SetDocShellAllowsScript(bool aAllowed); |
|
47 |
|
48 static Scriptability& Get(JSObject *aScope); |
|
49 |
|
50 private: |
|
51 // Whenever a consumer wishes to prevent script from running on a global, |
|
52 // it increments this value with a call to Block(). When it wishes to |
|
53 // re-enable it (if ever), it decrements this value with a call to Unblock(). |
|
54 // Script may not run if this value is non-zero. |
|
55 uint32_t mScriptBlocks; |
|
56 |
|
57 // Whether the docshell allows javascript in this scope. If this scope |
|
58 // doesn't have a docshell, this value is always true. |
|
59 bool mDocShellAllowsScript; |
|
60 |
|
61 // Whether this scope is immune to user-defined or addon-defined script |
|
62 // policy. |
|
63 bool mImmuneToScriptPolicy; |
|
64 |
|
65 // Whether the new-style domain policy when this compartment was created |
|
66 // forbids script execution. |
|
67 bool mScriptBlockedByPolicy; |
|
68 }; |
|
69 |
|
70 JSObject * |
|
71 TransplantObject(JSContext *cx, JS::HandleObject origobj, JS::HandleObject target); |
|
72 |
|
73 bool IsXBLScope(JSCompartment *compartment); |
|
74 bool IsInXBLScope(JSObject *obj); |
|
75 |
|
76 // Return a raw XBL scope object corresponding to contentScope, which must |
|
77 // be an object whose global is a DOM window. |
|
78 // |
|
79 // The return value is not wrapped into cx->compartment, so be sure to enter |
|
80 // its compartment before doing anything meaningful. |
|
81 // |
|
82 // Also note that XBL scopes are lazily created, so the return-value should be |
|
83 // null-checked unless the caller can ensure that the scope must already |
|
84 // exist. |
|
85 // |
|
86 // This function asserts if |contentScope| is itself in an XBL scope to catch |
|
87 // sloppy consumers. Conversely, GetXBLScopeOrGlobal will handle objects that |
|
88 // are in XBL scope (by just returning the global). |
|
89 JSObject * |
|
90 GetXBLScope(JSContext *cx, JSObject *contentScope); |
|
91 |
|
92 inline JSObject * |
|
93 GetXBLScopeOrGlobal(JSContext *cx, JSObject *obj) { |
|
94 if (IsInXBLScope(obj)) |
|
95 return js::GetGlobalForObjectCrossCompartment(obj); |
|
96 return GetXBLScope(cx, obj); |
|
97 } |
|
98 |
|
99 // Returns whether XBL scopes have been explicitly disabled for code running |
|
100 // in this compartment. See the comment around mAllowXBLScope. |
|
101 bool |
|
102 AllowXBLScope(JSCompartment *c); |
|
103 |
|
104 // Returns whether we will use an XBL scope for this compartment. This is |
|
105 // semantically equivalent to comparing global != GetXBLScope(global), but it |
|
106 // does not have the side-effect of eagerly creating the XBL scope if it does |
|
107 // not already exist. |
|
108 bool |
|
109 UseXBLScope(JSCompartment *c); |
|
110 |
|
111 bool |
|
112 IsSandboxPrototypeProxy(JSObject *obj); |
|
113 |
|
114 bool |
|
115 IsReflector(JSObject *obj); |
|
116 |
|
117 bool |
|
118 IsXrayWrapper(JSObject *obj); |
|
119 |
|
120 // If this function was created for a given XrayWrapper, returns the global of |
|
121 // the Xrayed object. Otherwise, returns the global of the function. |
|
122 // |
|
123 // To emphasize the obvious: the return value here is not necessarily same- |
|
124 // compartment with the argument. |
|
125 JSObject * |
|
126 XrayAwareCalleeGlobal(JSObject *fun); |
|
127 |
|
128 void |
|
129 TraceXPCGlobal(JSTracer *trc, JSObject *obj); |
|
130 |
|
131 } /* namespace xpc */ |
|
132 |
|
133 namespace JS { |
|
134 |
|
135 struct RuntimeStats; |
|
136 |
|
137 } |
|
138 |
|
139 #define XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(n) \ |
|
140 JSCLASS_DOM_GLOBAL | JSCLASS_HAS_PRIVATE | \ |
|
141 JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_IMPLEMENTS_BARRIERS | \ |
|
142 JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS + n) |
|
143 |
|
144 #define XPCONNECT_GLOBAL_EXTRA_SLOT_OFFSET (JSCLASS_GLOBAL_SLOT_COUNT + DOM_GLOBAL_SLOTS) |
|
145 |
|
146 #define XPCONNECT_GLOBAL_FLAGS XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(0) |
|
147 |
|
148 inline JSObject* |
|
149 xpc_FastGetCachedWrapper(JSContext *cx, nsWrapperCache *cache, JS::MutableHandleValue vp) |
|
150 { |
|
151 if (cache) { |
|
152 JSObject* wrapper = cache->GetWrapper(); |
|
153 if (wrapper && |
|
154 js::GetObjectCompartment(wrapper) == js::GetContextCompartment(cx)) |
|
155 { |
|
156 vp.setObject(*wrapper); |
|
157 return wrapper; |
|
158 } |
|
159 } |
|
160 |
|
161 return nullptr; |
|
162 } |
|
163 |
|
164 // The JS GC marks objects gray that are held alive directly or |
|
165 // indirectly by an XPConnect root. The cycle collector explores only |
|
166 // this subset of the JS heap. |
|
167 inline bool |
|
168 xpc_IsGrayGCThing(void *thing) |
|
169 { |
|
170 return JS::GCThingIsMarkedGray(thing); |
|
171 } |
|
172 |
|
173 // The cycle collector only cares about some kinds of GCthings that are |
|
174 // reachable from an XPConnect root. Implemented in nsXPConnect.cpp. |
|
175 extern bool |
|
176 xpc_GCThingIsGrayCCThing(void *thing); |
|
177 |
|
178 inline JSScript * |
|
179 xpc_UnmarkGrayScript(JSScript *script) |
|
180 { |
|
181 if (script) |
|
182 JS::ExposeGCThingToActiveJS(script, JSTRACE_SCRIPT); |
|
183 |
|
184 return script; |
|
185 } |
|
186 |
|
187 // If aVariant is an XPCVariant, this marks the object to be in aGeneration. |
|
188 // This also unmarks the gray JSObject. |
|
189 extern void |
|
190 xpc_MarkInCCGeneration(nsISupports* aVariant, uint32_t aGeneration); |
|
191 |
|
192 // If aWrappedJS is a JS wrapper, unmark its JSObject. |
|
193 extern void |
|
194 xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS); |
|
195 |
|
196 extern void |
|
197 xpc_UnmarkSkippableJSHolders(); |
|
198 |
|
199 // No JS can be on the stack when this is called. Probably only useful from |
|
200 // xpcshell. |
|
201 void |
|
202 xpc_ActivateDebugMode(); |
|
203 |
|
204 // readable string conversions, static methods and members only |
|
205 class XPCStringConvert |
|
206 { |
|
207 // One-slot cache, because it turns out it's common for web pages to |
|
208 // get the same string a few times in a row. We get about a 40% cache |
|
209 // hit rate on this cache last it was measured. We'd get about 70% |
|
210 // hit rate with a hashtable with removal on finalization, but that |
|
211 // would take a lot more machinery. |
|
212 struct ZoneStringCache |
|
213 { |
|
214 nsStringBuffer* mBuffer; |
|
215 JSString* mString; |
|
216 }; |
|
217 |
|
218 public: |
|
219 |
|
220 // If the string shares the readable's buffer, that buffer will |
|
221 // get assigned to *sharedBuffer. Otherwise null will be |
|
222 // assigned. |
|
223 static bool ReadableToJSVal(JSContext *cx, const nsAString &readable, |
|
224 nsStringBuffer** sharedBuffer, |
|
225 JS::MutableHandleValue vp); |
|
226 |
|
227 // Convert the given stringbuffer/length pair to a jsval |
|
228 static MOZ_ALWAYS_INLINE bool |
|
229 StringBufferToJSVal(JSContext* cx, nsStringBuffer* buf, uint32_t length, |
|
230 JS::MutableHandleValue rval, bool* sharedBuffer) |
|
231 { |
|
232 JS::Zone *zone = js::GetContextZone(cx); |
|
233 ZoneStringCache *cache = static_cast<ZoneStringCache*>(JS_GetZoneUserData(zone)); |
|
234 if (cache && buf == cache->mBuffer) { |
|
235 MOZ_ASSERT(JS::GetGCThingZone(cache->mString) == zone); |
|
236 JS::MarkStringAsLive(zone, cache->mString); |
|
237 rval.setString(cache->mString); |
|
238 *sharedBuffer = false; |
|
239 return true; |
|
240 } |
|
241 |
|
242 JSString *str = JS_NewExternalString(cx, |
|
243 static_cast<jschar*>(buf->Data()), |
|
244 length, &sDOMStringFinalizer); |
|
245 if (!str) { |
|
246 return false; |
|
247 } |
|
248 rval.setString(str); |
|
249 if (!cache) { |
|
250 cache = new ZoneStringCache(); |
|
251 JS_SetZoneUserData(zone, cache); |
|
252 } |
|
253 cache->mBuffer = buf; |
|
254 cache->mString = str; |
|
255 *sharedBuffer = true; |
|
256 return true; |
|
257 } |
|
258 |
|
259 static void FreeZoneCache(JS::Zone *zone); |
|
260 static void ClearZoneCache(JS::Zone *zone); |
|
261 |
|
262 static MOZ_ALWAYS_INLINE bool IsLiteral(JSString *str) |
|
263 { |
|
264 return JS_IsExternalString(str) && |
|
265 JS_GetExternalStringFinalizer(str) == &sLiteralFinalizer; |
|
266 } |
|
267 |
|
268 static MOZ_ALWAYS_INLINE bool IsDOMString(JSString *str) |
|
269 { |
|
270 return JS_IsExternalString(str) && |
|
271 JS_GetExternalStringFinalizer(str) == &sDOMStringFinalizer; |
|
272 } |
|
273 |
|
274 private: |
|
275 static const JSStringFinalizer sLiteralFinalizer, sDOMStringFinalizer; |
|
276 |
|
277 static void FinalizeLiteral(const JSStringFinalizer *fin, jschar *chars); |
|
278 |
|
279 static void FinalizeDOMString(const JSStringFinalizer *fin, jschar *chars); |
|
280 |
|
281 XPCStringConvert(); // not implemented |
|
282 }; |
|
283 |
|
284 namespace xpc { |
|
285 |
|
286 // If these functions return false, then an exception will be set on cx. |
|
287 bool Base64Encode(JSContext *cx, JS::HandleValue val, JS::MutableHandleValue out); |
|
288 bool Base64Decode(JSContext *cx, JS::HandleValue val, JS::MutableHandleValue out); |
|
289 |
|
290 /** |
|
291 * Convert an nsString to jsval, returning true on success. |
|
292 * Note, the ownership of the string buffer may be moved from str to rval. |
|
293 * If that happens, str will point to an empty string after this call. |
|
294 */ |
|
295 bool NonVoidStringToJsval(JSContext *cx, nsAString &str, JS::MutableHandleValue rval); |
|
296 inline bool StringToJsval(JSContext *cx, nsAString &str, JS::MutableHandleValue rval) |
|
297 { |
|
298 // From the T_DOMSTRING case in XPCConvert::NativeData2JS. |
|
299 if (str.IsVoid()) { |
|
300 rval.setNull(); |
|
301 return true; |
|
302 } |
|
303 return NonVoidStringToJsval(cx, str, rval); |
|
304 } |
|
305 |
|
306 inline bool |
|
307 NonVoidStringToJsval(JSContext* cx, const nsAString& str, JS::MutableHandleValue rval) |
|
308 { |
|
309 nsString mutableCopy(str); |
|
310 return NonVoidStringToJsval(cx, mutableCopy, rval); |
|
311 } |
|
312 |
|
313 inline bool |
|
314 StringToJsval(JSContext* cx, const nsAString& str, JS::MutableHandleValue rval) |
|
315 { |
|
316 nsString mutableCopy(str); |
|
317 return StringToJsval(cx, mutableCopy, rval); |
|
318 } |
|
319 |
|
320 /** |
|
321 * As above, but for mozilla::dom::DOMString. |
|
322 */ |
|
323 MOZ_ALWAYS_INLINE |
|
324 bool NonVoidStringToJsval(JSContext* cx, mozilla::dom::DOMString& str, |
|
325 JS::MutableHandleValue rval) |
|
326 { |
|
327 if (!str.HasStringBuffer()) { |
|
328 // It's an actual XPCOM string |
|
329 return NonVoidStringToJsval(cx, str.AsAString(), rval); |
|
330 } |
|
331 |
|
332 uint32_t length = str.StringBufferLength(); |
|
333 if (length == 0) { |
|
334 rval.set(JS_GetEmptyStringValue(cx)); |
|
335 return true; |
|
336 } |
|
337 |
|
338 nsStringBuffer* buf = str.StringBuffer(); |
|
339 bool shared; |
|
340 if (!XPCStringConvert::StringBufferToJSVal(cx, buf, length, rval, |
|
341 &shared)) { |
|
342 return false; |
|
343 } |
|
344 if (shared) { |
|
345 // JS now needs to hold a reference to the buffer |
|
346 buf->AddRef(); |
|
347 } |
|
348 return true; |
|
349 } |
|
350 |
|
351 MOZ_ALWAYS_INLINE |
|
352 bool StringToJsval(JSContext* cx, mozilla::dom::DOMString& str, |
|
353 JS::MutableHandleValue rval) |
|
354 { |
|
355 if (str.IsNull()) { |
|
356 rval.setNull(); |
|
357 return true; |
|
358 } |
|
359 return NonVoidStringToJsval(cx, str, rval); |
|
360 } |
|
361 |
|
362 nsIPrincipal *GetCompartmentPrincipal(JSCompartment *compartment); |
|
363 |
|
364 void SetLocationForGlobal(JSObject *global, const nsACString& location); |
|
365 void SetLocationForGlobal(JSObject *global, nsIURI *locationURI); |
|
366 |
|
367 // ReportJSRuntimeExplicitTreeStats will expect this in the |extra| member |
|
368 // of JS::ZoneStats. |
|
369 class ZoneStatsExtras { |
|
370 public: |
|
371 ZoneStatsExtras() |
|
372 {} |
|
373 |
|
374 nsAutoCString pathPrefix; |
|
375 |
|
376 private: |
|
377 ZoneStatsExtras(const ZoneStatsExtras &other) MOZ_DELETE; |
|
378 ZoneStatsExtras& operator=(const ZoneStatsExtras &other) MOZ_DELETE; |
|
379 }; |
|
380 |
|
381 // ReportJSRuntimeExplicitTreeStats will expect this in the |extra| member |
|
382 // of JS::CompartmentStats. |
|
383 class CompartmentStatsExtras { |
|
384 public: |
|
385 CompartmentStatsExtras() |
|
386 {} |
|
387 |
|
388 nsAutoCString jsPathPrefix; |
|
389 nsAutoCString domPathPrefix; |
|
390 nsCOMPtr<nsIURI> location; |
|
391 |
|
392 private: |
|
393 CompartmentStatsExtras(const CompartmentStatsExtras &other) MOZ_DELETE; |
|
394 CompartmentStatsExtras& operator=(const CompartmentStatsExtras &other) MOZ_DELETE; |
|
395 }; |
|
396 |
|
397 // This reports all the stats in |rtStats| that belong in the "explicit" tree, |
|
398 // (which isn't all of them). |
|
399 // @see ZoneStatsExtras |
|
400 // @see CompartmentStatsExtras |
|
401 nsresult |
|
402 ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats, |
|
403 const nsACString &rtPath, |
|
404 nsIMemoryReporterCallback *cb, |
|
405 nsISupports *closure, size_t *rtTotal = nullptr); |
|
406 |
|
407 /** |
|
408 * Throws an exception on cx and returns false. |
|
409 */ |
|
410 bool |
|
411 Throw(JSContext *cx, nsresult rv); |
|
412 |
|
413 /** |
|
414 * Every global should hold a native that implements the nsIGlobalObject interface. |
|
415 */ |
|
416 nsIGlobalObject * |
|
417 GetNativeForGlobal(JSObject *global); |
|
418 |
|
419 /** |
|
420 * In some cases a native object does not really belong to any compartment (XBL, |
|
421 * document created from by XHR of a worker, etc.). But when for some reason we |
|
422 * have to wrap these natives (because of an event for example) instead of just |
|
423 * wrapping them into some random compartment we find on the context stack (like |
|
424 * we did previously) a default compartment is used. This function returns that |
|
425 * compartment's global. It is a singleton on the runtime. |
|
426 * If you find yourself wanting to use this compartment, you're probably doing |
|
427 * something wrong. Callers MUST consult with the XPConnect module owner before |
|
428 * using this compartment. If you don't, bholley will hunt you down. |
|
429 */ |
|
430 JSObject * |
|
431 GetJunkScope(); |
|
432 |
|
433 /** |
|
434 * Returns the native global of the junk scope. See comment of GetJunkScope |
|
435 * about the conditions of using it. |
|
436 */ |
|
437 nsIGlobalObject * |
|
438 GetJunkScopeGlobal(); |
|
439 |
|
440 /** |
|
441 * Shared compilation scope for XUL prototype documents and XBL |
|
442 * precompilation. This compartment has a null principal. No code may run, and |
|
443 * it is invisible to the debugger. |
|
444 */ |
|
445 JSObject * |
|
446 GetCompilationScope(); |
|
447 |
|
448 /** |
|
449 * If |aObj| is a window, returns the associated nsGlobalWindow. |
|
450 * Otherwise, returns null. |
|
451 */ |
|
452 nsGlobalWindow* |
|
453 WindowOrNull(JSObject *aObj); |
|
454 |
|
455 /* |
|
456 * Returns the dummy global associated with the SafeJSContext. Callers MUST |
|
457 * consult with the XPConnect module owner before using this function. |
|
458 */ |
|
459 JSObject * |
|
460 GetSafeJSContextGlobal(); |
|
461 |
|
462 /** |
|
463 * If |aObj| has a window for a global, returns the associated nsGlobalWindow. |
|
464 * Otherwise, returns null. |
|
465 */ |
|
466 nsGlobalWindow* |
|
467 WindowGlobalOrNull(JSObject *aObj); |
|
468 |
|
469 // Error reporter used when there is no associated DOM window on to which to |
|
470 // report errors and warnings. |
|
471 void |
|
472 SystemErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep); |
|
473 |
|
474 void |
|
475 SimulateActivityCallback(bool aActive); |
|
476 |
|
477 void |
|
478 RecordAdoptedNode(JSCompartment *c); |
|
479 |
|
480 void |
|
481 RecordDonatedNode(JSCompartment *c); |
|
482 |
|
483 // This function may be used off-main-thread, in which case it is benignly |
|
484 // racey. |
|
485 bool |
|
486 ShouldDiscardSystemSource(); |
|
487 |
|
488 } // namespace xpc |
|
489 |
|
490 namespace mozilla { |
|
491 namespace dom { |
|
492 |
|
493 typedef JSObject* |
|
494 (*DefineInterface)(JSContext *cx, JS::Handle<JSObject*> global, |
|
495 JS::Handle<jsid> id, bool defineOnGlobal); |
|
496 |
|
497 typedef JSObject* |
|
498 (*ConstructNavigatorProperty)(JSContext *cx, JS::Handle<JSObject*> naviObj); |
|
499 |
|
500 // Check whether a constructor should be enabled for the given object. |
|
501 // Note that the object should NOT be an Xray, since Xrays will end up |
|
502 // defining constructors on the underlying object. |
|
503 // This is a typedef for the function type itself, not the function |
|
504 // pointer, so it's more obvious that pointers to a ConstructorEnabled |
|
505 // can be null. |
|
506 typedef bool |
|
507 (ConstructorEnabled)(JSContext* cx, JS::Handle<JSObject*> obj); |
|
508 |
|
509 void |
|
510 Register(nsScriptNameSpaceManager* aNameSpaceManager); |
|
511 |
|
512 /** |
|
513 * A test for whether WebIDL methods that should only be visible to |
|
514 * chrome or XBL scopes should be exposed. |
|
515 */ |
|
516 bool IsChromeOrXBL(JSContext* cx, JSObject* /* unused */); |
|
517 |
|
518 } // namespace dom |
|
519 } // namespace mozilla |
|
520 |
|
521 #endif |