Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 4 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #ifndef mozilla_dom_DOMJSClass_h |
michael@0 | 7 | #define mozilla_dom_DOMJSClass_h |
michael@0 | 8 | |
michael@0 | 9 | #include "jsfriendapi.h" |
michael@0 | 10 | #include "mozilla/Assertions.h" |
michael@0 | 11 | |
michael@0 | 12 | #include "mozilla/dom/PrototypeList.h" // auto-generated |
michael@0 | 13 | |
michael@0 | 14 | #include "mozilla/dom/JSSlots.h" |
michael@0 | 15 | |
michael@0 | 16 | class nsCycleCollectionParticipant; |
michael@0 | 17 | |
michael@0 | 18 | // All DOM globals must have a slot at DOM_PROTOTYPE_SLOT. |
michael@0 | 19 | #define DOM_PROTOTYPE_SLOT JSCLASS_GLOBAL_SLOT_COUNT |
michael@0 | 20 | |
michael@0 | 21 | // Keep this count up to date with any extra global slots added above. |
michael@0 | 22 | #define DOM_GLOBAL_SLOTS 1 |
michael@0 | 23 | |
michael@0 | 24 | // We use these flag bits for the new bindings. |
michael@0 | 25 | #define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT1 |
michael@0 | 26 | #define JSCLASS_IS_DOMIFACEANDPROTOJSCLASS JSCLASS_USERBIT2 |
michael@0 | 27 | |
michael@0 | 28 | namespace mozilla { |
michael@0 | 29 | namespace dom { |
michael@0 | 30 | |
michael@0 | 31 | typedef bool |
michael@0 | 32 | (* ResolveOwnProperty)(JSContext* cx, JS::Handle<JSObject*> wrapper, |
michael@0 | 33 | JS::Handle<JSObject*> obj, JS::Handle<jsid> id, |
michael@0 | 34 | JS::MutableHandle<JSPropertyDescriptor> desc); |
michael@0 | 35 | |
michael@0 | 36 | typedef bool |
michael@0 | 37 | (* EnumerateOwnProperties)(JSContext* cx, JS::Handle<JSObject*> wrapper, |
michael@0 | 38 | JS::Handle<JSObject*> obj, |
michael@0 | 39 | JS::AutoIdVector& props); |
michael@0 | 40 | |
michael@0 | 41 | struct ConstantSpec |
michael@0 | 42 | { |
michael@0 | 43 | const char* name; |
michael@0 | 44 | JS::Value value; |
michael@0 | 45 | }; |
michael@0 | 46 | |
michael@0 | 47 | typedef bool (*PropertyEnabled)(JSContext* cx, JSObject* global); |
michael@0 | 48 | |
michael@0 | 49 | template<typename T> |
michael@0 | 50 | struct Prefable { |
michael@0 | 51 | inline bool isEnabled(JSContext* cx, JSObject* obj) const { |
michael@0 | 52 | if (!enabled) { |
michael@0 | 53 | return false; |
michael@0 | 54 | } |
michael@0 | 55 | if (!enabledFunc && !availableFunc) { |
michael@0 | 56 | return true; |
michael@0 | 57 | } |
michael@0 | 58 | // Just go ahead and root obj, in case enabledFunc GCs |
michael@0 | 59 | JS::Rooted<JSObject*> rootedObj(cx, obj); |
michael@0 | 60 | if (enabledFunc && |
michael@0 | 61 | !enabledFunc(cx, js::GetGlobalForObjectCrossCompartment(rootedObj))) { |
michael@0 | 62 | return false; |
michael@0 | 63 | } |
michael@0 | 64 | if (availableFunc && |
michael@0 | 65 | !availableFunc(cx, js::GetGlobalForObjectCrossCompartment(rootedObj))) { |
michael@0 | 66 | return false; |
michael@0 | 67 | } |
michael@0 | 68 | return true; |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | // A boolean indicating whether this set of specs is enabled |
michael@0 | 72 | bool enabled; |
michael@0 | 73 | // A function pointer to a function that can say the property is disabled |
michael@0 | 74 | // even if "enabled" is set to true. If the pointer is null the value of |
michael@0 | 75 | // "enabled" is used as-is unless availableFunc overrides. |
michael@0 | 76 | PropertyEnabled enabledFunc; |
michael@0 | 77 | // A function pointer to a function that can be used to disable a |
michael@0 | 78 | // property even if "enabled" is true and enabledFunc allowed. This |
michael@0 | 79 | // is basically a hack to avoid having to codegen PropertyEnabled |
michael@0 | 80 | // implementations in case when we need to do two separate checks. |
michael@0 | 81 | PropertyEnabled availableFunc; |
michael@0 | 82 | // Array of specs, terminated in whatever way is customary for T. |
michael@0 | 83 | // Null to indicate a end-of-array for Prefable, when such an |
michael@0 | 84 | // indicator is needed. |
michael@0 | 85 | const T* specs; |
michael@0 | 86 | }; |
michael@0 | 87 | |
michael@0 | 88 | struct NativeProperties |
michael@0 | 89 | { |
michael@0 | 90 | const Prefable<const JSFunctionSpec>* staticMethods; |
michael@0 | 91 | jsid* staticMethodIds; |
michael@0 | 92 | const JSFunctionSpec* staticMethodsSpecs; |
michael@0 | 93 | const Prefable<const JSPropertySpec>* staticAttributes; |
michael@0 | 94 | jsid* staticAttributeIds; |
michael@0 | 95 | const JSPropertySpec* staticAttributeSpecs; |
michael@0 | 96 | const Prefable<const JSFunctionSpec>* methods; |
michael@0 | 97 | jsid* methodIds; |
michael@0 | 98 | const JSFunctionSpec* methodsSpecs; |
michael@0 | 99 | const Prefable<const JSPropertySpec>* attributes; |
michael@0 | 100 | jsid* attributeIds; |
michael@0 | 101 | const JSPropertySpec* attributeSpecs; |
michael@0 | 102 | const Prefable<const JSPropertySpec>* unforgeableAttributes; |
michael@0 | 103 | jsid* unforgeableAttributeIds; |
michael@0 | 104 | const JSPropertySpec* unforgeableAttributeSpecs; |
michael@0 | 105 | const Prefable<const ConstantSpec>* constants; |
michael@0 | 106 | jsid* constantIds; |
michael@0 | 107 | const ConstantSpec* constantSpecs; |
michael@0 | 108 | }; |
michael@0 | 109 | |
michael@0 | 110 | struct NativePropertiesHolder |
michael@0 | 111 | { |
michael@0 | 112 | const NativeProperties* regular; |
michael@0 | 113 | const NativeProperties* chromeOnly; |
michael@0 | 114 | }; |
michael@0 | 115 | |
michael@0 | 116 | // Helper structure for Xrays for DOM binding objects. The same instance is used |
michael@0 | 117 | // for instances, interface objects and interface prototype objects of a |
michael@0 | 118 | // specific interface. |
michael@0 | 119 | struct NativePropertyHooks |
michael@0 | 120 | { |
michael@0 | 121 | // The hook to call for resolving indexed or named properties. May be null if |
michael@0 | 122 | // there can't be any. |
michael@0 | 123 | ResolveOwnProperty mResolveOwnProperty; |
michael@0 | 124 | // The hook to call for enumerating indexed or named properties. May be null |
michael@0 | 125 | // if there can't be any. |
michael@0 | 126 | EnumerateOwnProperties mEnumerateOwnProperties; |
michael@0 | 127 | |
michael@0 | 128 | // The property arrays for this interface. |
michael@0 | 129 | NativePropertiesHolder mNativeProperties; |
michael@0 | 130 | |
michael@0 | 131 | // This will be set to the ID of the interface prototype object for the |
michael@0 | 132 | // interface, if it has one. If it doesn't have one it will be set to |
michael@0 | 133 | // prototypes::id::_ID_Count. |
michael@0 | 134 | prototypes::ID mPrototypeID; |
michael@0 | 135 | |
michael@0 | 136 | // This will be set to the ID of the interface object for the interface, if it |
michael@0 | 137 | // has one. If it doesn't have one it will be set to |
michael@0 | 138 | // constructors::id::_ID_Count. |
michael@0 | 139 | constructors::ID mConstructorID; |
michael@0 | 140 | |
michael@0 | 141 | // The NativePropertyHooks instance for the parent interface. |
michael@0 | 142 | const NativePropertyHooks* mProtoHooks; |
michael@0 | 143 | }; |
michael@0 | 144 | |
michael@0 | 145 | enum DOMObjectType { |
michael@0 | 146 | eInstance, |
michael@0 | 147 | eInterface, |
michael@0 | 148 | eInterfacePrototype |
michael@0 | 149 | }; |
michael@0 | 150 | |
michael@0 | 151 | typedef JSObject* (*ParentGetter)(JSContext* aCx, JS::Handle<JSObject*> aObj); |
michael@0 | 152 | /** |
michael@0 | 153 | * Returns a handle to the relevent WebIDL prototype object for the given global |
michael@0 | 154 | * (which may be a handle to null on out of memory). Once allocated, the |
michael@0 | 155 | * prototype object is guaranteed to exist as long as the global does, since the |
michael@0 | 156 | * global traces its array of WebIDL prototypes and constructors. |
michael@0 | 157 | */ |
michael@0 | 158 | typedef JS::Handle<JSObject*> (*ProtoGetter)(JSContext* aCx, |
michael@0 | 159 | JS::Handle<JSObject*> aGlobal); |
michael@0 | 160 | |
michael@0 | 161 | struct DOMClass |
michael@0 | 162 | { |
michael@0 | 163 | // A list of interfaces that this object implements, in order of decreasing |
michael@0 | 164 | // derivedness. |
michael@0 | 165 | const prototypes::ID mInterfaceChain[MAX_PROTOTYPE_CHAIN_LENGTH]; |
michael@0 | 166 | |
michael@0 | 167 | // We store the DOM object in reserved slot with index DOM_OBJECT_SLOT or in |
michael@0 | 168 | // the proxy private if we use a proxy object. |
michael@0 | 169 | // Sometimes it's an nsISupports and sometimes it's not; this class tells |
michael@0 | 170 | // us which it is. |
michael@0 | 171 | const bool mDOMObjectIsISupports; |
michael@0 | 172 | |
michael@0 | 173 | const NativePropertyHooks* mNativeHooks; |
michael@0 | 174 | |
michael@0 | 175 | ParentGetter mGetParent; |
michael@0 | 176 | ProtoGetter mGetProto; |
michael@0 | 177 | |
michael@0 | 178 | // This stores the CC participant for the native, null if this class is for a |
michael@0 | 179 | // worker or for a native inheriting from nsISupports (we can get the CC |
michael@0 | 180 | // participant by QI'ing in that case). |
michael@0 | 181 | nsCycleCollectionParticipant* mParticipant; |
michael@0 | 182 | }; |
michael@0 | 183 | |
michael@0 | 184 | // Special JSClass for reflected DOM objects. |
michael@0 | 185 | struct DOMJSClass |
michael@0 | 186 | { |
michael@0 | 187 | // It would be nice to just inherit from JSClass, but that precludes pure |
michael@0 | 188 | // compile-time initialization of the form |DOMJSClass = {...};|, since C++ |
michael@0 | 189 | // only allows brace initialization for aggregate/POD types. |
michael@0 | 190 | const js::Class mBase; |
michael@0 | 191 | |
michael@0 | 192 | const DOMClass mClass; |
michael@0 | 193 | |
michael@0 | 194 | static const DOMJSClass* FromJSClass(const JSClass* base) { |
michael@0 | 195 | MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS); |
michael@0 | 196 | return reinterpret_cast<const DOMJSClass*>(base); |
michael@0 | 197 | } |
michael@0 | 198 | |
michael@0 | 199 | static const DOMJSClass* FromJSClass(const js::Class* base) { |
michael@0 | 200 | return FromJSClass(Jsvalify(base)); |
michael@0 | 201 | } |
michael@0 | 202 | |
michael@0 | 203 | const JSClass* ToJSClass() const { return Jsvalify(&mBase); } |
michael@0 | 204 | }; |
michael@0 | 205 | |
michael@0 | 206 | // Special JSClass for DOM interface and interface prototype objects. |
michael@0 | 207 | struct DOMIfaceAndProtoJSClass |
michael@0 | 208 | { |
michael@0 | 209 | // It would be nice to just inherit from JSClass, but that precludes pure |
michael@0 | 210 | // compile-time initialization of the form |
michael@0 | 211 | // |DOMJSInterfaceAndPrototypeClass = {...};|, since C++ only allows brace |
michael@0 | 212 | // initialization for aggregate/POD types. |
michael@0 | 213 | const JSClass mBase; |
michael@0 | 214 | |
michael@0 | 215 | // Either eInterface or eInterfacePrototype |
michael@0 | 216 | DOMObjectType mType; |
michael@0 | 217 | |
michael@0 | 218 | const NativePropertyHooks* mNativeHooks; |
michael@0 | 219 | |
michael@0 | 220 | // The value to return for toString() on this interface or interface prototype |
michael@0 | 221 | // object. |
michael@0 | 222 | const char* mToString; |
michael@0 | 223 | |
michael@0 | 224 | const prototypes::ID mPrototypeID; |
michael@0 | 225 | const uint32_t mDepth; |
michael@0 | 226 | |
michael@0 | 227 | static const DOMIfaceAndProtoJSClass* FromJSClass(const JSClass* base) { |
michael@0 | 228 | MOZ_ASSERT(base->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS); |
michael@0 | 229 | return reinterpret_cast<const DOMIfaceAndProtoJSClass*>(base); |
michael@0 | 230 | } |
michael@0 | 231 | static const DOMIfaceAndProtoJSClass* FromJSClass(const js::Class* base) { |
michael@0 | 232 | return FromJSClass(Jsvalify(base)); |
michael@0 | 233 | } |
michael@0 | 234 | |
michael@0 | 235 | const JSClass* ToJSClass() const { return &mBase; } |
michael@0 | 236 | }; |
michael@0 | 237 | |
michael@0 | 238 | class ProtoAndIfaceCache; |
michael@0 | 239 | |
michael@0 | 240 | inline bool |
michael@0 | 241 | HasProtoAndIfaceCache(JSObject* global) |
michael@0 | 242 | { |
michael@0 | 243 | MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL); |
michael@0 | 244 | // This can be undefined if we GC while creating the global |
michael@0 | 245 | return !js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).isUndefined(); |
michael@0 | 246 | } |
michael@0 | 247 | |
michael@0 | 248 | inline ProtoAndIfaceCache* |
michael@0 | 249 | GetProtoAndIfaceCache(JSObject* global) |
michael@0 | 250 | { |
michael@0 | 251 | MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL); |
michael@0 | 252 | return static_cast<ProtoAndIfaceCache*>( |
michael@0 | 253 | js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).toPrivate()); |
michael@0 | 254 | } |
michael@0 | 255 | |
michael@0 | 256 | } // namespace dom |
michael@0 | 257 | } // namespace mozilla |
michael@0 | 258 | |
michael@0 | 259 | #endif /* mozilla_dom_DOMJSClass_h */ |