js/xpconnect/src/xpcprivate.h

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

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

mercurial