js/xpconnect/src/xpcprivate.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:07916965e467
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 /*
8 * XPConnect allows JS code to manipulate C++ object and C++ code to manipulate
9 * JS objects. JS manipulation of C++ objects tends to be significantly more
10 * complex. This comment explains how it is orchestrated by XPConnect.
11 *
12 * For each C++ object to be manipulated in JS, there is a corresponding JS
13 * object. This is called the "flattened JS object". By default, there is an
14 * additional C++ object involved of type XPCWrappedNative. The XPCWrappedNative
15 * holds pointers to the C++ object and the flat JS object.
16 *
17 * All XPCWrappedNative objects belong to an XPCWrappedNativeScope. These scopes
18 * are essentially in 1:1 correspondence with JS global objects. The
19 * XPCWrappedNativeScope has a pointer to the JS global object. The parent of a
20 * flattened JS object is, by default, the global JS object corresponding to the
21 * wrapper's XPCWrappedNativeScope (the exception to this rule is when a
22 * PreCreate hook asks for a different parent; see nsIXPCScriptable below).
23 *
24 * Some C++ objects (notably DOM objects) have information associated with them
25 * that lists the interfaces implemented by these objects. A C++ object exposes
26 * this information by implementing nsIClassInfo. If a C++ object implements
27 * nsIClassInfo, then JS code can call its methods without needing to use
28 * QueryInterface first. Typically, all instances of a C++ class share the same
29 * nsIClassInfo instance. (That is, obj->QueryInterface(nsIClassInfo) returns
30 * the same result for every obj of a given class.)
31 *
32 * XPConnect tracks nsIClassInfo information in an XPCWrappedNativeProto object.
33 * A given XPCWrappedNativeScope will have one XPCWrappedNativeProto for each
34 * nsIClassInfo instance being used. The XPCWrappedNativeProto has an associated
35 * JS object, which is used as the prototype of all flattened JS objects created
36 * for C++ objects with the given nsIClassInfo.
37 *
38 * Each XPCWrappedNativeProto has a pointer to its XPCWrappedNativeScope. If an
39 * XPCWrappedNative wraps a C++ object with class info, then it points to its
40 * XPCWrappedNativeProto. Otherwise it points to its XPCWrappedNativeScope. (The
41 * pointers are smooshed together in a tagged union.) Either way it can reach
42 * its scope.
43 *
44 * An XPCWrappedNativeProto keeps track of the set of interfaces implemented by
45 * the C++ object in an XPCNativeSet. (The list of interfaces is obtained by
46 * calling a method on the nsIClassInfo.) An XPCNativeSet is a collection of
47 * XPCNativeInterfaces. Each interface stores the list of members, which can be
48 * methods, constants, getters, or setters.
49 *
50 * An XPCWrappedNative also points to an XPCNativeSet. Initially this starts out
51 * the same as the XPCWrappedNativeProto's set. If there is no proto, it starts
52 * out as a singleton set containing nsISupports. If JS code QI's new interfaces
53 * outside of the existing set, the set will grow. All QueryInterface results
54 * are cached in XPCWrappedNativeTearOff objects, which are linked off of the
55 * XPCWrappedNative.
56 *
57 * Besides having class info, a C++ object may be "scriptable" (i.e., implement
58 * nsIXPCScriptable). This allows it to implement a more DOM-like interface,
59 * besides just exposing XPCOM methods and constants. An nsIXPCScriptable
60 * instance has hooks that correspond to all the normal JSClass hooks. Each
61 * nsIXPCScriptable instance is mirrored by an XPCNativeScriptableInfo in
62 * XPConnect. These can have pointers from XPCWrappedNativeProto and
63 * XPCWrappedNative (since C++ objects can have scriptable info without having
64 * class info).
65 *
66 * Most data in an XPCNativeScriptableInfo is shared between instances. The
67 * shared data is stored in an XPCNativeScriptableShared object. This type is
68 * important because it holds the JSClass of the flattened JS objects with the
69 * given scriptable info.
70 */
71
72 /* All the XPConnect private declarations - only include locally. */
73
74 #ifndef xpcprivate_h___
75 #define xpcprivate_h___
76
77 #include "mozilla/Alignment.h"
78 #include "mozilla/Assertions.h"
79 #include "mozilla/Attributes.h"
80 #include "mozilla/CycleCollectedJSRuntime.h"
81 #include "mozilla/GuardObjects.h"
82 #include "mozilla/Maybe.h"
83 #include "mozilla/MemoryReporting.h"
84 #include "mozilla/TimeStamp.h"
85
86 #include <math.h>
87 #include <stdint.h>
88 #include <stdlib.h>
89 #include <string.h>
90
91 #include "xpcpublic.h"
92 #include "js/TracingAPI.h"
93 #include "js/WeakMapPtr.h"
94 #include "pldhash.h"
95 #include "nscore.h"
96 #include "nsXPCOM.h"
97 #include "nsAutoPtr.h"
98 #include "nsCycleCollectionParticipant.h"
99 #include "nsDebug.h"
100 #include "nsISupports.h"
101 #include "nsIServiceManager.h"
102 #include "nsIClassInfoImpl.h"
103 #include "nsIComponentManager.h"
104 #include "nsIComponentRegistrar.h"
105 #include "nsISupportsPrimitives.h"
106 #include "nsMemory.h"
107 #include "nsIXPConnect.h"
108 #include "nsIInterfaceInfo.h"
109 #include "nsIXPCScriptable.h"
110 #include "nsIXPCSecurityManager.h"
111 #include "nsIJSRuntimeService.h"
112 #include "nsWeakReference.h"
113 #include "nsCOMPtr.h"
114 #include "nsXPTCUtils.h"
115 #include "xptinfo.h"
116 #include "XPCForwards.h"
117 #include "XPCLog.h"
118 #include "xpccomponents.h"
119 #include "xpcexception.h"
120 #include "xpcjsid.h"
121 #include "prenv.h"
122 #include "prclist.h"
123 #include "prcvar.h"
124 #include "nsString.h"
125 #include "nsReadableUtils.h"
126 #include "nsXPIDLString.h"
127 #include "nsAutoJSValHolder.h"
128
129 #include "MainThreadUtils.h"
130
131 #include "nsIConsoleService.h"
132 #include "nsIScriptError.h"
133 #include "nsIException.h"
134
135 #include "nsVariant.h"
136 #include "nsIPropertyBag.h"
137 #include "nsIProperty.h"
138 #include "nsCOMArray.h"
139 #include "nsTArray.h"
140 #include "nsBaseHashtable.h"
141 #include "nsHashKeys.h"
142 #include "nsWrapperCache.h"
143 #include "nsStringBuffer.h"
144 #include "nsDataHashtable.h"
145 #include "nsDeque.h"
146
147 #include "nsIScriptSecurityManager.h"
148 #include "nsNetUtil.h"
149
150 #include "nsIPrincipal.h"
151 #include "nsJSPrincipals.h"
152 #include "nsIScriptObjectPrincipal.h"
153 #include "xpcObjectHelper.h"
154 #include "nsIThreadInternal.h"
155
156 #include "SandboxPrivate.h"
157 #include "BackstagePass.h"
158 #include "nsCxPusher.h"
159 #include "nsAXPCNativeCallContext.h"
160
161 #ifdef XP_WIN
162 // Nasty MS defines
163 #ifdef GetClassInfo
164 #undef GetClassInfo
165 #endif
166 #ifdef GetClassName
167 #undef GetClassName
168 #endif
169 #endif /* XP_WIN */
170
171 #include "nsINode.h"
172
173 /***************************************************************************/
174 // default initial sizes for maps (hashtables)
175
176 #define XPC_CONTEXT_MAP_SIZE 16
177 #define XPC_JS_MAP_SIZE 64
178 #define XPC_JS_CLASS_MAP_SIZE 64
179
180 #define XPC_NATIVE_MAP_SIZE 64
181 #define XPC_NATIVE_PROTO_MAP_SIZE 16
182 #define XPC_DYING_NATIVE_PROTO_MAP_SIZE 16
183 #define XPC_DETACHED_NATIVE_PROTO_MAP_SIZE 32
184 #define XPC_NATIVE_INTERFACE_MAP_SIZE 64
185 #define XPC_NATIVE_SET_MAP_SIZE 64
186 #define XPC_NATIVE_JSCLASS_MAP_SIZE 32
187 #define XPC_THIS_TRANSLATOR_MAP_SIZE 8
188 #define XPC_NATIVE_WRAPPER_MAP_SIZE 16
189 #define XPC_WRAPPER_MAP_SIZE 16
190
191 /***************************************************************************/
192 // data declarations...
193 extern const char XPC_CONTEXT_STACK_CONTRACTID[];
194 extern const char XPC_RUNTIME_CONTRACTID[];
195 extern const char XPC_EXCEPTION_CONTRACTID[];
196 extern const char XPC_CONSOLE_CONTRACTID[];
197 extern const char XPC_SCRIPT_ERROR_CONTRACTID[];
198 extern const char XPC_ID_CONTRACTID[];
199 extern const char XPC_XPCONNECT_CONTRACTID[];
200
201 /***************************************************************************/
202 // Useful macros...
203
204 #define XPC_STRING_GETTER_BODY(dest, src) \
205 NS_ENSURE_ARG_POINTER(dest); \
206 char* result; \
207 if (src) \
208 result = (char*) nsMemory::Clone(src, \
209 sizeof(char)*(strlen(src)+1)); \
210 else \
211 result = nullptr; \
212 *dest = result; \
213 return (result || !src) ? NS_OK : NS_ERROR_OUT_OF_MEMORY
214
215
216 #define WRAPPER_SLOTS (JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS )
217
218 #define INVALID_OBJECT ((JSObject *)1)
219
220 // If IS_WN_CLASS for the JSClass of an object is true, the object is a
221 // wrappednative wrapper, holding the XPCWrappedNative in its private slot.
222 static inline bool IS_WN_CLASS(const js::Class* clazz)
223 {
224 return clazz->ext.isWrappedNative;
225 }
226
227 static inline bool IS_WN_REFLECTOR(JSObject *obj)
228 {
229 return IS_WN_CLASS(js::GetObjectClass(obj));
230 }
231
232 /***************************************************************************
233 ****************************************************************************
234 *
235 * Core runtime and context classes...
236 *
237 ****************************************************************************
238 ***************************************************************************/
239
240 // We have a general rule internally that getters that return addref'd interface
241 // pointer generally do so using an 'out' parm. When interface pointers are
242 // returned as function call result values they are not addref'd. Exceptions
243 // to this rule are noted explicitly.
244
245 inline bool
246 AddToCCKind(JSGCTraceKind kind)
247 {
248 return kind == JSTRACE_OBJECT || kind == JSTRACE_SCRIPT;
249 }
250
251 class nsXPConnect : public nsIXPConnect,
252 public nsIThreadObserver,
253 public nsSupportsWeakReference,
254 public nsIJSRuntimeService
255 {
256 public:
257 // all the interface method declarations...
258 NS_DECL_ISUPPORTS
259 NS_DECL_NSIXPCONNECT
260 NS_DECL_NSITHREADOBSERVER
261 NS_DECL_NSIJSRUNTIMESERVICE
262
263 // non-interface implementation
264 public:
265 // These get non-addref'd pointers
266 static nsXPConnect* XPConnect()
267 {
268 // Do a release-mode assert that we're not doing anything significant in
269 // XPConnect off the main thread. If you're an extension developer hitting
270 // this, you need to change your code. See bug 716167.
271 if (!MOZ_LIKELY(NS_IsMainThread()))
272 MOZ_CRASH();
273
274 return gSelf;
275 }
276
277 static XPCJSRuntime* GetRuntimeInstance();
278 XPCJSRuntime* GetRuntime() {return mRuntime;}
279
280 static bool IsISupportsDescendant(nsIInterfaceInfo* info);
281
282 nsIXPCSecurityManager* GetDefaultSecurityManager() const
283 {
284 // mDefaultSecurityManager is main-thread only.
285 if (!NS_IsMainThread()) {
286 return nullptr;
287 }
288 return mDefaultSecurityManager;
289 }
290
291 // This returns an AddRef'd pointer. It does not do this with an 'out' param
292 // only because this form is required by the generic module macro:
293 // NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR
294 static nsXPConnect* GetSingleton();
295
296 // Called by module code in dll startup
297 static void InitStatics();
298 // Called by module code on dll shutdown.
299 static void ReleaseXPConnectSingleton();
300
301 virtual ~nsXPConnect();
302
303 bool IsShuttingDown() const {return mShuttingDown;}
304
305 nsresult GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info);
306 nsresult GetInfoForName(const char * name, nsIInterfaceInfo** info);
307
308 virtual nsIPrincipal* GetPrincipal(JSObject* obj,
309 bool allowShortCircuit) const;
310
311 void RecordTraversal(void *p, nsISupports *s);
312 virtual char* DebugPrintJSStack(bool showArgs,
313 bool showLocals,
314 bool showThisProps);
315
316
317 static bool ReportAllJSExceptions()
318 {
319 return gReportAllJSExceptions > 0;
320 }
321
322 static void CheckForDebugMode(JSRuntime *rt);
323
324 protected:
325 nsXPConnect();
326
327 private:
328 // Singleton instance
329 static nsXPConnect* gSelf;
330 static bool gOnceAliveNowDead;
331
332 XPCJSRuntime* mRuntime;
333 nsRefPtr<nsIXPCSecurityManager> mDefaultSecurityManager;
334 bool mShuttingDown;
335
336 // nsIThreadInternal doesn't remember which observers it called
337 // OnProcessNextEvent on when it gets around to calling AfterProcessNextEvent.
338 // So if XPConnect gets initialized mid-event (which can happen), we'll get
339 // an 'after' notification without getting an 'on' notification. If we don't
340 // watch out for this, we'll do an unmatched |pop| on the context stack.
341 uint16_t mEventDepth;
342
343 static uint32_t gReportAllJSExceptions;
344
345 public:
346 static nsIScriptSecurityManager *gScriptSecurityManager;
347 };
348
349 /***************************************************************************/
350
351 class XPCRootSetElem
352 {
353 public:
354 XPCRootSetElem()
355 {
356 #ifdef DEBUG
357 mNext = nullptr;
358 mSelfp = nullptr;
359 #endif
360 }
361
362 ~XPCRootSetElem()
363 {
364 MOZ_ASSERT(!mNext, "Must be unlinked");
365 MOZ_ASSERT(!mSelfp, "Must be unlinked");
366 }
367
368 inline XPCRootSetElem* GetNextRoot() { return mNext; }
369 void AddToRootSet(XPCRootSetElem **listHead);
370 void RemoveFromRootSet();
371
372 private:
373 XPCRootSetElem *mNext;
374 XPCRootSetElem **mSelfp;
375 };
376
377 /***************************************************************************/
378
379 // In the current xpconnect system there can only be one XPCJSRuntime.
380 // So, xpconnect can only be used on one JSRuntime within the process.
381
382 class XPCJSContextStack;
383 class WatchdogManager;
384
385 enum WatchdogTimestampCategory
386 {
387 TimestampRuntimeStateChange = 0,
388 TimestampWatchdogWakeup,
389 TimestampWatchdogHibernateStart,
390 TimestampWatchdogHibernateStop,
391 TimestampCount
392 };
393
394 class AsyncFreeSnowWhite;
395
396 class XPCJSRuntime : public mozilla::CycleCollectedJSRuntime
397 {
398 public:
399 static XPCJSRuntime* newXPCJSRuntime(nsXPConnect* aXPConnect);
400 static XPCJSRuntime* Get() { return nsXPConnect::XPConnect()->GetRuntime(); }
401
402 XPCJSContextStack* GetJSContextStack() {return mJSContextStack;}
403 void DestroyJSContextStack();
404
405 XPCCallContext* GetCallContext() const {return mCallContext;}
406 XPCCallContext* SetCallContext(XPCCallContext* ccx)
407 {XPCCallContext* old = mCallContext; mCallContext = ccx; return old;}
408
409 jsid GetResolveName() const {return mResolveName;}
410 jsid SetResolveName(jsid name)
411 {jsid old = mResolveName; mResolveName = name; return old;}
412
413 XPCWrappedNative* GetResolvingWrapper() const {return mResolvingWrapper;}
414 XPCWrappedNative* SetResolvingWrapper(XPCWrappedNative* w)
415 {XPCWrappedNative* old = mResolvingWrapper;
416 mResolvingWrapper = w; return old;}
417
418 JSObject2WrappedJSMap* GetWrappedJSMap() const
419 {return mWrappedJSMap;}
420
421 IID2WrappedJSClassMap* GetWrappedJSClassMap() const
422 {return mWrappedJSClassMap;}
423
424 IID2NativeInterfaceMap* GetIID2NativeInterfaceMap() const
425 {return mIID2NativeInterfaceMap;}
426
427 ClassInfo2NativeSetMap* GetClassInfo2NativeSetMap() const
428 {return mClassInfo2NativeSetMap;}
429
430 NativeSetMap* GetNativeSetMap() const
431 {return mNativeSetMap;}
432
433 IID2ThisTranslatorMap* GetThisTranslatorMap() const
434 {return mThisTranslatorMap;}
435
436 XPCNativeScriptableSharedMap* GetNativeScriptableSharedMap() const
437 {return mNativeScriptableSharedMap;}
438
439 XPCWrappedNativeProtoMap* GetDyingWrappedNativeProtoMap() const
440 {return mDyingWrappedNativeProtoMap;}
441
442 XPCWrappedNativeProtoMap* GetDetachedWrappedNativeProtoMap() const
443 {return mDetachedWrappedNativeProtoMap;}
444
445 bool OnJSContextNew(JSContext* cx);
446
447 virtual bool
448 DescribeCustomObjects(JSObject* aObject, const js::Class* aClasp,
449 char (&aName)[72]) const MOZ_OVERRIDE;
450 virtual bool
451 NoteCustomGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj,
452 nsCycleCollectionTraversalCallback& aCb) const MOZ_OVERRIDE;
453
454 /**
455 * Infrastructure for classes that need to defer part of the finalization
456 * until after the GC has run, for example for objects that we don't want to
457 * destroy during the GC.
458 */
459
460 public:
461 bool GetDoingFinalization() const {return mDoingFinalization;}
462
463 // Mapping of often used strings to jsid atoms that live 'forever'.
464 //
465 // To add a new string: add to this list and to XPCJSRuntime::mStrings
466 // at the top of xpcjsruntime.cpp
467 enum {
468 IDX_CONSTRUCTOR = 0 ,
469 IDX_TO_STRING ,
470 IDX_TO_SOURCE ,
471 IDX_LAST_RESULT ,
472 IDX_RETURN_CODE ,
473 IDX_VALUE ,
474 IDX_QUERY_INTERFACE ,
475 IDX_COMPONENTS ,
476 IDX_WRAPPED_JSOBJECT ,
477 IDX_OBJECT ,
478 IDX_FUNCTION ,
479 IDX_PROTOTYPE ,
480 IDX_CREATE_INSTANCE ,
481 IDX_ITEM ,
482 IDX_PROTO ,
483 IDX_ITERATOR ,
484 IDX_EXPOSEDPROPS ,
485 IDX_EVAL ,
486 IDX_CONTROLLERS ,
487 IDX_TOTAL_COUNT // just a count of the above
488 };
489
490 JS::HandleId GetStringID(unsigned index) const
491 {
492 MOZ_ASSERT(index < IDX_TOTAL_COUNT, "index out of range");
493 // fromMarkedLocation() is safe because the string is interned.
494 return JS::HandleId::fromMarkedLocation(&mStrIDs[index]);
495 }
496 JS::HandleValue GetStringJSVal(unsigned index) const
497 {
498 MOZ_ASSERT(index < IDX_TOTAL_COUNT, "index out of range");
499 // fromMarkedLocation() is safe because the string is interned.
500 return JS::HandleValue::fromMarkedLocation(&mStrJSVals[index]);
501 }
502 const char* GetStringName(unsigned index) const
503 {
504 MOZ_ASSERT(index < IDX_TOTAL_COUNT, "index out of range");
505 return mStrings[index];
506 }
507
508 void TraceNativeBlackRoots(JSTracer* trc) MOZ_OVERRIDE;
509 void TraceAdditionalNativeGrayRoots(JSTracer* aTracer) MOZ_OVERRIDE;
510 void TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& cb) MOZ_OVERRIDE;
511 void UnmarkSkippableJSHolders();
512 void PrepareForForgetSkippable() MOZ_OVERRIDE;
513 void BeginCycleCollectionCallback() MOZ_OVERRIDE;
514 void EndCycleCollectionCallback(mozilla::CycleCollectorResults &aResults) MOZ_OVERRIDE;
515 void DispatchDeferredDeletion(bool continuation) MOZ_OVERRIDE;
516
517 void CustomGCCallback(JSGCStatus status) MOZ_OVERRIDE;
518 bool CustomContextCallback(JSContext *cx, unsigned operation) MOZ_OVERRIDE;
519 static void GCSliceCallback(JSRuntime *rt,
520 JS::GCProgress progress,
521 const JS::GCDescription &desc);
522 static void FinalizeCallback(JSFreeOp *fop, JSFinalizeStatus status, bool isCompartmentGC);
523
524 inline void AddVariantRoot(XPCTraceableVariant* variant);
525 inline void AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS);
526 inline void AddObjectHolderRoot(XPCJSObjectHolder* holder);
527
528 static void SuspectWrappedNative(XPCWrappedNative *wrapper,
529 nsCycleCollectionNoteRootCallback &cb);
530
531 void DebugDump(int16_t depth);
532
533 void SystemIsBeingShutDown();
534
535 bool GCIsRunning() const {return mGCIsRunning;}
536
537 ~XPCJSRuntime();
538
539 nsString* NewShortLivedString();
540 void DeleteShortLivedString(nsString *string);
541
542 void AddGCCallback(xpcGCCallback cb);
543 void RemoveGCCallback(xpcGCCallback cb);
544 void AddContextCallback(xpcContextCallback cb);
545 void RemoveContextCallback(xpcContextCallback cb);
546
547 static JSContext* DefaultJSContextCallback(JSRuntime *rt);
548 static void ActivityCallback(void *arg, bool active);
549 static void CTypesActivityCallback(JSContext *cx,
550 js::CTypesActivityType type);
551 static bool InterruptCallback(JSContext *cx);
552 static void OutOfMemoryCallback(JSContext *cx);
553
554 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
555
556 AutoMarkingPtr** GetAutoRootsAdr() {return &mAutoRoots;}
557
558 JSObject* GetJunkScope();
559 JSObject* GetCompilationScope();
560 void DeleteSingletonScopes();
561
562 PRTime GetWatchdogTimestamp(WatchdogTimestampCategory aCategory);
563 void OnAfterProcessNextEvent() { mSlowScriptCheckpoint = mozilla::TimeStamp(); }
564
565 private:
566 XPCJSRuntime(); // no implementation
567 XPCJSRuntime(nsXPConnect* aXPConnect);
568
569 void ReleaseIncrementally(nsTArray<nsISupports *> &array);
570
571 static const char* const mStrings[IDX_TOTAL_COUNT];
572 jsid mStrIDs[IDX_TOTAL_COUNT];
573 jsval mStrJSVals[IDX_TOTAL_COUNT];
574
575 XPCJSContextStack* mJSContextStack;
576 XPCCallContext* mCallContext;
577 AutoMarkingPtr* mAutoRoots;
578 jsid mResolveName;
579 XPCWrappedNative* mResolvingWrapper;
580 JSObject2WrappedJSMap* mWrappedJSMap;
581 IID2WrappedJSClassMap* mWrappedJSClassMap;
582 IID2NativeInterfaceMap* mIID2NativeInterfaceMap;
583 ClassInfo2NativeSetMap* mClassInfo2NativeSetMap;
584 NativeSetMap* mNativeSetMap;
585 IID2ThisTranslatorMap* mThisTranslatorMap;
586 XPCNativeScriptableSharedMap* mNativeScriptableSharedMap;
587 XPCWrappedNativeProtoMap* mDyingWrappedNativeProtoMap;
588 XPCWrappedNativeProtoMap* mDetachedWrappedNativeProtoMap;
589 bool mGCIsRunning;
590 nsTArray<nsXPCWrappedJS*> mWrappedJSToReleaseArray;
591 nsTArray<nsISupports*> mNativesToReleaseArray;
592 bool mDoingFinalization;
593 XPCRootSetElem *mVariantRoots;
594 XPCRootSetElem *mWrappedJSRoots;
595 XPCRootSetElem *mObjectHolderRoots;
596 nsTArray<xpcGCCallback> extraGCCallbacks;
597 nsTArray<xpcContextCallback> extraContextCallbacks;
598 nsRefPtr<WatchdogManager> mWatchdogManager;
599 JS::GCSliceCallback mPrevGCSliceCallback;
600 JS::PersistentRootedObject mJunkScope;
601 JS::PersistentRootedObject mCompilationScope;
602 nsRefPtr<AsyncFreeSnowWhite> mAsyncSnowWhiteFreer;
603
604 mozilla::TimeStamp mSlowScriptCheckpoint;
605
606 #define XPCCCX_STRING_CACHE_SIZE 2
607
608 mozilla::Maybe<nsString> mScratchStrings[XPCCCX_STRING_CACHE_SIZE];
609
610 friend class Watchdog;
611 friend class AutoLockWatchdog;
612 friend class XPCIncrementalReleaseRunnable;
613 };
614
615 /***************************************************************************/
616 /***************************************************************************/
617 // XPCContext is mostly a dumb class to hold JSContext specific data and
618 // maps that let us find wrappers created for the given JSContext.
619
620 // no virtuals
621 class XPCContext
622 {
623 friend class XPCJSRuntime;
624 public:
625 static XPCContext* GetXPCContext(JSContext* aJSContext)
626 {
627 MOZ_ASSERT(JS_GetSecondContextPrivate(aJSContext), "should already have XPCContext");
628 return static_cast<XPCContext *>(JS_GetSecondContextPrivate(aJSContext));
629 }
630
631 XPCJSRuntime* GetRuntime() const {return mRuntime;}
632 JSContext* GetJSContext() const {return mJSContext;}
633
634 enum LangType {LANG_UNKNOWN, LANG_JS, LANG_NATIVE};
635
636 LangType GetCallingLangType() const
637 {
638 return mCallingLangType;
639 }
640 LangType SetCallingLangType(LangType lt)
641 {
642 LangType tmp = mCallingLangType;
643 mCallingLangType = lt;
644 return tmp;
645 }
646 bool CallerTypeIsJavaScript() const
647 {
648 return LANG_JS == mCallingLangType;
649 }
650 bool CallerTypeIsNative() const
651 {
652 return LANG_NATIVE == mCallingLangType;
653 }
654 bool CallerTypeIsKnown() const
655 {
656 return LANG_UNKNOWN != mCallingLangType;
657 }
658
659 nsresult GetException(nsIException** e)
660 {
661 nsCOMPtr<nsIException> rval = mException;
662 rval.forget(e);
663 return NS_OK;
664 }
665 void SetException(nsIException* e)
666 {
667 mException = e;
668 }
669
670 nsresult GetLastResult() {return mLastResult;}
671 void SetLastResult(nsresult rc) {mLastResult = rc;}
672
673 nsresult GetPendingResult() {return mPendingResult;}
674 void SetPendingResult(nsresult rc) {mPendingResult = rc;}
675
676 void DebugDump(int16_t depth);
677 void AddScope(PRCList *scope) { PR_INSERT_AFTER(scope, &mScopes); }
678 void RemoveScope(PRCList *scope) { PR_REMOVE_LINK(scope); }
679
680 void MarkErrorUnreported() { mErrorUnreported = true; }
681 void ClearUnreportedError() { mErrorUnreported = false; }
682 bool WasErrorReported() { return !mErrorUnreported; }
683
684 ~XPCContext();
685
686 private:
687 XPCContext(); // no implementation
688 XPCContext(XPCJSRuntime* aRuntime, JSContext* aJSContext);
689
690 static XPCContext* newXPCContext(XPCJSRuntime* aRuntime,
691 JSContext* aJSContext);
692 private:
693 XPCJSRuntime* mRuntime;
694 JSContext* mJSContext;
695 nsresult mLastResult;
696 nsresult mPendingResult;
697 nsCOMPtr<nsIException> mException;
698 LangType mCallingLangType;
699 bool mErrorUnreported;
700
701 // A linked list of scopes to notify when we are destroyed.
702 PRCList mScopes;
703 };
704
705 /***************************************************************************/
706
707 #define NATIVE_CALLER XPCContext::LANG_NATIVE
708 #define JS_CALLER XPCContext::LANG_JS
709
710 // No virtuals
711 // XPCCallContext is ALWAYS declared as a local variable in some function;
712 // i.e. instance lifetime is always controled by some C++ function returning.
713 //
714 // These things are created frequently in many places. We *intentionally* do
715 // not inialialize all members in order to save on construction overhead.
716 // Some constructor pass more valid params than others. We init what must be
717 // init'd and leave other members undefined. In debug builds the accessors
718 // use a CHECK_STATE macro to track whether or not the object is in a valid
719 // state to answer the question a caller might be asking. As long as this
720 // class is maintained correctly it can do its job without a bunch of added
721 // overhead from useless initializations and non-DEBUG error checking.
722 //
723 // Note that most accessors are inlined.
724
725 class MOZ_STACK_CLASS XPCCallContext : public nsAXPCNativeCallContext
726 {
727 public:
728 NS_IMETHOD GetCallee(nsISupports **aResult);
729 NS_IMETHOD GetCalleeMethodIndex(uint16_t *aResult);
730 NS_IMETHOD GetCalleeWrapper(nsIXPConnectWrappedNative **aResult);
731 NS_IMETHOD GetJSContext(JSContext **aResult);
732 NS_IMETHOD GetArgc(uint32_t *aResult);
733 NS_IMETHOD GetArgvPtr(jsval **aResult);
734 NS_IMETHOD GetCalleeInterface(nsIInterfaceInfo **aResult);
735 NS_IMETHOD GetCalleeClassInfo(nsIClassInfo **aResult);
736 NS_IMETHOD GetPreviousCallContext(nsAXPCNativeCallContext **aResult);
737 NS_IMETHOD GetLanguage(uint16_t *aResult);
738
739 enum {NO_ARGS = (unsigned) -1};
740
741 static JSContext* GetDefaultJSContext();
742
743 XPCCallContext(XPCContext::LangType callerLanguage,
744 JSContext* cx,
745 JS::HandleObject obj = JS::NullPtr(),
746 JS::HandleObject funobj = JS::NullPtr(),
747 JS::HandleId id = JSID_VOIDHANDLE,
748 unsigned argc = NO_ARGS,
749 jsval *argv = nullptr,
750 jsval *rval = nullptr);
751
752 virtual ~XPCCallContext();
753
754 inline bool IsValid() const ;
755
756 inline XPCJSRuntime* GetRuntime() const ;
757 inline XPCContext* GetXPCContext() const ;
758 inline JSContext* GetJSContext() const ;
759 inline bool GetContextPopRequired() const ;
760 inline XPCContext::LangType GetCallerLanguage() const ;
761 inline XPCContext::LangType GetPrevCallerLanguage() const ;
762 inline XPCCallContext* GetPrevCallContext() const ;
763
764 inline JSObject* GetFlattenedJSObject() const ;
765 inline nsISupports* GetIdentityObject() const ;
766 inline XPCWrappedNative* GetWrapper() const ;
767 inline XPCWrappedNativeProto* GetProto() const ;
768
769 inline bool CanGetTearOff() const ;
770 inline XPCWrappedNativeTearOff* GetTearOff() const ;
771
772 inline XPCNativeScriptableInfo* GetScriptableInfo() const ;
773 inline bool CanGetSet() const ;
774 inline XPCNativeSet* GetSet() const ;
775 inline bool CanGetInterface() const ;
776 inline XPCNativeInterface* GetInterface() const ;
777 inline XPCNativeMember* GetMember() const ;
778 inline bool HasInterfaceAndMember() const ;
779 inline jsid GetName() const ;
780 inline bool GetStaticMemberIsLocal() const ;
781 inline unsigned GetArgc() const ;
782 inline jsval* GetArgv() const ;
783 inline jsval* GetRetVal() const ;
784
785 inline uint16_t GetMethodIndex() const ;
786 inline void SetMethodIndex(uint16_t index) ;
787
788 inline jsid GetResolveName() const;
789 inline jsid SetResolveName(JS::HandleId name);
790
791 inline XPCWrappedNative* GetResolvingWrapper() const;
792 inline XPCWrappedNative* SetResolvingWrapper(XPCWrappedNative* w);
793
794 inline void SetRetVal(jsval val);
795
796 void SetName(jsid name);
797 void SetArgsAndResultPtr(unsigned argc, jsval *argv, jsval *rval);
798 void SetCallInfo(XPCNativeInterface* iface, XPCNativeMember* member,
799 bool isSetter);
800
801 nsresult CanCallNow();
802
803 void SystemIsBeingShutDown();
804
805 operator JSContext*() const {return GetJSContext();}
806
807 private:
808
809 // no copy ctor or assignment allowed
810 XPCCallContext(const XPCCallContext& r); // not implemented
811 XPCCallContext& operator= (const XPCCallContext& r); // not implemented
812
813 XPCWrappedNative* UnwrapThisIfAllowed(JS::HandleObject obj, JS::HandleObject fun,
814 unsigned argc);
815
816 private:
817 // posible values for mState
818 enum State {
819 INIT_FAILED,
820 SYSTEM_SHUTDOWN,
821 HAVE_CONTEXT,
822 HAVE_OBJECT,
823 HAVE_NAME,
824 HAVE_ARGS,
825 READY_TO_CALL,
826 CALL_DONE
827 };
828
829 #ifdef DEBUG
830 inline void CHECK_STATE(int s) const {MOZ_ASSERT(mState >= s, "bad state");}
831 #else
832 #define CHECK_STATE(s) ((void)0)
833 #endif
834
835 private:
836 JSAutoRequest mAr;
837 State mState;
838
839 nsRefPtr<nsXPConnect> mXPC;
840
841 XPCContext* mXPCContext;
842 JSContext* mJSContext;
843
844 XPCContext::LangType mCallerLanguage;
845
846 // ctor does not necessarily init the following. BEWARE!
847
848 XPCContext::LangType mPrevCallerLanguage;
849
850 XPCCallContext* mPrevCallContext;
851
852 JS::RootedObject mFlattenedJSObject;
853 XPCWrappedNative* mWrapper;
854 XPCWrappedNativeTearOff* mTearOff;
855
856 XPCNativeScriptableInfo* mScriptableInfo;
857
858 XPCNativeSet* mSet;
859 XPCNativeInterface* mInterface;
860 XPCNativeMember* mMember;
861
862 JS::RootedId mName;
863 bool mStaticMemberIsLocal;
864
865 unsigned mArgc;
866 jsval* mArgv;
867 jsval* mRetVal;
868
869 uint16_t mMethodIndex;
870 };
871
872 /***************************************************************************
873 ****************************************************************************
874 *
875 * Core classes for wrapped native objects for use from JavaScript...
876 *
877 ****************************************************************************
878 ***************************************************************************/
879
880 // These are the various JSClasses and callbacks whose use that required
881 // visibility from more than one .cpp file.
882
883 struct XPCWrappedNativeJSClass;
884 extern const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass;
885 extern const js::Class XPC_WN_NoMods_WithCall_Proto_JSClass;
886 extern const js::Class XPC_WN_NoMods_NoCall_Proto_JSClass;
887 extern const js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass;
888 extern const js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass;
889 extern const js::Class XPC_WN_Tearoff_JSClass;
890 extern const js::Class XPC_WN_NoHelper_Proto_JSClass;
891
892 extern bool
893 XPC_WN_CallMethod(JSContext *cx, unsigned argc, jsval *vp);
894
895 extern bool
896 XPC_WN_GetterSetter(JSContext *cx, unsigned argc, jsval *vp);
897
898 extern bool
899 XPC_WN_JSOp_Enumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp enum_op,
900 JS::MutableHandleValue statep, JS::MutableHandleId idp);
901
902 extern JSObject*
903 XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj);
904
905 // Macros to initialize Object or Function like XPC_WN classes
906 #define XPC_WN_WithCall_ObjectOps \
907 { \
908 nullptr, /* lookupGeneric */ \
909 nullptr, /* lookupProperty */ \
910 nullptr, /* lookupElement */ \
911 nullptr, /* defineGeneric */ \
912 nullptr, /* defineProperty */ \
913 nullptr, /* defineElement */ \
914 nullptr, /* getGeneric */ \
915 nullptr, /* getProperty */ \
916 nullptr, /* getElement */ \
917 nullptr, /* setGeneric */ \
918 nullptr, /* setProperty */ \
919 nullptr, /* setElement */ \
920 nullptr, /* getGenericAttributes */ \
921 nullptr, /* setGenericAttributes */ \
922 nullptr, /* deleteProperty */ \
923 nullptr, /* deleteElement */ \
924 nullptr, nullptr, /* watch/unwatch */ \
925 nullptr, /* slice */ \
926 XPC_WN_JSOp_Enumerate, \
927 XPC_WN_JSOp_ThisObject, \
928 }
929
930 #define XPC_WN_NoCall_ObjectOps \
931 { \
932 nullptr, /* lookupGeneric */ \
933 nullptr, /* lookupProperty */ \
934 nullptr, /* lookupElement */ \
935 nullptr, /* defineGeneric */ \
936 nullptr, /* defineProperty */ \
937 nullptr, /* defineElement */ \
938 nullptr, /* getGeneric */ \
939 nullptr, /* getProperty */ \
940 nullptr, /* getElement */ \
941 nullptr, /* setGeneric */ \
942 nullptr, /* setProperty */ \
943 nullptr, /* setElement */ \
944 nullptr, /* getGenericAttributes */ \
945 nullptr, /* setGenericAttributes */ \
946 nullptr, /* deleteProperty */ \
947 nullptr, /* deleteElement */ \
948 nullptr, nullptr, /* watch/unwatch */ \
949 nullptr, /* slice */ \
950 XPC_WN_JSOp_Enumerate, \
951 XPC_WN_JSOp_ThisObject, \
952 }
953
954 // Maybe this macro should check for class->enumerate ==
955 // XPC_WN_Shared_Proto_Enumerate or something rather than checking for
956 // 4 classes?
957 static inline bool IS_PROTO_CLASS(const js::Class *clazz)
958 {
959 return clazz == &XPC_WN_NoMods_WithCall_Proto_JSClass ||
960 clazz == &XPC_WN_NoMods_NoCall_Proto_JSClass ||
961 clazz == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||
962 clazz == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass;
963 }
964
965 /***************************************************************************/
966 // XPCWrappedNativeScope is one-to-one with a JS global object.
967
968 class nsXPCComponentsBase;
969 class XPCWrappedNativeScope : public PRCList
970 {
971 public:
972
973 static XPCWrappedNativeScope*
974 GetNewOrUsed(JSContext *cx, JS::HandleObject aGlobal);
975
976 XPCJSRuntime*
977 GetRuntime() const {return XPCJSRuntime::Get();}
978
979 Native2WrappedNativeMap*
980 GetWrappedNativeMap() const {return mWrappedNativeMap;}
981
982 ClassInfo2WrappedNativeProtoMap*
983 GetWrappedNativeProtoMap() const {return mWrappedNativeProtoMap;}
984
985 nsXPCComponentsBase*
986 GetComponents() const {return mComponents;}
987
988 // Forces the creation of a privileged |Components| object, even in
989 // content scopes. This will crash if used outside of automation.
990 void
991 ForcePrivilegedComponents();
992
993 bool AttachComponentsObject(JSContext *aCx);
994
995 // Returns the JS object reflection of the Components object.
996 bool
997 GetComponentsJSObject(JS::MutableHandleObject obj);
998
999 JSObject*
1000 GetGlobalJSObject() const {
1001 JS::ExposeObjectToActiveJS(mGlobalJSObject);
1002 return mGlobalJSObject;
1003 }
1004
1005 JSObject*
1006 GetGlobalJSObjectPreserveColor() const {return mGlobalJSObject;}
1007
1008 nsIPrincipal*
1009 GetPrincipal() const {
1010 JSCompartment *c = js::GetObjectCompartment(mGlobalJSObject);
1011 return nsJSPrincipals::get(JS_GetCompartmentPrincipals(c));
1012 }
1013
1014 JSObject*
1015 GetExpandoChain(JS::HandleObject target);
1016
1017 bool
1018 SetExpandoChain(JSContext *cx, JS::HandleObject target, JS::HandleObject chain);
1019
1020 void RemoveWrappedNativeProtos();
1021
1022 static void
1023 SystemIsBeingShutDown();
1024
1025 static void
1026 TraceWrappedNativesInAllScopes(JSTracer* trc, XPCJSRuntime* rt);
1027
1028 void TraceInside(JSTracer *trc) {
1029 MOZ_ASSERT(mGlobalJSObject);
1030 mGlobalJSObject.trace(trc, "XPCWrappedNativeScope::mGlobalJSObject");
1031 if (mXBLScope)
1032 mXBLScope.trace(trc, "XPCWrappedNativeScope::mXBLScope");
1033 if (mXrayExpandos.initialized())
1034 mXrayExpandos.trace(trc);
1035 }
1036
1037 static void
1038 SuspectAllWrappers(XPCJSRuntime* rt, nsCycleCollectionNoteRootCallback &cb);
1039
1040 static void
1041 StartFinalizationPhaseOfGC(JSFreeOp *fop, XPCJSRuntime* rt);
1042
1043 static void
1044 FinishedFinalizationPhaseOfGC();
1045
1046 static void
1047 MarkAllWrappedNativesAndProtos();
1048
1049 #ifdef DEBUG
1050 static void
1051 ASSERT_NoInterfaceSetsAreMarked();
1052 #endif
1053
1054 static void
1055 SweepAllWrappedNativeTearOffs();
1056
1057 static void
1058 DebugDumpAllScopes(int16_t depth);
1059
1060 void
1061 DebugDump(int16_t depth);
1062
1063 struct ScopeSizeInfo {
1064 ScopeSizeInfo(mozilla::MallocSizeOf mallocSizeOf)
1065 : mMallocSizeOf(mallocSizeOf),
1066 mScopeAndMapSize(0),
1067 mProtoAndIfaceCacheSize(0)
1068 {}
1069
1070 mozilla::MallocSizeOf mMallocSizeOf;
1071 size_t mScopeAndMapSize;
1072 size_t mProtoAndIfaceCacheSize;
1073 };
1074
1075 static void
1076 AddSizeOfAllScopesIncludingThis(ScopeSizeInfo* scopeSizeInfo);
1077
1078 void
1079 AddSizeOfIncludingThis(ScopeSizeInfo* scopeSizeInfo);
1080
1081 bool
1082 IsValid() const {return mRuntime != nullptr;}
1083
1084 static bool
1085 IsDyingScope(XPCWrappedNativeScope *scope);
1086
1087 static void InitStatics() { gScopes = nullptr; gDyingScopes = nullptr; }
1088
1089 XPCContext *GetContext() { return mContext; }
1090 void ClearContext() { mContext = nullptr; }
1091
1092 typedef js::HashSet<JSObject *,
1093 js::PointerHasher<JSObject *, 3>,
1094 js::SystemAllocPolicy> DOMExpandoSet;
1095
1096 bool RegisterDOMExpandoObject(JSObject *expando) {
1097 // Expandos are proxy objects, and proxies are always tenured.
1098 JS::AssertGCThingMustBeTenured(expando);
1099 if (!mDOMExpandoSet) {
1100 mDOMExpandoSet = new DOMExpandoSet();
1101 mDOMExpandoSet->init(8);
1102 }
1103 return mDOMExpandoSet->put(expando);
1104 }
1105 void RemoveDOMExpandoObject(JSObject *expando) {
1106 if (mDOMExpandoSet)
1107 mDOMExpandoSet->remove(expando);
1108 }
1109
1110 // Gets the appropriate scope object for XBL in this scope. The context
1111 // must be same-compartment with the global upon entering, and the scope
1112 // object is wrapped into the compartment of the global.
1113 JSObject *EnsureXBLScope(JSContext *cx);
1114
1115 XPCWrappedNativeScope(JSContext *cx, JS::HandleObject aGlobal);
1116
1117 nsAutoPtr<JSObject2JSObjectMap> mWaiverWrapperMap;
1118
1119 bool IsXBLScope() { return mIsXBLScope; }
1120 bool AllowXBLScope();
1121 bool UseXBLScope() { return mUseXBLScope; }
1122
1123 protected:
1124 virtual ~XPCWrappedNativeScope();
1125
1126 static void KillDyingScopes();
1127
1128 XPCWrappedNativeScope(); // not implemented
1129
1130 private:
1131 static XPCWrappedNativeScope* gScopes;
1132 static XPCWrappedNativeScope* gDyingScopes;
1133
1134 XPCJSRuntime* mRuntime;
1135 Native2WrappedNativeMap* mWrappedNativeMap;
1136 ClassInfo2WrappedNativeProtoMap* mWrappedNativeProtoMap;
1137 nsRefPtr<nsXPCComponentsBase> mComponents;
1138 XPCWrappedNativeScope* mNext;
1139 // The JS global object for this scope. If non-null, this will be the
1140 // default parent for the XPCWrappedNatives that have us as the scope,
1141 // unless a PreCreate hook overrides it. Note that this _may_ be null (see
1142 // constructor).
1143 JS::ObjectPtr mGlobalJSObject;
1144
1145 // XBL Scope. This is is a lazily-created sandbox for non-system scopes.
1146 // EnsureXBLScope() decides whether it needs to be created or not.
1147 // This reference is wrapped into the compartment of mGlobalJSObject.
1148 JS::ObjectPtr mXBLScope;
1149
1150 XPCContext* mContext;
1151
1152 nsAutoPtr<DOMExpandoSet> mDOMExpandoSet;
1153
1154 JS::WeakMapPtr<JSObject*, JSObject*> mXrayExpandos;
1155
1156 bool mIsXBLScope;
1157
1158 // For remote XUL domains, we run all XBL in the content scope for compat
1159 // reasons (though we sometimes pref this off for automation). We separately
1160 // track the result of this decision (mAllowXBLScope), from the decision
1161 // of whether to actually _use_ an XBL scope (mUseXBLScope), which depends
1162 // on the type of global and whether the compartment is system principal
1163 // or not.
1164 //
1165 // This distinction is useful primarily because, if true, we know that we
1166 // have no way of distinguishing XBL script from content script for the
1167 // given scope. In these (unsupported) situations, we just always claim to
1168 // be XBL.
1169 bool mAllowXBLScope;
1170 bool mUseXBLScope;
1171 };
1172
1173 /***************************************************************************/
1174 // XPCNativeMember represents a single idl declared method, attribute or
1175 // constant.
1176
1177 // Tight. No virtual methods. Can be bitwise copied (until any resolution done).
1178
1179 class XPCNativeMember
1180 {
1181 public:
1182 static bool GetCallInfo(JSObject* funobj,
1183 XPCNativeInterface** pInterface,
1184 XPCNativeMember** pMember);
1185
1186 jsid GetName() const {return mName;}
1187
1188 uint16_t GetIndex() const {return mIndex;}
1189
1190 bool GetConstantValue(XPCCallContext& ccx, XPCNativeInterface* iface,
1191 jsval* pval)
1192 {MOZ_ASSERT(IsConstant(),
1193 "Only call this if you're sure this is a constant!");
1194 return Resolve(ccx, iface, JS::NullPtr(), pval);}
1195
1196 bool NewFunctionObject(XPCCallContext& ccx, XPCNativeInterface* iface,
1197 JS::HandleObject parent, jsval* pval);
1198
1199 bool IsMethod() const
1200 {return 0 != (mFlags & METHOD);}
1201
1202 bool IsConstant() const
1203 {return 0 != (mFlags & CONSTANT);}
1204
1205 bool IsAttribute() const
1206 {return 0 != (mFlags & GETTER);}
1207
1208 bool IsWritableAttribute() const
1209 {return 0 != (mFlags & SETTER_TOO);}
1210
1211 bool IsReadOnlyAttribute() const
1212 {return IsAttribute() && !IsWritableAttribute();}
1213
1214
1215 void SetName(jsid a) {mName = a;}
1216
1217 void SetMethod(uint16_t index)
1218 {mFlags = METHOD; mIndex = index;}
1219
1220 void SetConstant(uint16_t index)
1221 {mFlags = CONSTANT; mIndex = index;}
1222
1223 void SetReadOnlyAttribute(uint16_t index)
1224 {mFlags = GETTER; mIndex = index;}
1225
1226 void SetWritableAttribute()
1227 {MOZ_ASSERT(mFlags == GETTER,"bad"); mFlags = GETTER | SETTER_TOO;}
1228
1229 /* default ctor - leave random contents */
1230 XPCNativeMember() {MOZ_COUNT_CTOR(XPCNativeMember);}
1231 ~XPCNativeMember() {MOZ_COUNT_DTOR(XPCNativeMember);}
1232
1233 private:
1234 bool Resolve(XPCCallContext& ccx, XPCNativeInterface* iface,
1235 JS::HandleObject parent, jsval *vp);
1236
1237 enum {
1238 METHOD = 0x01,
1239 CONSTANT = 0x02,
1240 GETTER = 0x04,
1241 SETTER_TOO = 0x08
1242 };
1243
1244 private:
1245 // our only data...
1246 jsid mName;
1247 uint16_t mIndex;
1248 uint16_t mFlags;
1249 };
1250
1251 /***************************************************************************/
1252 // XPCNativeInterface represents a single idl declared interface. This is
1253 // primarily the set of XPCNativeMembers.
1254
1255 // Tight. No virtual methods.
1256
1257 class XPCNativeInterface
1258 {
1259 public:
1260 static XPCNativeInterface* GetNewOrUsed(const nsIID* iid);
1261 static XPCNativeInterface* GetNewOrUsed(nsIInterfaceInfo* info);
1262 static XPCNativeInterface* GetNewOrUsed(const char* name);
1263 static XPCNativeInterface* GetISupports();
1264
1265 inline nsIInterfaceInfo* GetInterfaceInfo() const {return mInfo.get();}
1266 inline jsid GetName() const {return mName;}
1267
1268 inline const nsIID* GetIID() const;
1269 inline const char* GetNameString() const;
1270 inline XPCNativeMember* FindMember(jsid name) const;
1271
1272 inline bool HasAncestor(const nsIID* iid) const;
1273
1274 uint16_t GetMemberCount() const {
1275 return mMemberCount;
1276 }
1277 XPCNativeMember* GetMemberAt(uint16_t i) {
1278 MOZ_ASSERT(i < mMemberCount, "bad index");
1279 return &mMembers[i];
1280 }
1281
1282 void DebugDump(int16_t depth);
1283
1284 #define XPC_NATIVE_IFACE_MARK_FLAG ((uint16_t)JS_BIT(15)) // only high bit of 16 is set
1285
1286 void Mark() {
1287 mMarked = 1;
1288 }
1289
1290 void Unmark() {
1291 mMarked = 0;
1292 }
1293
1294 bool IsMarked() const {
1295 return mMarked != 0;
1296 }
1297
1298 // NOP. This is just here to make the AutoMarkingPtr code compile.
1299 inline void TraceJS(JSTracer* trc) {}
1300 inline void AutoTrace(JSTracer* trc) {}
1301
1302 static void DestroyInstance(XPCNativeInterface* inst);
1303
1304 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
1305
1306 protected:
1307 static XPCNativeInterface* NewInstance(nsIInterfaceInfo* aInfo);
1308
1309 XPCNativeInterface(); // not implemented
1310 XPCNativeInterface(nsIInterfaceInfo* aInfo, jsid aName)
1311 : mInfo(aInfo), mName(aName), mMemberCount(0), mMarked(0)
1312 {
1313 MOZ_COUNT_CTOR(XPCNativeInterface);
1314 }
1315 ~XPCNativeInterface() {
1316 MOZ_COUNT_DTOR(XPCNativeInterface);
1317 }
1318
1319 void* operator new(size_t, void* p) CPP_THROW_NEW {return p;}
1320
1321 XPCNativeInterface(const XPCNativeInterface& r); // not implemented
1322 XPCNativeInterface& operator= (const XPCNativeInterface& r); // not implemented
1323
1324 private:
1325 nsCOMPtr<nsIInterfaceInfo> mInfo;
1326 jsid mName;
1327 uint16_t mMemberCount : 15;
1328 uint16_t mMarked : 1;
1329 XPCNativeMember mMembers[1]; // always last - object sized for array
1330 };
1331
1332 /***************************************************************************/
1333 // XPCNativeSetKey is used to key a XPCNativeSet in a NativeSetMap.
1334
1335 class XPCNativeSetKey
1336 {
1337 public:
1338 XPCNativeSetKey(XPCNativeSet* BaseSet = nullptr,
1339 XPCNativeInterface* Addition = nullptr,
1340 uint16_t Position = 0)
1341 : mIsAKey(IS_A_KEY), mPosition(Position), mBaseSet(BaseSet),
1342 mAddition(Addition) {}
1343 ~XPCNativeSetKey() {}
1344
1345 XPCNativeSet* GetBaseSet() const {return mBaseSet;}
1346 XPCNativeInterface* GetAddition() const {return mAddition;}
1347 uint16_t GetPosition() const {return mPosition;}
1348
1349 // This is a fun little hack...
1350 // We build these keys only on the stack. We use them for lookup in
1351 // NativeSetMap. Becasue we don't want to pay the cost of cloning a key and
1352 // sticking it into the hashtable, when the XPCNativeSet actually
1353 // gets added to the table the 'key' in the table is a pointer to the
1354 // set itself and not this key. Our key compare function expects to get
1355 // a key and a set. When we do external lookups in the map we pass in one
1356 // of these keys and our compare function gets passed a key and a set.
1357 // (see compare_NativeKeyToSet in xpcmaps.cpp). This is all well and good.
1358 // Except, when the table decides to resize itself. Then it tries to use
1359 // our compare function with the 'keys' that are in the hashtable (which are
1360 // really XPCNativeSet objects and not XPCNativeSetKey objects!
1361 //
1362 // So, the hack is to have the compare function assume it is getting a
1363 // XPCNativeSetKey pointer and call this IsAKey method. If that fails then
1364 // it realises that it really has a XPCNativeSet pointer and deals with that
1365 // fact. This is safe because we know that both of these classes have no
1366 // virtual methods and their first data member is a uint16_t. We are
1367 // confident that XPCNativeSet->mMemberCount will never be 0xffff.
1368
1369 bool IsAKey() const {return mIsAKey == IS_A_KEY;}
1370
1371 enum {IS_A_KEY = 0xffff};
1372
1373 // Allow shallow copy
1374
1375 private:
1376 uint16_t mIsAKey; // must be first data member
1377 uint16_t mPosition;
1378 XPCNativeSet* mBaseSet;
1379 XPCNativeInterface* mAddition;
1380 };
1381
1382 /***************************************************************************/
1383 // XPCNativeSet represents an ordered collection of XPCNativeInterface pointers.
1384
1385 class XPCNativeSet
1386 {
1387 public:
1388 static XPCNativeSet* GetNewOrUsed(const nsIID* iid);
1389 static XPCNativeSet* GetNewOrUsed(nsIClassInfo* classInfo);
1390 static XPCNativeSet* GetNewOrUsed(XPCNativeSet* otherSet,
1391 XPCNativeInterface* newInterface,
1392 uint16_t position);
1393
1394 // This generates a union set.
1395 //
1396 // If preserveFirstSetOrder is true, the elements from |firstSet| come first,
1397 // followed by any non-duplicate items from |secondSet|. If false, the same
1398 // algorithm is applied; but if we detect that |secondSet| is a superset of
1399 // |firstSet|, we return |secondSet| without worrying about whether the
1400 // ordering might differ from |firstSet|.
1401 static XPCNativeSet* GetNewOrUsed(XPCNativeSet* firstSet,
1402 XPCNativeSet* secondSet,
1403 bool preserveFirstSetOrder);
1404
1405 static void ClearCacheEntryForClassInfo(nsIClassInfo* classInfo);
1406
1407 inline bool FindMember(jsid name, XPCNativeMember** pMember,
1408 uint16_t* pInterfaceIndex) const;
1409
1410 inline bool FindMember(jsid name, XPCNativeMember** pMember,
1411 XPCNativeInterface** pInterface) const;
1412
1413 inline bool FindMember(jsid name,
1414 XPCNativeMember** pMember,
1415 XPCNativeInterface** pInterface,
1416 XPCNativeSet* protoSet,
1417 bool* pIsLocal) const;
1418
1419 inline bool HasInterface(XPCNativeInterface* aInterface) const;
1420 inline bool HasInterfaceWithAncestor(XPCNativeInterface* aInterface) const;
1421 inline bool HasInterfaceWithAncestor(const nsIID* iid) const;
1422
1423 inline XPCNativeInterface* FindInterfaceWithIID(const nsIID& iid) const;
1424
1425 inline XPCNativeInterface* FindNamedInterface(jsid name) const;
1426
1427 uint16_t GetMemberCount() const {
1428 return mMemberCount;
1429 }
1430 uint16_t GetInterfaceCount() const {
1431 return mInterfaceCount;
1432 }
1433 XPCNativeInterface **GetInterfaceArray() {
1434 return mInterfaces;
1435 }
1436
1437 XPCNativeInterface* GetInterfaceAt(uint16_t i)
1438 {MOZ_ASSERT(i < mInterfaceCount, "bad index"); return mInterfaces[i];}
1439
1440 inline bool MatchesSetUpToInterface(const XPCNativeSet* other,
1441 XPCNativeInterface* iface) const;
1442
1443 #define XPC_NATIVE_SET_MARK_FLAG ((uint16_t)JS_BIT(15)) // only high bit of 16 is set
1444
1445 inline void Mark();
1446
1447 // NOP. This is just here to make the AutoMarkingPtr code compile.
1448 inline void TraceJS(JSTracer* trc) {}
1449 inline void AutoTrace(JSTracer* trc) {}
1450
1451 private:
1452 void MarkSelfOnly() {
1453 mMarked = 1;
1454 }
1455
1456 public:
1457 void Unmark() {
1458 mMarked = 0;
1459 }
1460 bool IsMarked() const {
1461 return !!mMarked;
1462 }
1463
1464 #ifdef DEBUG
1465 inline void ASSERT_NotMarked();
1466 #endif
1467
1468 void DebugDump(int16_t depth);
1469
1470 static void DestroyInstance(XPCNativeSet* inst);
1471
1472 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
1473
1474 protected:
1475 static XPCNativeSet* NewInstance(XPCNativeInterface** array,
1476 uint16_t count);
1477 static XPCNativeSet* NewInstanceMutate(XPCNativeSet* otherSet,
1478 XPCNativeInterface* newInterface,
1479 uint16_t position);
1480 XPCNativeSet()
1481 : mMemberCount(0), mInterfaceCount(0), mMarked(0)
1482 {
1483 MOZ_COUNT_CTOR(XPCNativeSet);
1484 }
1485 ~XPCNativeSet() {
1486 MOZ_COUNT_DTOR(XPCNativeSet);
1487 }
1488 void* operator new(size_t, void* p) CPP_THROW_NEW {return p;}
1489
1490 private:
1491 uint16_t mMemberCount;
1492 uint16_t mInterfaceCount : 15;
1493 uint16_t mMarked : 1;
1494 XPCNativeInterface* mInterfaces[1]; // always last - object sized for array
1495 };
1496
1497 /***************************************************************************/
1498 // XPCNativeScriptableFlags is a wrapper class that holds the flags returned
1499 // from calls to nsIXPCScriptable::GetScriptableFlags(). It has convenience
1500 // methods to check for particular bitflags. Since we also use this class as
1501 // a member of the gc'd class XPCNativeScriptableShared, this class holds the
1502 // bit and exposes the inlined methods to support marking.
1503
1504 #define XPC_WN_SJSFLAGS_MARK_FLAG JS_BIT(31) // only high bit of 32 is set
1505
1506 class XPCNativeScriptableFlags
1507 {
1508 private:
1509 uint32_t mFlags;
1510
1511 public:
1512
1513 XPCNativeScriptableFlags(uint32_t flags = 0) : mFlags(flags) {}
1514
1515 uint32_t GetFlags() const {return mFlags & ~XPC_WN_SJSFLAGS_MARK_FLAG;}
1516 void SetFlags(uint32_t flags) {mFlags = flags;}
1517
1518 operator uint32_t() const {return GetFlags();}
1519
1520 XPCNativeScriptableFlags(const XPCNativeScriptableFlags& r)
1521 {mFlags = r.GetFlags();}
1522
1523 XPCNativeScriptableFlags& operator= (const XPCNativeScriptableFlags& r)
1524 {mFlags = r.GetFlags(); return *this;}
1525
1526 void Mark() {mFlags |= XPC_WN_SJSFLAGS_MARK_FLAG;}
1527 void Unmark() {mFlags &= ~XPC_WN_SJSFLAGS_MARK_FLAG;}
1528 bool IsMarked() const {return 0 != (mFlags & XPC_WN_SJSFLAGS_MARK_FLAG);}
1529
1530 #ifdef GET_IT
1531 #undef GET_IT
1532 #endif
1533 #define GET_IT(f_) const {return 0 != (mFlags & nsIXPCScriptable:: f_ );}
1534
1535 bool WantPreCreate() GET_IT(WANT_PRECREATE)
1536 bool WantCreate() GET_IT(WANT_CREATE)
1537 bool WantPostCreate() GET_IT(WANT_POSTCREATE)
1538 bool WantAddProperty() GET_IT(WANT_ADDPROPERTY)
1539 bool WantDelProperty() GET_IT(WANT_DELPROPERTY)
1540 bool WantGetProperty() GET_IT(WANT_GETPROPERTY)
1541 bool WantSetProperty() GET_IT(WANT_SETPROPERTY)
1542 bool WantEnumerate() GET_IT(WANT_ENUMERATE)
1543 bool WantNewEnumerate() GET_IT(WANT_NEWENUMERATE)
1544 bool WantNewResolve() GET_IT(WANT_NEWRESOLVE)
1545 bool WantConvert() GET_IT(WANT_CONVERT)
1546 bool WantFinalize() GET_IT(WANT_FINALIZE)
1547 bool WantCall() GET_IT(WANT_CALL)
1548 bool WantConstruct() GET_IT(WANT_CONSTRUCT)
1549 bool WantHasInstance() GET_IT(WANT_HASINSTANCE)
1550 bool WantOuterObject() GET_IT(WANT_OUTER_OBJECT)
1551 bool UseJSStubForAddProperty() GET_IT(USE_JSSTUB_FOR_ADDPROPERTY)
1552 bool UseJSStubForDelProperty() GET_IT(USE_JSSTUB_FOR_DELPROPERTY)
1553 bool UseJSStubForSetProperty() GET_IT(USE_JSSTUB_FOR_SETPROPERTY)
1554 bool DontEnumStaticProps() GET_IT(DONT_ENUM_STATIC_PROPS)
1555 bool DontEnumQueryInterface() GET_IT(DONT_ENUM_QUERY_INTERFACE)
1556 bool DontAskInstanceForScriptable() GET_IT(DONT_ASK_INSTANCE_FOR_SCRIPTABLE)
1557 bool ClassInfoInterfacesOnly() GET_IT(CLASSINFO_INTERFACES_ONLY)
1558 bool AllowPropModsDuringResolve() GET_IT(ALLOW_PROP_MODS_DURING_RESOLVE)
1559 bool AllowPropModsToPrototype() GET_IT(ALLOW_PROP_MODS_TO_PROTOTYPE)
1560 bool IsGlobalObject() GET_IT(IS_GLOBAL_OBJECT)
1561 bool DontReflectInterfaceNames() GET_IT(DONT_REFLECT_INTERFACE_NAMES)
1562
1563 #undef GET_IT
1564 };
1565
1566 /***************************************************************************/
1567
1568 // XPCNativeScriptableShared is used to hold the JSClass and the
1569 // associated scriptable flags for XPCWrappedNatives. These are shared across
1570 // the runtime and are garbage collected by xpconnect. We *used* to just store
1571 // this inside the XPCNativeScriptableInfo (usually owned by instances of
1572 // XPCWrappedNativeProto. This had two problems... It was wasteful, and it
1573 // was a big problem when wrappers are reparented to different scopes (and
1574 // thus different protos (the DOM does this).
1575
1576 // We maintain the invariant that every JSClass for which ext.isWrappedNative
1577 // is true is a contained in an instance of this struct, and can thus be cast
1578 // to it.
1579 struct XPCWrappedNativeJSClass
1580 {
1581 js::Class base;
1582 uint32_t interfacesBitmap;
1583 };
1584
1585 class XPCNativeScriptableShared
1586 {
1587 public:
1588 const XPCNativeScriptableFlags& GetFlags() const {return mFlags;}
1589 uint32_t GetInterfacesBitmap() const
1590 {return mJSClass.interfacesBitmap;}
1591 const JSClass* GetJSClass()
1592 {return Jsvalify(&mJSClass.base);}
1593
1594 XPCNativeScriptableShared(uint32_t aFlags, char* aName,
1595 uint32_t interfacesBitmap)
1596 : mFlags(aFlags)
1597 {memset(&mJSClass, 0, sizeof(mJSClass));
1598 mJSClass.base.name = aName; // take ownership
1599 mJSClass.interfacesBitmap = interfacesBitmap;
1600 MOZ_COUNT_CTOR(XPCNativeScriptableShared);}
1601
1602 ~XPCNativeScriptableShared()
1603 {if (mJSClass.base.name)nsMemory::Free((void*)mJSClass.base.name);
1604 MOZ_COUNT_DTOR(XPCNativeScriptableShared);}
1605
1606 char* TransferNameOwnership()
1607 {char* name=(char*)mJSClass.base.name; mJSClass.base.name = nullptr;
1608 return name;}
1609
1610 void PopulateJSClass();
1611
1612 void Mark() {mFlags.Mark();}
1613 void Unmark() {mFlags.Unmark();}
1614 bool IsMarked() const {return mFlags.IsMarked();}
1615
1616 private:
1617 XPCNativeScriptableFlags mFlags;
1618 XPCWrappedNativeJSClass mJSClass;
1619 };
1620
1621 /***************************************************************************/
1622 // XPCNativeScriptableInfo is used to hold the nsIXPCScriptable state for a
1623 // given class or instance.
1624
1625 class XPCNativeScriptableInfo
1626 {
1627 public:
1628 static XPCNativeScriptableInfo*
1629 Construct(const XPCNativeScriptableCreateInfo* sci);
1630
1631 nsIXPCScriptable*
1632 GetCallback() const {return mCallback;}
1633
1634 const XPCNativeScriptableFlags&
1635 GetFlags() const {return mShared->GetFlags();}
1636
1637 uint32_t
1638 GetInterfacesBitmap() const {return mShared->GetInterfacesBitmap();}
1639
1640 const JSClass*
1641 GetJSClass() {return mShared->GetJSClass();}
1642
1643 XPCNativeScriptableShared*
1644 GetScriptableShared() {return mShared;}
1645
1646 void
1647 SetCallback(nsIXPCScriptable* s) {mCallback = s;}
1648 void
1649 SetCallback(already_AddRefed<nsIXPCScriptable>&& s) {mCallback = s;}
1650
1651 void
1652 SetScriptableShared(XPCNativeScriptableShared* shared) {mShared = shared;}
1653
1654 void Mark() {
1655 if (mShared)
1656 mShared->Mark();
1657 }
1658
1659 void TraceJS(JSTracer *trc) {}
1660 void AutoTrace(JSTracer *trc) {}
1661
1662 protected:
1663 XPCNativeScriptableInfo(nsIXPCScriptable* scriptable = nullptr,
1664 XPCNativeScriptableShared* shared = nullptr)
1665 : mCallback(scriptable), mShared(shared)
1666 {MOZ_COUNT_CTOR(XPCNativeScriptableInfo);}
1667 public:
1668 ~XPCNativeScriptableInfo() {MOZ_COUNT_DTOR(XPCNativeScriptableInfo);}
1669 private:
1670
1671 // disable copy ctor and assignment
1672 XPCNativeScriptableInfo(const XPCNativeScriptableInfo& r); // not implemented
1673 XPCNativeScriptableInfo& operator= (const XPCNativeScriptableInfo& r); // not implemented
1674
1675 private:
1676 nsCOMPtr<nsIXPCScriptable> mCallback;
1677 XPCNativeScriptableShared* mShared;
1678 };
1679
1680 /***************************************************************************/
1681 // XPCNativeScriptableCreateInfo is used in creating new wrapper and protos.
1682 // it abstracts out the scriptable interface pointer and the flags. After
1683 // creation these are factored differently using XPCNativeScriptableInfo.
1684
1685 class MOZ_STACK_CLASS XPCNativeScriptableCreateInfo
1686 {
1687 public:
1688
1689 XPCNativeScriptableCreateInfo(const XPCNativeScriptableInfo& si)
1690 : mCallback(si.GetCallback()), mFlags(si.GetFlags()),
1691 mInterfacesBitmap(si.GetInterfacesBitmap()) {}
1692
1693 XPCNativeScriptableCreateInfo(already_AddRefed<nsIXPCScriptable>&& callback,
1694 XPCNativeScriptableFlags flags,
1695 uint32_t interfacesBitmap)
1696 : mCallback(callback), mFlags(flags),
1697 mInterfacesBitmap(interfacesBitmap) {}
1698
1699 XPCNativeScriptableCreateInfo()
1700 : mFlags(0), mInterfacesBitmap(0) {}
1701
1702
1703 nsIXPCScriptable*
1704 GetCallback() const {return mCallback;}
1705
1706 const XPCNativeScriptableFlags&
1707 GetFlags() const {return mFlags;}
1708
1709 uint32_t
1710 GetInterfacesBitmap() const {return mInterfacesBitmap;}
1711
1712 void
1713 SetCallback(already_AddRefed<nsIXPCScriptable>&& callback)
1714 {mCallback = callback;}
1715
1716 void
1717 SetFlags(const XPCNativeScriptableFlags& flags) {mFlags = flags;}
1718
1719 void
1720 SetInterfacesBitmap(uint32_t interfacesBitmap)
1721 {mInterfacesBitmap = interfacesBitmap;}
1722
1723 private:
1724 nsCOMPtr<nsIXPCScriptable> mCallback;
1725 XPCNativeScriptableFlags mFlags;
1726 uint32_t mInterfacesBitmap;
1727 };
1728
1729 /***********************************************/
1730 // XPCWrappedNativeProto hold the additional shared wrapper data
1731 // for XPCWrappedNative whose native objects expose nsIClassInfo.
1732
1733 class XPCWrappedNativeProto
1734 {
1735 public:
1736 static XPCWrappedNativeProto*
1737 GetNewOrUsed(XPCWrappedNativeScope* scope,
1738 nsIClassInfo* classInfo,
1739 const XPCNativeScriptableCreateInfo* scriptableCreateInfo,
1740 bool callPostCreatePrototype = true);
1741
1742 XPCWrappedNativeScope*
1743 GetScope() const {return mScope;}
1744
1745 XPCJSRuntime*
1746 GetRuntime() const {return mScope->GetRuntime();}
1747
1748 JSObject*
1749 GetJSProtoObject() const {
1750 JS::ExposeObjectToActiveJS(mJSProtoObject);
1751 return mJSProtoObject;
1752 }
1753
1754 nsIClassInfo*
1755 GetClassInfo() const {return mClassInfo;}
1756
1757 XPCNativeSet*
1758 GetSet() const {return mSet;}
1759
1760 XPCNativeScriptableInfo*
1761 GetScriptableInfo() {return mScriptableInfo;}
1762
1763 uint32_t
1764 GetClassInfoFlags() const {return mClassInfoFlags;}
1765
1766 #ifdef GET_IT
1767 #undef GET_IT
1768 #endif
1769 #define GET_IT(f_) const {return !!(mClassInfoFlags & nsIClassInfo:: f_ );}
1770
1771 bool ClassIsSingleton() GET_IT(SINGLETON)
1772 bool ClassIsDOMObject() GET_IT(DOM_OBJECT)
1773 bool ClassIsPluginObject() GET_IT(PLUGIN_OBJECT)
1774
1775 #undef GET_IT
1776
1777 void SetScriptableInfo(XPCNativeScriptableInfo* si)
1778 {MOZ_ASSERT(!mScriptableInfo, "leak here!"); mScriptableInfo = si;}
1779
1780 bool CallPostCreatePrototype();
1781 void JSProtoObjectFinalized(js::FreeOp *fop, JSObject *obj);
1782
1783 void SystemIsBeingShutDown();
1784
1785 void DebugDump(int16_t depth);
1786
1787 void TraceSelf(JSTracer *trc) {
1788 if (mJSProtoObject)
1789 mJSProtoObject.trace(trc, "XPCWrappedNativeProto::mJSProtoObject");
1790 }
1791
1792 void TraceInside(JSTracer *trc) {
1793 if (JS_IsGCMarkingTracer(trc)) {
1794 mSet->Mark();
1795 if (mScriptableInfo)
1796 mScriptableInfo->Mark();
1797 }
1798
1799 GetScope()->TraceInside(trc);
1800 }
1801
1802 void TraceJS(JSTracer *trc) {
1803 TraceSelf(trc);
1804 TraceInside(trc);
1805 }
1806
1807 void WriteBarrierPre(JSRuntime* rt)
1808 {
1809 if (JS::IsIncrementalBarrierNeeded(rt) && mJSProtoObject)
1810 mJSProtoObject.writeBarrierPre(rt);
1811 }
1812
1813 // NOP. This is just here to make the AutoMarkingPtr code compile.
1814 inline void AutoTrace(JSTracer* trc) {}
1815
1816 // Yes, we *do* need to mark the mScriptableInfo in both cases.
1817 void Mark() const
1818 {mSet->Mark();
1819 if (mScriptableInfo) mScriptableInfo->Mark();}
1820
1821 #ifdef DEBUG
1822 void ASSERT_SetNotMarked() const {mSet->ASSERT_NotMarked();}
1823 #endif
1824
1825 ~XPCWrappedNativeProto();
1826
1827 protected:
1828 // disable copy ctor and assignment
1829 XPCWrappedNativeProto(const XPCWrappedNativeProto& r); // not implemented
1830 XPCWrappedNativeProto& operator= (const XPCWrappedNativeProto& r); // not implemented
1831
1832 // hide ctor
1833 XPCWrappedNativeProto(XPCWrappedNativeScope* Scope,
1834 nsIClassInfo* ClassInfo,
1835 uint32_t ClassInfoFlags,
1836 XPCNativeSet* Set);
1837
1838 bool Init(const XPCNativeScriptableCreateInfo* scriptableCreateInfo,
1839 bool callPostCreatePrototype);
1840
1841 private:
1842 #ifdef DEBUG
1843 static int32_t gDEBUG_LiveProtoCount;
1844 #endif
1845
1846 private:
1847 XPCWrappedNativeScope* mScope;
1848 JS::ObjectPtr mJSProtoObject;
1849 nsCOMPtr<nsIClassInfo> mClassInfo;
1850 uint32_t mClassInfoFlags;
1851 XPCNativeSet* mSet;
1852 XPCNativeScriptableInfo* mScriptableInfo;
1853 };
1854
1855 /***********************************************/
1856 // XPCWrappedNativeTearOff represents the info needed to make calls to one
1857 // interface on the underlying native object of a XPCWrappedNative.
1858
1859 class XPCWrappedNativeTearOff
1860 {
1861 public:
1862 bool IsAvailable() const {return mInterface == nullptr;}
1863 bool IsReserved() const {return mInterface == (XPCNativeInterface*)1;}
1864 bool IsValid() const {return !IsAvailable() && !IsReserved();}
1865 void SetReserved() {mInterface = (XPCNativeInterface*)1;}
1866
1867 XPCNativeInterface* GetInterface() const {return mInterface;}
1868 nsISupports* GetNative() const {return mNative;}
1869 JSObject* GetJSObject();
1870 JSObject* GetJSObjectPreserveColor() const;
1871 void SetInterface(XPCNativeInterface* Interface) {mInterface = Interface;}
1872 void SetNative(nsISupports* Native) {mNative = Native;}
1873 void SetJSObject(JSObject* JSObj);
1874
1875 void JSObjectFinalized() {SetJSObject(nullptr);}
1876
1877 XPCWrappedNativeTearOff()
1878 : mInterface(nullptr), mNative(nullptr), mJSObject(nullptr) {}
1879 ~XPCWrappedNativeTearOff();
1880
1881 // NOP. This is just here to make the AutoMarkingPtr code compile.
1882 inline void TraceJS(JSTracer* trc) {}
1883 inline void AutoTrace(JSTracer* trc) {}
1884
1885 void Mark() {mJSObject = (JSObject*)(intptr_t(mJSObject) | 1);}
1886 void Unmark() {mJSObject = (JSObject*)(intptr_t(mJSObject) & ~1);}
1887 bool IsMarked() const {return !!(intptr_t(mJSObject) & 1);}
1888
1889 private:
1890 XPCWrappedNativeTearOff(const XPCWrappedNativeTearOff& r) MOZ_DELETE;
1891 XPCWrappedNativeTearOff& operator= (const XPCWrappedNativeTearOff& r) MOZ_DELETE;
1892
1893 private:
1894 XPCNativeInterface* mInterface;
1895 nsISupports* mNative;
1896 JSObject* mJSObject;
1897 };
1898
1899 /***********************************************/
1900 // XPCWrappedNativeTearOffChunk is a collections of XPCWrappedNativeTearOff
1901 // objects. It lets us allocate a set of XPCWrappedNativeTearOff objects and
1902 // link the sets - rather than only having the option of linking single
1903 // XPCWrappedNativeTearOff objects.
1904 //
1905 // The value of XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK can be tuned at buildtime
1906 // to balance between the code of allocations of additional chunks and the waste
1907 // of space for ununsed XPCWrappedNativeTearOff objects.
1908
1909 #define XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK 1
1910
1911 class XPCWrappedNativeTearOffChunk
1912 {
1913 friend class XPCWrappedNative;
1914 private:
1915 XPCWrappedNativeTearOffChunk() : mNextChunk(nullptr) {}
1916 ~XPCWrappedNativeTearOffChunk() {delete mNextChunk;}
1917
1918 private:
1919 XPCWrappedNativeTearOff mTearOffs[XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK];
1920 XPCWrappedNativeTearOffChunk* mNextChunk;
1921 };
1922
1923 void *xpc_GetJSPrivate(JSObject *obj);
1924
1925 /***************************************************************************/
1926 // XPCWrappedNative the wrapper around one instance of a native xpcom object
1927 // to be used from JavaScript.
1928
1929 class XPCWrappedNative : public nsIXPConnectWrappedNative
1930 {
1931 public:
1932 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
1933 NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
1934 NS_DECL_NSIXPCONNECTWRAPPEDNATIVE
1935
1936 NS_DECL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
1937
1938 nsIPrincipal* GetObjectPrincipal() const;
1939
1940 bool
1941 IsValid() const { return mFlatJSObject.hasFlag(FLAT_JS_OBJECT_VALID); }
1942
1943 #define XPC_SCOPE_WORD(s) (intptr_t(s))
1944 #define XPC_SCOPE_MASK (intptr_t(0x3))
1945 #define XPC_SCOPE_TAG (intptr_t(0x1))
1946 #define XPC_WRAPPER_EXPIRED (intptr_t(0x2))
1947
1948 static inline bool
1949 IsTaggedScope(XPCWrappedNativeScope* s)
1950 {return XPC_SCOPE_WORD(s) & XPC_SCOPE_TAG;}
1951
1952 static inline XPCWrappedNativeScope*
1953 TagScope(XPCWrappedNativeScope* s)
1954 {MOZ_ASSERT(!IsTaggedScope(s), "bad pointer!");
1955 return (XPCWrappedNativeScope*)(XPC_SCOPE_WORD(s) | XPC_SCOPE_TAG);}
1956
1957 static inline XPCWrappedNativeScope*
1958 UnTagScope(XPCWrappedNativeScope* s)
1959 {return (XPCWrappedNativeScope*)(XPC_SCOPE_WORD(s) & ~XPC_SCOPE_TAG);}
1960
1961 inline bool
1962 IsWrapperExpired() const
1963 {return XPC_SCOPE_WORD(mMaybeScope) & XPC_WRAPPER_EXPIRED;}
1964
1965 bool
1966 HasProto() const {return !IsTaggedScope(mMaybeScope);}
1967
1968 XPCWrappedNativeProto*
1969 GetProto() const
1970 {return HasProto() ?
1971 (XPCWrappedNativeProto*)
1972 (XPC_SCOPE_WORD(mMaybeProto) & ~XPC_SCOPE_MASK) : nullptr;}
1973
1974 void SetProto(XPCWrappedNativeProto* p);
1975
1976 XPCWrappedNativeScope*
1977 GetScope() const
1978 {return GetProto() ? GetProto()->GetScope() :
1979 (XPCWrappedNativeScope*)
1980 (XPC_SCOPE_WORD(mMaybeScope) & ~XPC_SCOPE_MASK);}
1981
1982 nsISupports*
1983 GetIdentityObject() const {return mIdentity;}
1984
1985 /**
1986 * This getter clears the gray bit before handing out the JSObject which
1987 * means that the object is guaranteed to be kept alive past the next CC.
1988 */
1989 JSObject*
1990 GetFlatJSObject() const
1991 {
1992 JS::ExposeObjectToActiveJS(mFlatJSObject);
1993 return mFlatJSObject;
1994 }
1995
1996 /**
1997 * This getter does not change the color of the JSObject meaning that the
1998 * object returned is not guaranteed to be kept alive past the next CC.
1999 *
2000 * This should only be called if you are certain that the return value won't
2001 * be passed into a JS API function and that it won't be stored without
2002 * being rooted (or otherwise signaling the stored value to the CC).
2003 */
2004 JSObject*
2005 GetFlatJSObjectPreserveColor() const {return mFlatJSObject;}
2006
2007 XPCNativeSet*
2008 GetSet() const {return mSet;}
2009
2010 void
2011 SetSet(XPCNativeSet* set) {mSet = set;}
2012
2013 static XPCWrappedNative* Get(JSObject *obj) {
2014 MOZ_ASSERT(IS_WN_REFLECTOR(obj));
2015 return (XPCWrappedNative*)js::GetObjectPrivate(obj);
2016 }
2017
2018 private:
2019 inline void
2020 ExpireWrapper()
2021 {mMaybeScope = (XPCWrappedNativeScope*)
2022 (XPC_SCOPE_WORD(mMaybeScope) | XPC_WRAPPER_EXPIRED);}
2023
2024 public:
2025
2026 XPCNativeScriptableInfo*
2027 GetScriptableInfo() const {return mScriptableInfo;}
2028
2029 nsIXPCScriptable* // call this wrong and you deserve to crash
2030 GetScriptableCallback() const {return mScriptableInfo->GetCallback();}
2031
2032 nsIClassInfo*
2033 GetClassInfo() const {return IsValid() && HasProto() ?
2034 GetProto()->GetClassInfo() : nullptr;}
2035
2036 bool
2037 HasMutatedSet() const {return IsValid() &&
2038 (!HasProto() ||
2039 GetSet() != GetProto()->GetSet());}
2040
2041 XPCJSRuntime*
2042 GetRuntime() const {XPCWrappedNativeScope* scope = GetScope();
2043 return scope ? scope->GetRuntime() : nullptr;}
2044
2045 static nsresult
2046 WrapNewGlobal(xpcObjectHelper &nativeHelper,
2047 nsIPrincipal *principal, bool initStandardClasses,
2048 JS::CompartmentOptions& aOptions,
2049 XPCWrappedNative **wrappedGlobal);
2050
2051 static nsresult
2052 GetNewOrUsed(xpcObjectHelper& helper,
2053 XPCWrappedNativeScope* Scope,
2054 XPCNativeInterface* Interface,
2055 XPCWrappedNative** wrapper);
2056
2057 public:
2058 static nsresult
2059 GetUsedOnly(nsISupports* Object,
2060 XPCWrappedNativeScope* Scope,
2061 XPCNativeInterface* Interface,
2062 XPCWrappedNative** wrapper);
2063
2064 static nsresult
2065 ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope,
2066 XPCWrappedNativeScope* aNewScope,
2067 JS::HandleObject aNewParent,
2068 nsISupports* aCOMObj);
2069
2070 nsresult RescueOrphans();
2071
2072 void FlatJSObjectFinalized();
2073
2074 void SystemIsBeingShutDown();
2075
2076 enum CallMode {CALL_METHOD, CALL_GETTER, CALL_SETTER};
2077
2078 static bool CallMethod(XPCCallContext& ccx,
2079 CallMode mode = CALL_METHOD);
2080
2081 static bool GetAttribute(XPCCallContext& ccx)
2082 {return CallMethod(ccx, CALL_GETTER);}
2083
2084 static bool SetAttribute(XPCCallContext& ccx)
2085 {return CallMethod(ccx, CALL_SETTER);}
2086
2087 inline bool HasInterfaceNoQI(const nsIID& iid);
2088
2089 XPCWrappedNativeTearOff* LocateTearOff(XPCNativeInterface* aInterface);
2090 XPCWrappedNativeTearOff* FindTearOff(XPCNativeInterface* aInterface,
2091 bool needJSObject = false,
2092 nsresult* pError = nullptr);
2093 void Mark() const
2094 {
2095 mSet->Mark();
2096 if (mScriptableInfo) mScriptableInfo->Mark();
2097 if (HasProto()) GetProto()->Mark();
2098 }
2099
2100 // Yes, we *do* need to mark the mScriptableInfo in both cases.
2101 inline void TraceInside(JSTracer *trc) {
2102 if (JS_IsGCMarkingTracer(trc)) {
2103 mSet->Mark();
2104 if (mScriptableInfo)
2105 mScriptableInfo->Mark();
2106 }
2107 if (HasProto())
2108 GetProto()->TraceSelf(trc);
2109 else
2110 GetScope()->TraceInside(trc);
2111 if (mFlatJSObject && JS_IsGlobalObject(mFlatJSObject))
2112 {
2113 xpc::TraceXPCGlobal(trc, mFlatJSObject);
2114 }
2115 }
2116
2117 void TraceJS(JSTracer *trc) {
2118 TraceInside(trc);
2119 }
2120
2121 void TraceSelf(JSTracer *trc) {
2122 // If this got called, we're being kept alive by someone who really
2123 // needs us alive and whole. Do not let our mFlatJSObject go away.
2124 // This is the only time we should be tracing our mFlatJSObject,
2125 // normally somebody else is doing that. Be careful not to trace the
2126 // bogus INVALID_OBJECT value we can have during init, though.
2127 if (mFlatJSObject) {
2128 JS_CallTenuredObjectTracer(trc, &mFlatJSObject,
2129 "XPCWrappedNative::mFlatJSObject");
2130 }
2131 }
2132
2133 static void Trace(JSTracer *trc, JSObject *obj);
2134
2135 void AutoTrace(JSTracer *trc) {
2136 TraceSelf(trc);
2137 }
2138
2139 #ifdef DEBUG
2140 void ASSERT_SetsNotMarked() const
2141 {mSet->ASSERT_NotMarked();
2142 if (HasProto()){GetProto()->ASSERT_SetNotMarked();}}
2143 #endif
2144
2145 inline void SweepTearOffs();
2146
2147 // Returns a string that shuld be free'd using JS_smprintf_free (or null).
2148 char* ToString(XPCWrappedNativeTearOff* to = nullptr) const;
2149
2150 static void GatherProtoScriptableCreateInfo(nsIClassInfo* classInfo,
2151 XPCNativeScriptableCreateInfo& sciProto);
2152
2153 bool HasExternalReference() const {return mRefCnt > 1;}
2154
2155 void NoteTearoffs(nsCycleCollectionTraversalCallback& cb);
2156
2157 // Make ctor and dtor protected (rather than private) to placate nsCOMPtr.
2158 protected:
2159 XPCWrappedNative(); // not implemented
2160
2161 // This ctor is used if this object will have a proto.
2162 XPCWrappedNative(already_AddRefed<nsISupports>&& aIdentity,
2163 XPCWrappedNativeProto* aProto);
2164
2165 // This ctor is used if this object will NOT have a proto.
2166 XPCWrappedNative(already_AddRefed<nsISupports>&& aIdentity,
2167 XPCWrappedNativeScope* aScope,
2168 XPCNativeSet* aSet);
2169
2170 virtual ~XPCWrappedNative();
2171 void Destroy();
2172
2173 void UpdateScriptableInfo(XPCNativeScriptableInfo *si);
2174
2175 private:
2176 enum {
2177 // Flags bits for mFlatJSObject:
2178 FLAT_JS_OBJECT_VALID = JS_BIT(0)
2179 };
2180
2181 private:
2182
2183 bool Init(JS::HandleObject parent, const XPCNativeScriptableCreateInfo* sci);
2184 bool FinishInit();
2185
2186 bool ExtendSet(XPCNativeInterface* aInterface);
2187
2188 nsresult InitTearOff(XPCWrappedNativeTearOff* aTearOff,
2189 XPCNativeInterface* aInterface,
2190 bool needJSObject);
2191
2192 bool InitTearOffJSObject(XPCWrappedNativeTearOff* to);
2193
2194 public:
2195 static const XPCNativeScriptableCreateInfo& GatherScriptableCreateInfo(nsISupports* obj,
2196 nsIClassInfo* classInfo,
2197 XPCNativeScriptableCreateInfo& sciProto,
2198 XPCNativeScriptableCreateInfo& sciWrapper);
2199
2200 private:
2201 union
2202 {
2203 XPCWrappedNativeScope* mMaybeScope;
2204 XPCWrappedNativeProto* mMaybeProto;
2205 };
2206 XPCNativeSet* mSet;
2207 JS::TenuredHeap<JSObject*> mFlatJSObject;
2208 XPCNativeScriptableInfo* mScriptableInfo;
2209 XPCWrappedNativeTearOffChunk mFirstChunk;
2210 };
2211
2212 /***************************************************************************
2213 ****************************************************************************
2214 *
2215 * Core classes for wrapped JSObject for use from native code...
2216 *
2217 ****************************************************************************
2218 ***************************************************************************/
2219
2220 // this interfaces exists so we can refcount nsXPCWrappedJSClass
2221 // {2453EBA0-A9B8-11d2-BA64-00805F8A5DD7}
2222 #define NS_IXPCONNECT_WRAPPED_JS_CLASS_IID \
2223 { 0x2453eba0, 0xa9b8, 0x11d2, \
2224 { 0xba, 0x64, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } }
2225
2226 class nsIXPCWrappedJSClass : public nsISupports
2227 {
2228 public:
2229 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXPCONNECT_WRAPPED_JS_CLASS_IID)
2230 NS_IMETHOD DebugDump(int16_t depth) = 0;
2231 };
2232
2233 NS_DEFINE_STATIC_IID_ACCESSOR(nsIXPCWrappedJSClass,
2234 NS_IXPCONNECT_WRAPPED_JS_CLASS_IID)
2235
2236 /*************************/
2237 // nsXPCWrappedJSClass represents the sharable factored out common code and
2238 // data for nsXPCWrappedJS instances for the same interface type.
2239
2240 class nsXPCWrappedJSClass : public nsIXPCWrappedJSClass
2241 {
2242 // all the interface method declarations...
2243 NS_DECL_ISUPPORTS
2244 NS_IMETHOD DebugDump(int16_t depth);
2245 public:
2246
2247 static already_AddRefed<nsXPCWrappedJSClass>
2248 GetNewOrUsed(JSContext* cx,
2249 REFNSIID aIID);
2250
2251 REFNSIID GetIID() const {return mIID;}
2252 XPCJSRuntime* GetRuntime() const {return mRuntime;}
2253 nsIInterfaceInfo* GetInterfaceInfo() const {return mInfo;}
2254 const char* GetInterfaceName();
2255
2256 static bool IsWrappedJS(nsISupports* aPtr);
2257
2258 NS_IMETHOD DelegatedQueryInterface(nsXPCWrappedJS* self, REFNSIID aIID,
2259 void** aInstancePtr);
2260
2261 JSObject* GetRootJSObject(JSContext* cx, JSObject* aJSObj);
2262
2263 NS_IMETHOD CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
2264 const XPTMethodDescriptor* info,
2265 nsXPTCMiniVariant* params);
2266
2267 JSObject* CallQueryInterfaceOnJSObject(JSContext* cx,
2268 JSObject* jsobj, REFNSIID aIID);
2269
2270 static nsresult BuildPropertyEnumerator(XPCCallContext& ccx,
2271 JSObject* aJSObj,
2272 nsISimpleEnumerator** aEnumerate);
2273
2274 static nsresult GetNamedPropertyAsVariant(XPCCallContext& ccx,
2275 JSObject* aJSObj,
2276 const nsAString& aName,
2277 nsIVariant** aResult);
2278
2279 virtual ~nsXPCWrappedJSClass();
2280
2281 static nsresult CheckForException(XPCCallContext & ccx,
2282 const char * aPropertyName,
2283 const char * anInterfaceName,
2284 bool aForceReport);
2285 private:
2286 nsXPCWrappedJSClass(); // not implemented
2287 nsXPCWrappedJSClass(JSContext* cx, REFNSIID aIID,
2288 nsIInterfaceInfo* aInfo);
2289
2290 bool IsReflectable(uint16_t i) const
2291 {return (bool)(mDescriptors[i/32] & (1 << (i%32)));}
2292 void SetReflectable(uint16_t i, bool b)
2293 {if (b) mDescriptors[i/32] |= (1 << (i%32));
2294 else mDescriptors[i/32] &= ~(1 << (i%32));}
2295
2296 bool GetArraySizeFromParam(JSContext* cx,
2297 const XPTMethodDescriptor* method,
2298 const nsXPTParamInfo& param,
2299 uint16_t methodIndex,
2300 uint8_t paramIndex,
2301 nsXPTCMiniVariant* params,
2302 uint32_t* result);
2303
2304 bool GetInterfaceTypeFromParam(JSContext* cx,
2305 const XPTMethodDescriptor* method,
2306 const nsXPTParamInfo& param,
2307 uint16_t methodIndex,
2308 const nsXPTType& type,
2309 nsXPTCMiniVariant* params,
2310 nsID* result);
2311
2312 void CleanupPointerArray(const nsXPTType& datum_type,
2313 uint32_t array_count,
2314 void** arrayp);
2315
2316 void CleanupPointerTypeObject(const nsXPTType& type,
2317 void** pp);
2318
2319 private:
2320 XPCJSRuntime* mRuntime;
2321 nsCOMPtr<nsIInterfaceInfo> mInfo;
2322 char* mName;
2323 nsIID mIID;
2324 uint32_t* mDescriptors;
2325 };
2326
2327 /*************************/
2328 // nsXPCWrappedJS is a wrapper for a single JSObject for use from native code.
2329 // nsXPCWrappedJS objects are chained together to represent the various
2330 // interface on the single underlying (possibly aggregate) JSObject.
2331
2332 class nsXPCWrappedJS : protected nsAutoXPTCStub,
2333 public nsIXPConnectWrappedJS,
2334 public nsSupportsWeakReference,
2335 public nsIPropertyBag,
2336 public XPCRootSetElem
2337 {
2338 public:
2339 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
2340 NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
2341 NS_DECL_NSIXPCONNECTWRAPPEDJS
2342 NS_DECL_NSISUPPORTSWEAKREFERENCE
2343 NS_DECL_NSIPROPERTYBAG
2344
2345 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS_AMBIGUOUS(nsXPCWrappedJS, nsIXPConnectWrappedJS)
2346
2347 NS_IMETHOD CallMethod(uint16_t methodIndex,
2348 const XPTMethodDescriptor *info,
2349 nsXPTCMiniVariant* params);
2350
2351 /*
2352 * This is rarely called directly. Instead one usually calls
2353 * XPCConvert::JSObject2NativeInterface which will handles cases where the
2354 * JS object is already a wrapped native or a DOM object.
2355 */
2356
2357 static nsresult
2358 GetNewOrUsed(JS::HandleObject aJSObj,
2359 REFNSIID aIID,
2360 nsXPCWrappedJS** wrapper);
2361
2362 nsISomeInterface* GetXPTCStub() { return mXPTCStub; }
2363
2364 /**
2365 * This getter does not change the color of the JSObject meaning that the
2366 * object returned is not guaranteed to be kept alive past the next CC.
2367 *
2368 * This should only be called if you are certain that the return value won't
2369 * be passed into a JS API function and that it won't be stored without
2370 * being rooted (or otherwise signaling the stored value to the CC).
2371 */
2372 JSObject* GetJSObjectPreserveColor() const {return mJSObj;}
2373
2374 nsXPCWrappedJSClass* GetClass() const {return mClass;}
2375 REFNSIID GetIID() const {return GetClass()->GetIID();}
2376 nsXPCWrappedJS* GetRootWrapper() const {return mRoot;}
2377 nsXPCWrappedJS* GetNextWrapper() const {return mNext;}
2378
2379 nsXPCWrappedJS* Find(REFNSIID aIID);
2380 nsXPCWrappedJS* FindInherited(REFNSIID aIID);
2381 nsXPCWrappedJS* FindOrFindInherited(REFNSIID aIID) {
2382 nsXPCWrappedJS* wrapper = Find(aIID);
2383 if (wrapper)
2384 return wrapper;
2385 return FindInherited(aIID);
2386 }
2387
2388 bool IsRootWrapper() const {return mRoot == this;}
2389 bool IsValid() const {return mJSObj != nullptr;}
2390 void SystemIsBeingShutDown();
2391
2392 // These two methods are used by JSObject2WrappedJSMap::FindDyingJSObjects
2393 // to find non-rooting wrappers for dying JS objects. See the top of
2394 // XPCWrappedJS.cpp for more details.
2395 bool IsSubjectToFinalization() const {return IsValid() && mRefCnt == 1;}
2396 bool IsObjectAboutToBeFinalized() {return JS_IsAboutToBeFinalized(&mJSObj);}
2397
2398 bool IsAggregatedToNative() const {return mRoot->mOuter != nullptr;}
2399 nsISupports* GetAggregatedNativeObject() const {return mRoot->mOuter;}
2400 void SetAggregatedNativeObject(nsISupports *aNative) {
2401 MOZ_ASSERT(aNative);
2402 if (mRoot->mOuter) {
2403 MOZ_ASSERT(mRoot->mOuter == aNative,
2404 "Only one aggregated native can be set");
2405 return;
2406 }
2407 mRoot->mOuter = aNative;
2408 }
2409
2410 void TraceJS(JSTracer* trc);
2411 static void GetTraceName(JSTracer* trc, char *buf, size_t bufsize);
2412
2413 virtual ~nsXPCWrappedJS();
2414 protected:
2415 nsXPCWrappedJS(); // not implemented
2416 nsXPCWrappedJS(JSContext* cx,
2417 JSObject* aJSObj,
2418 nsXPCWrappedJSClass* aClass,
2419 nsXPCWrappedJS* root);
2420
2421 bool CanSkip();
2422 void Destroy();
2423 void Unlink();
2424
2425 private:
2426 JS::Heap<JSObject*> mJSObj;
2427 nsRefPtr<nsXPCWrappedJSClass> mClass;
2428 nsXPCWrappedJS* mRoot; // If mRoot != this, it is an owning pointer.
2429 nsXPCWrappedJS* mNext;
2430 nsCOMPtr<nsISupports> mOuter; // only set in root
2431 };
2432
2433 /***************************************************************************/
2434
2435 class XPCJSObjectHolder : public nsIXPConnectJSObjectHolder,
2436 public XPCRootSetElem
2437 {
2438 public:
2439 // all the interface method declarations...
2440 NS_DECL_ISUPPORTS
2441 NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
2442
2443 // non-interface implementation
2444
2445 public:
2446 static XPCJSObjectHolder* newHolder(JSObject* obj);
2447
2448 virtual ~XPCJSObjectHolder();
2449
2450 void TraceJS(JSTracer *trc);
2451 static void GetTraceName(JSTracer* trc, char *buf, size_t bufsize);
2452
2453 private:
2454 XPCJSObjectHolder(JSObject* obj);
2455 XPCJSObjectHolder(); // not implemented
2456
2457 JS::Heap<JSObject*> mJSObj;
2458 };
2459
2460 /***************************************************************************
2461 ****************************************************************************
2462 *
2463 * All manner of utility classes follow...
2464 *
2465 ****************************************************************************
2466 ***************************************************************************/
2467
2468 class xpcProperty : public nsIProperty
2469 {
2470 public:
2471 NS_DECL_ISUPPORTS
2472 NS_DECL_NSIPROPERTY
2473
2474 xpcProperty(const char16_t* aName, uint32_t aNameLen, nsIVariant* aValue);
2475 virtual ~xpcProperty() {}
2476
2477 private:
2478 nsString mName;
2479 nsCOMPtr<nsIVariant> mValue;
2480 };
2481
2482 /***************************************************************************/
2483 // class here just for static methods
2484 class XPCConvert
2485 {
2486 public:
2487 static bool IsMethodReflectable(const XPTMethodDescriptor& info);
2488
2489 /**
2490 * Convert a native object into a jsval.
2491 *
2492 * @param d [out] the resulting jsval
2493 * @param s the native object we're working with
2494 * @param type the type of object that s is
2495 * @param iid the interface of s that we want
2496 * @param scope the default scope to put on the new JSObject's parent
2497 * chain
2498 * @param pErr [out] relevant error code, if any.
2499 */
2500
2501 static bool NativeData2JS(JS::MutableHandleValue d,
2502 const void* s, const nsXPTType& type,
2503 const nsID* iid, nsresult* pErr);
2504
2505 static bool JSData2Native(void* d, JS::HandleValue s,
2506 const nsXPTType& type,
2507 bool useAllocator, const nsID* iid,
2508 nsresult* pErr);
2509
2510 /**
2511 * Convert a native nsISupports into a JSObject.
2512 *
2513 * @param dest [out] the resulting JSObject
2514 * @param src the native object we're working with
2515 * @param iid the interface of src that we want (may be null)
2516 * @param Interface the interface of src that we want
2517 * @param cache the wrapper cache for src (may be null, in which case src
2518 * will be QI'ed to get the cache)
2519 * @param allowNativeWrapper if true, this method may wrap the resulting
2520 * JSObject in an XPCNativeWrapper and return that, as needed.
2521 * @param pErr [out] relevant error code, if any.
2522 * @param src_is_identity optional performance hint. Set to true only
2523 * if src is the identity pointer.
2524 */
2525 static bool NativeInterface2JSObject(JS::MutableHandleValue d,
2526 nsIXPConnectJSObjectHolder** dest,
2527 xpcObjectHelper& aHelper,
2528 const nsID* iid,
2529 XPCNativeInterface** Interface,
2530 bool allowNativeWrapper,
2531 nsresult* pErr);
2532
2533 static bool GetNativeInterfaceFromJSObject(void** dest, JSObject* src,
2534 const nsID* iid,
2535 nsresult* pErr);
2536 static bool JSObject2NativeInterface(void** dest, JS::HandleObject src,
2537 const nsID* iid,
2538 nsISupports* aOuter,
2539 nsresult* pErr);
2540 static bool GetISupportsFromJSObject(JSObject* obj, nsISupports** iface);
2541
2542 /**
2543 * Convert a native array into a jsval.
2544 *
2545 * @param d [out] the resulting jsval
2546 * @param s the native array we're working with
2547 * @param type the type of objects in the array
2548 * @param iid the interface of each object in the array that we want
2549 * @param count the number of items in the array
2550 * @param scope the default scope to put on the new JSObjects' parent chain
2551 * @param pErr [out] relevant error code, if any.
2552 */
2553 static bool NativeArray2JS(JS::MutableHandleValue d, const void** s,
2554 const nsXPTType& type, const nsID* iid,
2555 uint32_t count, nsresult* pErr);
2556
2557 static bool JSArray2Native(void** d, JS::HandleValue s,
2558 uint32_t count, const nsXPTType& type,
2559 const nsID* iid, nsresult* pErr);
2560
2561 static bool JSTypedArray2Native(void** d,
2562 JSObject* jsarray,
2563 uint32_t count,
2564 const nsXPTType& type,
2565 nsresult* pErr);
2566
2567 static bool NativeStringWithSize2JS(JS::MutableHandleValue d, const void* s,
2568 const nsXPTType& type,
2569 uint32_t count,
2570 nsresult* pErr);
2571
2572 static bool JSStringWithSize2Native(void* d, JS::HandleValue s,
2573 uint32_t count, const nsXPTType& type,
2574 nsresult* pErr);
2575
2576 static nsresult JSValToXPCException(JS::MutableHandleValue s,
2577 const char* ifaceName,
2578 const char* methodName,
2579 nsIException** exception);
2580
2581 static nsresult JSErrorToXPCException(const char* message,
2582 const char* ifaceName,
2583 const char* methodName,
2584 const JSErrorReport* report,
2585 nsIException** exception);
2586
2587 static nsresult ConstructException(nsresult rv, const char* message,
2588 const char* ifaceName,
2589 const char* methodName,
2590 nsISupports* data,
2591 nsIException** exception,
2592 JSContext* cx,
2593 jsval *jsExceptionPtr);
2594
2595 private:
2596 XPCConvert(); // not implemented
2597
2598 };
2599
2600 /***************************************************************************/
2601 // code for throwing exceptions into JS
2602
2603 class nsXPCException;
2604
2605 class XPCThrower
2606 {
2607 public:
2608 static void Throw(nsresult rv, JSContext* cx);
2609 static void Throw(nsresult rv, XPCCallContext& ccx);
2610 static void ThrowBadResult(nsresult rv, nsresult result, XPCCallContext& ccx);
2611 static void ThrowBadParam(nsresult rv, unsigned paramNum, XPCCallContext& ccx);
2612 static bool SetVerbosity(bool state)
2613 {bool old = sVerbose; sVerbose = state; return old;}
2614
2615 static bool CheckForPendingException(nsresult result, JSContext *cx);
2616
2617 private:
2618 static void Verbosify(XPCCallContext& ccx,
2619 char** psz, bool own);
2620
2621 private:
2622 static bool sVerbose;
2623 };
2624
2625 /***************************************************************************/
2626
2627 class nsXPCException
2628 {
2629 public:
2630 static bool NameAndFormatForNSResult(nsresult rv,
2631 const char** name,
2632 const char** format);
2633
2634 static const void* IterateNSResults(nsresult* rv,
2635 const char** name,
2636 const char** format,
2637 const void** iterp);
2638
2639 static uint32_t GetNSResultCount();
2640 };
2641
2642 /***************************************************************************/
2643 /*
2644 * nsJSID implements nsIJSID. It is also used by nsJSIID and nsJSCID as a
2645 * member (as a hidden implementaion detail) to which they delegate many calls.
2646 */
2647
2648 // Initialization is done on demand, and calling the destructor below is always
2649 // safe.
2650 extern void xpc_DestroyJSxIDClassObjects();
2651
2652 class nsJSID : public nsIJSID
2653 {
2654 public:
2655 NS_DEFINE_STATIC_CID_ACCESSOR(NS_JS_ID_CID)
2656
2657 NS_DECL_ISUPPORTS
2658 NS_DECL_NSIJSID
2659
2660 bool InitWithName(const nsID& id, const char *nameString);
2661 bool SetName(const char* name);
2662 void SetNameToNoString()
2663 {MOZ_ASSERT(!mName, "name already set"); mName = gNoString;}
2664 bool NameIsSet() const {return nullptr != mName;}
2665 const nsID& ID() const {return mID;}
2666 bool IsValid() const {return !mID.Equals(GetInvalidIID());}
2667
2668 static already_AddRefed<nsJSID> NewID(const char* str);
2669 static already_AddRefed<nsJSID> NewID(const nsID& id);
2670
2671 nsJSID();
2672 virtual ~nsJSID();
2673 protected:
2674
2675 void Reset();
2676 const nsID& GetInvalidIID() const;
2677
2678 protected:
2679 static char gNoString[];
2680 nsID mID;
2681 char* mNumber;
2682 char* mName;
2683 };
2684
2685 // nsJSIID
2686
2687 class nsJSIID : public nsIJSIID,
2688 public nsIXPCScriptable
2689 {
2690 public:
2691 NS_DECL_ISUPPORTS
2692
2693 // we manually delagate these to nsJSID
2694 NS_DECL_NSIJSID
2695
2696 // we implement the rest...
2697 NS_DECL_NSIJSIID
2698 NS_DECL_NSIXPCSCRIPTABLE
2699
2700 static already_AddRefed<nsJSIID> NewID(nsIInterfaceInfo* aInfo);
2701
2702 nsJSIID(nsIInterfaceInfo* aInfo);
2703 nsJSIID(); // not implemented
2704 virtual ~nsJSIID();
2705
2706 private:
2707 nsCOMPtr<nsIInterfaceInfo> mInfo;
2708 };
2709
2710 // nsJSCID
2711
2712 class nsJSCID : public nsIJSCID, public nsIXPCScriptable
2713 {
2714 public:
2715 NS_DECL_ISUPPORTS
2716
2717 // we manually delagate these to nsJSID
2718 NS_DECL_NSIJSID
2719
2720 // we implement the rest...
2721 NS_DECL_NSIJSCID
2722 NS_DECL_NSIXPCSCRIPTABLE
2723
2724 static already_AddRefed<nsJSCID> NewID(const char* str);
2725
2726 nsJSCID();
2727 virtual ~nsJSCID();
2728
2729 private:
2730 void ResolveName();
2731
2732 private:
2733 nsJSID mDetails;
2734 };
2735
2736
2737 /***************************************************************************/
2738 // XPCJSContextStack is not actually an xpcom object, but xpcom calls are
2739 // delegated to it as an implementation detail.
2740 struct XPCJSContextInfo {
2741 XPCJSContextInfo(JSContext* aCx) :
2742 cx(aCx),
2743 savedFrameChain(false)
2744 {}
2745 JSContext* cx;
2746
2747 // Whether the frame chain was saved
2748 bool savedFrameChain;
2749 };
2750
2751 namespace xpc {
2752
2753 // These functions are used in a few places where a callback model makes it
2754 // impossible to push a JSContext using one of our stack-scoped classes. We
2755 // depend on those stack-scoped classes to maintain nsIScriptContext
2756 // invariants, so these functions may only be used of the context is not
2757 // associated with an nsJSContext/nsIScriptContext.
2758 bool PushJSContextNoScriptContext(JSContext *aCx);
2759 void PopJSContextNoScriptContext();
2760
2761 } /* namespace xpc */
2762
2763 class XPCJSContextStack
2764 {
2765 public:
2766 XPCJSContextStack(XPCJSRuntime *aRuntime)
2767 : mRuntime(aRuntime)
2768 , mSafeJSContext(nullptr)
2769 , mSafeJSContextGlobal(aRuntime->Runtime(), nullptr)
2770 { }
2771
2772 virtual ~XPCJSContextStack();
2773
2774 uint32_t Count()
2775 {
2776 return mStack.Length();
2777 }
2778
2779 JSContext *Peek()
2780 {
2781 return mStack.IsEmpty() ? nullptr : mStack[mStack.Length() - 1].cx;
2782 }
2783
2784 JSContext *InitSafeJSContext();
2785 JSContext *GetSafeJSContext();
2786 JSObject *GetSafeJSContextGlobal();
2787 bool HasJSContext(JSContext *cx);
2788
2789 const InfallibleTArray<XPCJSContextInfo>* GetStack()
2790 { return &mStack; }
2791
2792 private:
2793 friend class mozilla::AutoCxPusher;
2794 friend bool xpc::PushJSContextNoScriptContext(JSContext *aCx);;
2795 friend void xpc::PopJSContextNoScriptContext();
2796
2797 // We make these private so that stack manipulation can only happen
2798 // through one of the above friends.
2799 JSContext *Pop();
2800 bool Push(JSContext *cx);
2801
2802 AutoInfallibleTArray<XPCJSContextInfo, 16> mStack;
2803 XPCJSRuntime* mRuntime;
2804 JSContext* mSafeJSContext;
2805 JS::PersistentRootedObject mSafeJSContextGlobal;
2806 };
2807
2808 /***************************************************************************/
2809 // 'Components' object implementations. nsXPCComponentsBase has the
2810 // less-privileged stuff that we're willing to expose to XBL.
2811
2812 class nsXPCComponentsBase : public nsIXPCComponentsBase
2813 {
2814 public:
2815 NS_DECL_ISUPPORTS
2816 NS_DECL_NSIXPCCOMPONENTSBASE
2817
2818 public:
2819 void SystemIsBeingShutDown() { ClearMembers(); }
2820 virtual ~nsXPCComponentsBase();
2821
2822 XPCWrappedNativeScope *GetScope() { return mScope; }
2823
2824 protected:
2825 nsXPCComponentsBase(XPCWrappedNativeScope* aScope);
2826 virtual void ClearMembers();
2827
2828 XPCWrappedNativeScope* mScope;
2829
2830 // Unprivileged members from nsIXPCComponentsBase.
2831 nsRefPtr<nsXPCComponents_Interfaces> mInterfaces;
2832 nsRefPtr<nsXPCComponents_InterfacesByID> mInterfacesByID;
2833 nsRefPtr<nsXPCComponents_Results> mResults;
2834
2835 friend class XPCWrappedNativeScope;
2836 };
2837
2838 class nsXPCComponents : public nsXPCComponentsBase,
2839 public nsIXPCComponents
2840 {
2841 public:
2842 NS_DECL_ISUPPORTS
2843 NS_FORWARD_NSIXPCCOMPONENTSBASE(nsXPCComponentsBase::)
2844 NS_DECL_NSIXPCCOMPONENTS
2845
2846 protected:
2847 nsXPCComponents(XPCWrappedNativeScope* aScope);
2848 virtual ~nsXPCComponents();
2849 virtual void ClearMembers() MOZ_OVERRIDE;
2850
2851 // Privileged members added by nsIXPCComponents.
2852 nsRefPtr<nsXPCComponents_Classes> mClasses;
2853 nsRefPtr<nsXPCComponents_ClassesByID> mClassesByID;
2854 nsRefPtr<nsXPCComponents_ID> mID;
2855 nsRefPtr<nsXPCComponents_Exception> mException;
2856 nsRefPtr<nsXPCComponents_Constructor> mConstructor;
2857 nsRefPtr<nsXPCComponents_Utils> mUtils;
2858
2859 friend class XPCWrappedNativeScope;
2860 };
2861
2862
2863 /***************************************************************************/
2864
2865 extern JSObject*
2866 xpc_NewIDObject(JSContext *cx, JS::HandleObject jsobj, const nsID& aID);
2867
2868 extern const nsID*
2869 xpc_JSObjectToID(JSContext *cx, JSObject* obj);
2870
2871 extern bool
2872 xpc_JSObjectIsID(JSContext *cx, JSObject* obj);
2873
2874 /***************************************************************************/
2875 // in XPCDebug.cpp
2876
2877 extern bool
2878 xpc_DumpJSStack(JSContext* cx, bool showArgs, bool showLocals,
2879 bool showThisProps);
2880
2881 // Return a newly-allocated string containing a representation of the
2882 // current JS stack. It is the *caller's* responsibility to free this
2883 // string with JS_smprintf_free().
2884 extern char*
2885 xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals,
2886 bool showThisProps);
2887
2888 extern bool
2889 xpc_DumpEvalInJSStackFrame(JSContext* cx, uint32_t frameno, const char* text);
2890
2891 extern bool
2892 xpc_InstallJSDebuggerKeywordHandler(JSRuntime* rt);
2893
2894 /***************************************************************************/
2895
2896 // Definition of nsScriptError, defined here because we lack a place to put
2897 // XPCOM objects associated with the JavaScript engine.
2898 class nsScriptError : public nsIScriptError {
2899 public:
2900 nsScriptError();
2901
2902 virtual ~nsScriptError();
2903
2904 // TODO - do something reasonable on getting null from these babies.
2905
2906 NS_DECL_THREADSAFE_ISUPPORTS
2907 NS_DECL_NSICONSOLEMESSAGE
2908 NS_DECL_NSISCRIPTERROR
2909
2910 private:
2911 nsString mMessage;
2912 nsString mSourceName;
2913 uint32_t mLineNumber;
2914 nsString mSourceLine;
2915 uint32_t mColumnNumber;
2916 uint32_t mFlags;
2917 nsCString mCategory;
2918 uint64_t mOuterWindowID;
2919 uint64_t mInnerWindowID;
2920 int64_t mTimeStamp;
2921 bool mIsFromPrivateWindow;
2922 };
2923
2924 /******************************************************************************
2925 * Handles pre/post script processing and the setting/resetting the error
2926 * reporter
2927 */
2928 class MOZ_STACK_CLASS AutoScriptEvaluate
2929 {
2930 public:
2931 /**
2932 * Saves the JSContext as well as initializing our state
2933 * @param cx The JSContext, this can be null, we don't do anything then
2934 */
2935 AutoScriptEvaluate(JSContext * cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2936 : mJSContext(cx), mErrorReporterSet(false), mEvaluated(false) {
2937 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
2938 }
2939
2940 /**
2941 * Does the pre script evaluation and sets the error reporter if given
2942 * This function should only be called once, and will assert if called
2943 * more than once
2944 * @param errorReporter the error reporter callback function to set
2945 */
2946
2947 bool StartEvaluating(JS::HandleObject scope, JSErrorReporter errorReporter = nullptr);
2948
2949 /**
2950 * Does the post script evaluation and resets the error reporter
2951 */
2952 ~AutoScriptEvaluate();
2953 private:
2954 JSContext* mJSContext;
2955 mozilla::Maybe<JS::AutoSaveExceptionState> mState;
2956 bool mErrorReporterSet;
2957 bool mEvaluated;
2958 mozilla::Maybe<JSAutoCompartment> mAutoCompartment;
2959 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
2960
2961 // No copying or assignment allowed
2962 AutoScriptEvaluate(const AutoScriptEvaluate &) MOZ_DELETE;
2963 AutoScriptEvaluate & operator =(const AutoScriptEvaluate &) MOZ_DELETE;
2964 };
2965
2966 /***************************************************************************/
2967 class MOZ_STACK_CLASS AutoResolveName
2968 {
2969 public:
2970 AutoResolveName(XPCCallContext& ccx, JS::HandleId name
2971 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
2972 mOld(ccx, XPCJSRuntime::Get()->SetResolveName(name))
2973 #ifdef DEBUG
2974 ,mCheck(ccx, name)
2975 #endif
2976 {
2977 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
2978 }
2979 ~AutoResolveName()
2980 {
2981 #ifdef DEBUG
2982 jsid old =
2983 #endif
2984 XPCJSRuntime::Get()->SetResolveName(mOld);
2985 MOZ_ASSERT(old == mCheck, "Bad Nesting!");
2986 }
2987
2988 private:
2989 JS::RootedId mOld;
2990 #ifdef DEBUG
2991 JS::RootedId mCheck;
2992 #endif
2993 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
2994 };
2995
2996 /***************************************************************************/
2997 // AutoMarkingPtr is the base class for the various AutoMarking pointer types
2998 // below. This system allows us to temporarily protect instances of our garbage
2999 // collected types after they are constructed but before they are safely
3000 // attached to other rooted objects.
3001 // This base class has pure virtual support for marking.
3002
3003 class AutoMarkingPtr
3004 {
3005 public:
3006 AutoMarkingPtr(JSContext* cx) {
3007 mRoot = XPCJSRuntime::Get()->GetAutoRootsAdr();
3008 mNext = *mRoot;
3009 *mRoot = this;
3010 }
3011
3012 virtual ~AutoMarkingPtr() {
3013 if (mRoot) {
3014 MOZ_ASSERT(*mRoot == this);
3015 *mRoot = mNext;
3016 }
3017 }
3018
3019 void TraceJSAll(JSTracer* trc) {
3020 for (AutoMarkingPtr *cur = this; cur; cur = cur->mNext)
3021 cur->TraceJS(trc);
3022 }
3023
3024 void MarkAfterJSFinalizeAll() {
3025 for (AutoMarkingPtr *cur = this; cur; cur = cur->mNext)
3026 cur->MarkAfterJSFinalize();
3027 }
3028
3029 protected:
3030 virtual void TraceJS(JSTracer* trc) = 0;
3031 virtual void MarkAfterJSFinalize() = 0;
3032
3033 private:
3034 AutoMarkingPtr** mRoot;
3035 AutoMarkingPtr* mNext;
3036 };
3037
3038 template<class T>
3039 class TypedAutoMarkingPtr : public AutoMarkingPtr
3040 {
3041 public:
3042 TypedAutoMarkingPtr(JSContext* cx) : AutoMarkingPtr(cx), mPtr(nullptr) {}
3043 TypedAutoMarkingPtr(JSContext* cx, T* ptr) : AutoMarkingPtr(cx), mPtr(ptr) {}
3044
3045 T* get() const { return mPtr; }
3046 operator T *() const { return mPtr; }
3047 T* operator->() const { return mPtr; }
3048
3049 TypedAutoMarkingPtr<T>& operator =(T* ptr) { mPtr = ptr; return *this; }
3050
3051 protected:
3052 virtual void TraceJS(JSTracer* trc)
3053 {
3054 if (mPtr) {
3055 mPtr->TraceJS(trc);
3056 mPtr->AutoTrace(trc);
3057 }
3058 }
3059
3060 virtual void MarkAfterJSFinalize()
3061 {
3062 if (mPtr)
3063 mPtr->Mark();
3064 }
3065
3066 private:
3067 T* mPtr;
3068 };
3069
3070 typedef TypedAutoMarkingPtr<XPCNativeInterface> AutoMarkingNativeInterfacePtr;
3071 typedef TypedAutoMarkingPtr<XPCNativeSet> AutoMarkingNativeSetPtr;
3072 typedef TypedAutoMarkingPtr<XPCWrappedNative> AutoMarkingWrappedNativePtr;
3073 typedef TypedAutoMarkingPtr<XPCWrappedNativeTearOff> AutoMarkingWrappedNativeTearOffPtr;
3074 typedef TypedAutoMarkingPtr<XPCWrappedNativeProto> AutoMarkingWrappedNativeProtoPtr;
3075 typedef TypedAutoMarkingPtr<XPCNativeScriptableInfo> AutoMarkingNativeScriptableInfoPtr;
3076
3077 template<class T>
3078 class ArrayAutoMarkingPtr : public AutoMarkingPtr
3079 {
3080 public:
3081 ArrayAutoMarkingPtr(JSContext* cx)
3082 : AutoMarkingPtr(cx), mPtr(nullptr), mCount(0) {}
3083 ArrayAutoMarkingPtr(JSContext* cx, T** ptr, uint32_t count, bool clear)
3084 : AutoMarkingPtr(cx), mPtr(ptr), mCount(count)
3085 {
3086 if (!mPtr) mCount = 0;
3087 else if (clear) memset(mPtr, 0, mCount*sizeof(T*));
3088 }
3089
3090 T** get() const { return mPtr; }
3091 operator T **() const { return mPtr; }
3092 T** operator->() const { return mPtr; }
3093
3094 ArrayAutoMarkingPtr<T>& operator =(const ArrayAutoMarkingPtr<T> &other)
3095 {
3096 mPtr = other.mPtr;
3097 mCount = other.mCount;
3098 return *this;
3099 }
3100
3101 protected:
3102 virtual void TraceJS(JSTracer* trc)
3103 {
3104 for (uint32_t i = 0; i < mCount; i++) {
3105 if (mPtr[i]) {
3106 mPtr[i]->TraceJS(trc);
3107 mPtr[i]->AutoTrace(trc);
3108 }
3109 }
3110 }
3111
3112 virtual void MarkAfterJSFinalize()
3113 {
3114 for (uint32_t i = 0; i < mCount; i++) {
3115 if (mPtr[i])
3116 mPtr[i]->Mark();
3117 }
3118 }
3119
3120 private:
3121 T** mPtr;
3122 uint32_t mCount;
3123 };
3124
3125 typedef ArrayAutoMarkingPtr<XPCNativeInterface> AutoMarkingNativeInterfacePtrArrayPtr;
3126
3127 /***************************************************************************/
3128 namespace xpc {
3129 // Allocates a string that grants all access ("AllAccess")
3130 char *
3131 CloneAllAccess();
3132
3133 // Returns access if wideName is in list
3134 char *
3135 CheckAccessList(const char16_t *wideName, const char *const list[]);
3136 } /* namespace xpc */
3137
3138 /***************************************************************************/
3139 // in xpcvariant.cpp...
3140
3141 // {1809FD50-91E8-11d5-90F9-0010A4E73D9A}
3142 #define XPCVARIANT_IID \
3143 {0x1809fd50, 0x91e8, 0x11d5, \
3144 { 0x90, 0xf9, 0x0, 0x10, 0xa4, 0xe7, 0x3d, 0x9a } }
3145
3146 // {DC524540-487E-4501-9AC7-AAA784B17C1C}
3147 #define XPCVARIANT_CID \
3148 {0xdc524540, 0x487e, 0x4501, \
3149 { 0x9a, 0xc7, 0xaa, 0xa7, 0x84, 0xb1, 0x7c, 0x1c } }
3150
3151 class XPCVariant : public nsIVariant
3152 {
3153 public:
3154 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
3155 NS_DECL_NSIVARIANT
3156 NS_DECL_CYCLE_COLLECTION_CLASS(XPCVariant)
3157
3158 // If this class ever implements nsIWritableVariant, take special care with
3159 // the case when mJSVal is JSVAL_STRING, since we don't own the data in
3160 // that case.
3161
3162 // We #define and iid so that out module local code can use QI to detect
3163 // if a given nsIVariant is in fact an XPCVariant.
3164 NS_DECLARE_STATIC_IID_ACCESSOR(XPCVARIANT_IID)
3165
3166 static already_AddRefed<XPCVariant> newVariant(JSContext* cx, jsval aJSVal);
3167
3168 /**
3169 * This getter clears the gray bit before handing out the jsval if the jsval
3170 * represents a JSObject. That means that the object is guaranteed to be
3171 * kept alive past the next CC.
3172 */
3173 jsval GetJSVal() const {
3174 if (!JSVAL_IS_PRIMITIVE(mJSVal))
3175 JS::ExposeObjectToActiveJS(&mJSVal.toObject());
3176 return mJSVal;
3177 }
3178
3179 /**
3180 * This getter does not change the color of the jsval (if it represents a
3181 * JSObject) meaning that the value returned is not guaranteed to be kept
3182 * alive past the next CC.
3183 *
3184 * This should only be called if you are certain that the return value won't
3185 * be passed into a JS API function and that it won't be stored without
3186 * being rooted (or otherwise signaling the stored value to the CC).
3187 */
3188 jsval GetJSValPreserveColor() const {return mJSVal;}
3189
3190 XPCVariant(JSContext* cx, jsval aJSVal);
3191
3192 /**
3193 * Convert a variant into a jsval.
3194 *
3195 * @param ccx the context for the whole procedure
3196 * @param variant the variant to convert
3197 * @param scope the default scope to put on the new JSObject's parent chain
3198 * @param pErr [out] relevant error code, if any.
3199 * @param pJSVal [out] the resulting jsval.
3200 */
3201 static bool VariantDataToJS(nsIVariant* variant,
3202 nsresult* pErr, JS::MutableHandleValue pJSVal);
3203
3204 bool IsPurple()
3205 {
3206 return mRefCnt.IsPurple();
3207 }
3208
3209 void RemovePurple()
3210 {
3211 mRefCnt.RemovePurple();
3212 }
3213
3214 void SetCCGeneration(uint32_t aGen)
3215 {
3216 mCCGeneration = aGen;
3217 }
3218
3219 uint32_t CCGeneration() { return mCCGeneration; }
3220 protected:
3221 virtual ~XPCVariant() { }
3222
3223 bool InitializeData(JSContext* cx);
3224
3225 protected:
3226 nsDiscriminatedUnion mData;
3227 JS::Heap<JS::Value> mJSVal;
3228 bool mReturnRawObject : 1;
3229 uint32_t mCCGeneration : 31;
3230 };
3231
3232 NS_DEFINE_STATIC_IID_ACCESSOR(XPCVariant, XPCVARIANT_IID)
3233
3234 class XPCTraceableVariant: public XPCVariant,
3235 public XPCRootSetElem
3236 {
3237 public:
3238 XPCTraceableVariant(JSContext* cx, jsval aJSVal)
3239 : XPCVariant(cx, aJSVal)
3240 {
3241 nsXPConnect::GetRuntimeInstance()->AddVariantRoot(this);
3242 }
3243
3244 virtual ~XPCTraceableVariant();
3245
3246 void TraceJS(JSTracer* trc);
3247 static void GetTraceName(JSTracer* trc, char *buf, size_t bufsize);
3248 };
3249
3250 /***************************************************************************/
3251 // Utilities
3252
3253 inline void *
3254 xpc_GetJSPrivate(JSObject *obj)
3255 {
3256 return js::GetObjectPrivate(obj);
3257 }
3258
3259 inline JSContext *
3260 xpc_GetSafeJSContext()
3261 {
3262 return XPCJSRuntime::Get()->GetJSContextStack()->GetSafeJSContext();
3263 }
3264
3265 namespace xpc {
3266
3267 // JSNatives to expose atob and btoa in various non-DOM XPConnect scopes.
3268 bool
3269 Atob(JSContext *cx, unsigned argc, jsval *vp);
3270
3271 bool
3272 Btoa(JSContext *cx, unsigned argc, jsval *vp);
3273
3274
3275 // Helper function that creates a JSFunction that wraps a native function that
3276 // forwards the call to the original 'callable'. If the 'doclone' argument is
3277 // set, it also structure clones non-native arguments for extra security.
3278 bool
3279 NewFunctionForwarder(JSContext *cx, JS::HandleId id, JS::HandleObject callable,
3280 bool doclone, JS::MutableHandleValue vp);
3281
3282 bool
3283 NewFunctionForwarder(JSContext *cx, JS::HandleObject callable,
3284 bool doclone, JS::MutableHandleValue vp);
3285
3286 // Old fashioned xpc error reporter. Try to use JS_ReportError instead.
3287 nsresult
3288 ThrowAndFail(nsresult errNum, JSContext *cx, bool *retval);
3289
3290 struct GlobalProperties {
3291 GlobalProperties(bool aPromise) {
3292 mozilla::PodZero(this);
3293 Promise = true;
3294 }
3295 bool Parse(JSContext *cx, JS::HandleObject obj);
3296 bool Define(JSContext *cx, JS::HandleObject obj);
3297 bool Promise : 1;
3298 bool indexedDB : 1;
3299 bool XMLHttpRequest : 1;
3300 bool TextDecoder : 1;
3301 bool TextEncoder : 1;
3302 bool URL : 1;
3303 bool atob : 1;
3304 bool btoa : 1;
3305 };
3306
3307 // Infallible.
3308 already_AddRefed<nsIXPCComponents_utils_Sandbox>
3309 NewSandboxConstructor();
3310
3311 // Returns true if class of 'obj' is SandboxClass.
3312 bool
3313 IsSandbox(JSObject *obj);
3314
3315 class MOZ_STACK_CLASS OptionsBase {
3316 public:
3317 OptionsBase(JSContext *cx = xpc_GetSafeJSContext(),
3318 JSObject *options = nullptr)
3319 : mCx(cx)
3320 , mObject(cx, options)
3321 { }
3322
3323 virtual bool Parse() = 0;
3324
3325 protected:
3326 bool ParseValue(const char *name, JS::MutableHandleValue prop, bool *found = nullptr);
3327 bool ParseBoolean(const char *name, bool *prop);
3328 bool ParseObject(const char *name, JS::MutableHandleObject prop);
3329 bool ParseString(const char *name, nsCString &prop);
3330 bool ParseString(const char *name, nsString &prop);
3331 bool ParseId(const char* name, JS::MutableHandleId id);
3332
3333 JSContext *mCx;
3334 JS::RootedObject mObject;
3335 };
3336
3337 class MOZ_STACK_CLASS SandboxOptions : public OptionsBase {
3338 public:
3339 SandboxOptions(JSContext *cx = xpc_GetSafeJSContext(),
3340 JSObject *options = nullptr)
3341 : OptionsBase(cx, options)
3342 , wantXrays(true)
3343 , wantComponents(true)
3344 , wantExportHelpers(false)
3345 , proto(cx)
3346 , sameZoneAs(cx)
3347 , invisibleToDebugger(false)
3348 , discardSource(false)
3349 , globalProperties(true)
3350 , metadata(cx)
3351 { }
3352
3353 virtual bool Parse();
3354
3355 bool wantXrays;
3356 bool wantComponents;
3357 bool wantExportHelpers;
3358 JS::RootedObject proto;
3359 nsCString sandboxName;
3360 JS::RootedObject sameZoneAs;
3361 bool invisibleToDebugger;
3362 bool discardSource;
3363 GlobalProperties globalProperties;
3364 JS::RootedValue metadata;
3365
3366 protected:
3367 bool ParseGlobalProperties();
3368 };
3369
3370 class MOZ_STACK_CLASS CreateObjectInOptions : public OptionsBase {
3371 public:
3372 CreateObjectInOptions(JSContext *cx = xpc_GetSafeJSContext(),
3373 JSObject* options = nullptr)
3374 : OptionsBase(cx, options)
3375 , defineAs(cx, JSID_VOID)
3376 { }
3377
3378 virtual bool Parse() { return ParseId("defineAs", &defineAs); };
3379
3380 JS::RootedId defineAs;
3381 };
3382
3383 class MOZ_STACK_CLASS ExportOptions : public OptionsBase {
3384 public:
3385 ExportOptions(JSContext *cx = xpc_GetSafeJSContext(),
3386 JSObject* options = nullptr)
3387 : OptionsBase(cx, options)
3388 , defineAs(cx, JSID_VOID)
3389 { }
3390
3391 virtual bool Parse() { return ParseId("defineAs", &defineAs); };
3392
3393 JS::RootedId defineAs;
3394 };
3395
3396 JSObject *
3397 CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal,
3398 JS::CompartmentOptions& aOptions);
3399
3400 bool
3401 InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal,
3402 uint32_t aFlags);
3403
3404 // Helper for creating a sandbox object to use for evaluating
3405 // untrusted code completely separated from all other code in the
3406 // system using EvalInSandbox(). Takes the JSContext on which to
3407 // do setup etc on, puts the sandbox object in *vp (which must be
3408 // rooted by the caller), and uses the principal that's either
3409 // directly passed in prinOrSop or indirectly as an
3410 // nsIScriptObjectPrincipal holding the principal. If no principal is
3411 // reachable through prinOrSop, a new null principal will be created
3412 // and used.
3413 nsresult
3414 CreateSandboxObject(JSContext *cx, JS::MutableHandleValue vp, nsISupports *prinOrSop,
3415 xpc::SandboxOptions& options);
3416 // Helper for evaluating scripts in a sandbox object created with
3417 // CreateSandboxObject(). The caller is responsible of ensuring
3418 // that *rval doesn't get collected during the call or usage after the
3419 // call. This helper will use filename and lineNo for error reporting,
3420 // and if no filename is provided it will use the codebase from the
3421 // principal and line number 1 as a fallback. if returnStringOnly is
3422 // true, then the result in *rval, or the exception in cx->exception
3423 // will be coerced into strings. If an exception is thrown converting
3424 // an exception to a string, evalInSandbox will return an NS_ERROR_*
3425 // result, and cx->exception will be empty.
3426 nsresult
3427 EvalInSandbox(JSContext *cx, JS::HandleObject sandbox, const nsAString& source,
3428 const nsACString& filename, int32_t lineNo,
3429 JSVersion jsVersion, bool returnStringOnly,
3430 JS::MutableHandleValue rval);
3431
3432 // Helper for retrieving metadata stored in a reserved slot. The metadata
3433 // is set during the sandbox creation using the "metadata" option.
3434 nsresult
3435 GetSandboxMetadata(JSContext *cx, JS::HandleObject sandboxArg,
3436 JS::MutableHandleValue rval);
3437
3438 nsresult
3439 SetSandboxMetadata(JSContext *cx, JS::HandleObject sandboxArg,
3440 JS::HandleValue metadata);
3441
3442 bool
3443 CreateObjectIn(JSContext *cx, JS::HandleValue vobj, CreateObjectInOptions &options,
3444 JS::MutableHandleValue rval);
3445
3446 bool
3447 EvalInWindow(JSContext *cx, const nsAString &source, JS::HandleObject scope,
3448 JS::MutableHandleValue rval);
3449
3450 bool
3451 ExportFunction(JSContext *cx, JS::HandleValue vscope, JS::HandleValue vfunction,
3452 JS::HandleValue voptions, JS::MutableHandleValue rval);
3453
3454 bool
3455 CloneInto(JSContext *cx, JS::HandleValue vobj, JS::HandleValue vscope,
3456 JS::HandleValue voptions, JS::MutableHandleValue rval);
3457
3458 } /* namespace xpc */
3459
3460
3461 /***************************************************************************/
3462 // Inlined utilities.
3463
3464 inline bool
3465 xpc_ForcePropertyResolve(JSContext* cx, JS::HandleObject obj, jsid id);
3466
3467 inline jsid
3468 GetRTIdByIndex(JSContext *cx, unsigned index);
3469
3470 namespace xpc {
3471
3472 class CompartmentPrivate
3473 {
3474 public:
3475 enum LocationHint {
3476 LocationHintRegular,
3477 LocationHintAddon
3478 };
3479
3480 CompartmentPrivate(JSCompartment *c)
3481 : wantXrays(false)
3482 , universalXPConnectEnabled(false)
3483 , adoptedNode(false)
3484 , donatedNode(false)
3485 , scriptability(c)
3486 , scope(nullptr)
3487 {
3488 MOZ_COUNT_CTOR(xpc::CompartmentPrivate);
3489 }
3490
3491 ~CompartmentPrivate();
3492
3493 bool wantXrays;
3494
3495 // This is only ever set during mochitest runs when enablePrivilege is called.
3496 // It's intended as a temporary stopgap measure until we can finish ripping out
3497 // enablePrivilege. Once set, this value is never unset (i.e., it doesn't follow
3498 // the old scoping rules of enablePrivilege). Using it is inherently unsafe.
3499 bool universalXPConnectEnabled;
3500
3501 // for telemetry. See bug 928476.
3502 bool adoptedNode;
3503 bool donatedNode;
3504
3505 // The scriptability of this compartment.
3506 Scriptability scriptability;
3507
3508 // Our XPCWrappedNativeScope. This is non-null if and only if this is an
3509 // XPConnect compartment.
3510 XPCWrappedNativeScope *scope;
3511
3512 const nsACString& GetLocation() {
3513 if (location.IsEmpty() && locationURI) {
3514 if (NS_FAILED(locationURI->GetSpec(location)))
3515 location = NS_LITERAL_CSTRING("<unknown location>");
3516 }
3517 return location;
3518 }
3519 bool GetLocationURI(nsIURI **aURI) {
3520 return GetLocationURI(LocationHintRegular, aURI);
3521 }
3522 bool GetLocationURI(LocationHint aLocationHint, nsIURI **aURI) {
3523 if (locationURI) {
3524 nsCOMPtr<nsIURI> rval = locationURI;
3525 rval.forget(aURI);
3526 return true;
3527 }
3528 return TryParseLocationURI(aLocationHint, aURI);
3529 }
3530 void SetLocation(const nsACString& aLocation) {
3531 if (aLocation.IsEmpty())
3532 return;
3533 if (!location.IsEmpty() || locationURI)
3534 return;
3535 location = aLocation;
3536 }
3537 void SetLocationURI(nsIURI *aLocationURI) {
3538 if (!aLocationURI)
3539 return;
3540 if (locationURI)
3541 return;
3542 locationURI = aLocationURI;
3543 }
3544
3545 private:
3546 nsCString location;
3547 nsCOMPtr<nsIURI> locationURI;
3548
3549 bool TryParseLocationURI(LocationHint aType, nsIURI** aURI);
3550 };
3551
3552 CompartmentPrivate*
3553 EnsureCompartmentPrivate(JSObject *obj);
3554
3555 CompartmentPrivate*
3556 EnsureCompartmentPrivate(JSCompartment *c);
3557
3558 inline CompartmentPrivate*
3559 GetCompartmentPrivate(JSCompartment *compartment)
3560 {
3561 MOZ_ASSERT(compartment);
3562 void *priv = JS_GetCompartmentPrivate(compartment);
3563 return static_cast<CompartmentPrivate*>(priv);
3564 }
3565
3566 inline CompartmentPrivate*
3567 GetCompartmentPrivate(JSObject *object)
3568 {
3569 MOZ_ASSERT(object);
3570 JSCompartment *compartment = js::GetObjectCompartment(object);
3571
3572 MOZ_ASSERT(compartment);
3573 return GetCompartmentPrivate(compartment);
3574 }
3575
3576 bool IsUniversalXPConnectEnabled(JSCompartment *compartment);
3577 bool IsUniversalXPConnectEnabled(JSContext *cx);
3578 bool EnableUniversalXPConnect(JSContext *cx);
3579
3580 // This returns null if and only if it is called on an object in a non-XPConnect
3581 // compartment.
3582 inline XPCWrappedNativeScope*
3583 GetObjectScope(JSObject *obj)
3584 {
3585 return EnsureCompartmentPrivate(obj)->scope;
3586 }
3587
3588 // This returns null if a scope doesn't already exist.
3589 XPCWrappedNativeScope* MaybeGetObjectScope(JSObject *obj);
3590
3591 extern bool gDebugMode;
3592 extern bool gDesiredDebugMode;
3593
3594 extern const JSClass SafeJSContextGlobalClass;
3595
3596 JSObject* NewOutObject(JSContext* cx, JSObject* scope);
3597 bool IsOutObject(JSContext* cx, JSObject* obj);
3598
3599 nsresult HasInstance(JSContext *cx, JS::HandleObject objArg, const nsID *iid, bool *bp);
3600
3601 /**
3602 * Define quick stubs on the given object, @a proto.
3603 *
3604 * @param cx
3605 * A context. Requires request.
3606 * @param proto
3607 * The (newly created) prototype object for a DOM class. The JS half
3608 * of an XPCWrappedNativeProto.
3609 * @param flags
3610 * Property flags for the quick stub properties--should be either
3611 * JSPROP_ENUMERATE or 0.
3612 * @param interfaceCount
3613 * The number of interfaces the class implements.
3614 * @param interfaceArray
3615 * The interfaces the class implements; interfaceArray and
3616 * interfaceCount are like what nsIClassInfo.getInterfaces returns.
3617 */
3618 bool
3619 DOM_DefineQuickStubs(JSContext *cx, JSObject *proto, uint32_t flags,
3620 uint32_t interfaceCount, const nsIID **interfaceArray);
3621
3622 nsIPrincipal *GetObjectPrincipal(JSObject *obj);
3623
3624 } // namespace xpc
3625
3626 namespace mozilla {
3627 namespace dom {
3628 extern bool
3629 DefineStaticJSVals(JSContext *cx);
3630 } // namespace dom
3631 } // namespace mozilla
3632
3633 bool
3634 xpc_LocalizeRuntime(JSRuntime *rt);
3635 void
3636 xpc_DelocalizeRuntime(JSRuntime *rt);
3637
3638 /***************************************************************************/
3639 // Inlines use the above - include last.
3640
3641 #include "XPCInlines.h"
3642
3643 /***************************************************************************/
3644 // Maps have inlines that use the above - include last.
3645
3646 #include "XPCMaps.h"
3647
3648 /***************************************************************************/
3649
3650 #endif /* xpcprivate_h___ */

mercurial