Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/dom/DOMJSClass.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef mozilla_dom_DOMJSClass_h
8
#define mozilla_dom_DOMJSClass_h
9
10
#include "jsapi.h"
11
#include "jsfriendapi.h"
12
#include "js/Wrapper.h"
13
#include "mozilla/Assertions.h"
14
#include "mozilla/Attributes.h"
15
#include "mozilla/Likely.h"
16
17
#include "mozilla/dom/PrototypeList.h" // auto-generated
18
19
#include "mozilla/dom/JSSlots.h"
20
21
class nsCycleCollectionParticipant;
22
23
// All DOM globals must have a slot at DOM_PROTOTYPE_SLOT.
24
118
#define DOM_PROTOTYPE_SLOT JSCLASS_GLOBAL_SLOT_COUNT
25
26
// Keep this count up to date with any extra global slots added above.
27
3
#define DOM_GLOBAL_SLOTS 1
28
29
// We use these flag bits for the new bindings.
30
3.11M
#define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT1
31
0
#define JSCLASS_IS_DOMIFACEANDPROTOJSCLASS JSCLASS_USERBIT2
32
33
namespace mozilla {
34
namespace dom {
35
36
/**
37
 * Returns true if code running in the given JSContext is allowed to access
38
 * [SecureContext] API on the given JSObject.
39
 *
40
 * [SecureContext] API exposure is restricted to use by code in a Secure
41
 * Contexts:
42
 *
43
 *   https://w3c.github.io/webappsec-secure-contexts/
44
 *
45
 * Since we want [SecureContext] exposure to depend on the privileges of the
46
 * running code (rather than the privileges of an object's creator), this
47
 * function checks to see whether the given JSContext's Realm is flagged
48
 * as a Secure Context.  That allows us to make sure that system principal code
49
 * (which is marked as a Secure Context) can access Secure Context API on an
50
 * object in a different realm, regardless of whether the other realm is a
51
 * Secure Context or not.
52
 *
53
 * Checking the JSContext's Realm doesn't work for expanded principal
54
 * globals accessing a Secure Context web page though (e.g. those used by frame
55
 * scripts).  To handle that we fall back to checking whether the JSObject came
56
 * from a Secure Context.
57
 *
58
 * Note: We'd prefer this function to live in BindingUtils.h, but we need to
59
 * call it in this header, and BindingUtils.h includes us (i.e. we'd have a
60
 * circular dependency between headers if it lived there).
61
 */
62
inline bool
63
IsSecureContextOrObjectIsFromSecureContext(JSContext* aCx, JSObject* aObj)
64
0
{
65
0
  MOZ_ASSERT(!js::IsWrapper(aObj));
66
0
  return JS::GetIsSecureContext(js::GetContextRealm(aCx)) ||
67
0
         JS::GetIsSecureContext(js::GetNonCCWObjectRealm(aObj));
68
0
}
69
70
typedef bool
71
(* ResolveOwnProperty)(JSContext* cx, JS::Handle<JSObject*> wrapper,
72
                       JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
73
                       JS::MutableHandle<JS::PropertyDescriptor> desc);
74
75
typedef bool
76
(* EnumerateOwnProperties)(JSContext* cx, JS::Handle<JSObject*> wrapper,
77
                           JS::Handle<JSObject*> obj,
78
                           JS::AutoIdVector& props);
79
80
typedef bool
81
(* DeleteNamedProperty)(JSContext* cx, JS::Handle<JSObject*> wrapper,
82
                        JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
83
                        JS::ObjectOpResult& opresult);
84
85
// Returns true if the given global is of a type whose bit is set in
86
// aNonExposedGlobals.
87
bool
88
IsNonExposedGlobal(JSContext* aCx, JSObject* aGlobal,
89
                   uint32_t aNonExposedGlobals);
90
91
struct ConstantSpec
92
{
93
  const char* name;
94
  JS::Value value;
95
};
96
97
typedef bool (*PropertyEnabled)(JSContext* cx, JSObject* global);
98
99
namespace GlobalNames {
100
// The names of our possible globals.  These are the names of the actual
101
// interfaces, not of the global names used to refer to them in IDL [Exposed]
102
// annotations.
103
static const uint32_t Window = 1u << 0;
104
static const uint32_t BackstagePass = 1u << 1;
105
static const uint32_t DedicatedWorkerGlobalScope = 1u << 2;
106
static const uint32_t SharedWorkerGlobalScope = 1u << 3;
107
static const uint32_t ServiceWorkerGlobalScope = 1u << 4;
108
static const uint32_t WorkerDebuggerGlobalScope = 1u << 5;
109
static const uint32_t WorkletGlobalScope = 1u << 6;
110
static const uint32_t AudioWorkletGlobalScope = 1u << 7;
111
} // namespace GlobalNames
112
113
struct PrefableDisablers {
114
4
  inline bool isEnabled(JSContext* cx, JS::Handle<JSObject*> obj) const {
115
4
    // Reading "enabled" on a worker thread is technically undefined behavior,
116
4
    // because it's written only on main threads, with no barriers of any sort.
117
4
    // So we want to avoid doing that.  But we don't particularly want to make
118
4
    // expensive NS_IsMainThread calls here.
119
4
    //
120
4
    // The good news is that "enabled" is only written for things that have a
121
4
    // Pref annotation, and such things can never be exposed on non-Window
122
4
    // globals; our IDL parser enforces that.  So as long as we check our
123
4
    // exposure set before checking "enabled" we will be ok.
124
4
    if (nonExposedGlobals &&
125
4
        IsNonExposedGlobal(cx, JS::GetNonCCWObjectGlobal(obj),
126
4
                           nonExposedGlobals)) {
127
0
      return false;
128
0
    }
129
4
    if (!enabled) {
130
0
      return false;
131
0
    }
132
4
    if (secureContext && !IsSecureContextOrObjectIsFromSecureContext(cx, obj)) {
133
0
      return false;
134
0
    }
135
4
    if (enabledFunc && !enabledFunc(cx, JS::GetNonCCWObjectGlobal(obj))) {
136
1
      return false;
137
1
    }
138
3
    return true;
139
3
  }
140
141
  // A boolean indicating whether this set of specs is enabled. Not const
142
  // because it will change at runtime if the corresponding pref is changed.
143
  bool enabled;
144
145
  // A boolean indicating whether a Secure Context is required.
146
  const bool secureContext;
147
148
  // Bitmask of global names that we should not be exposed in.
149
  const uint16_t nonExposedGlobals;
150
151
  // A function pointer to a function that can say the property is disabled
152
  // even if "enabled" is set to true.  If the pointer is null the value of
153
  // "enabled" is used as-is.
154
  const PropertyEnabled enabledFunc;
155
};
156
157
template<typename T>
158
struct Prefable {
159
6
  inline bool isEnabled(JSContext* cx, JS::Handle<JSObject*> obj) const {
160
6
    MOZ_ASSERT(!js::IsWrapper(obj));
161
6
    if (MOZ_LIKELY(!disablers)) {
162
2
      return true;
163
2
    }
164
4
    return disablers->isEnabled(cx, obj);
165
4
  }
mozilla::dom::Prefable<JSFunctionSpec const>::isEnabled(JSContext*, JS::Handle<JSObject*>) const
Line
Count
Source
159
5
  inline bool isEnabled(JSContext* cx, JS::Handle<JSObject*> obj) const {
160
5
    MOZ_ASSERT(!js::IsWrapper(obj));
161
5
    if (MOZ_LIKELY(!disablers)) {
162
1
      return true;
163
1
    }
164
4
    return disablers->isEnabled(cx, obj);
165
4
  }
mozilla::dom::Prefable<JSPropertySpec const>::isEnabled(JSContext*, JS::Handle<JSObject*>) const
Line
Count
Source
159
1
  inline bool isEnabled(JSContext* cx, JS::Handle<JSObject*> obj) const {
160
1
    MOZ_ASSERT(!js::IsWrapper(obj));
161
1
    if (MOZ_LIKELY(!disablers)) {
162
1
      return true;
163
1
    }
164
0
    return disablers->isEnabled(cx, obj);
165
0
  }
Unexecuted instantiation: mozilla::dom::Prefable<mozilla::dom::ConstantSpec const>::isEnabled(JSContext*, JS::Handle<JSObject*>) const
166
167
  // Things that can disable this set of specs. |nullptr| means "cannot be
168
  // disabled".
169
  PrefableDisablers* const disablers;
170
171
  // Array of specs, terminated in whatever way is customary for T.
172
  // Null to indicate a end-of-array for Prefable, when such an
173
  // indicator is needed.
174
  const T* const specs;
175
};
176
177
enum PropertyType {
178
  eStaticMethod,
179
  eStaticAttribute,
180
  eMethod,
181
  eAttribute,
182
  eUnforgeableMethod,
183
  eUnforgeableAttribute,
184
  eConstant,
185
  ePropertyTypeCount
186
};
187
188
#define NUM_BITS_PROPERTY_INFO_TYPE        3
189
#define NUM_BITS_PROPERTY_INFO_PREF_INDEX 13
190
#define NUM_BITS_PROPERTY_INFO_SPEC_INDEX 16
191
192
struct PropertyInfo {
193
private:
194
  // MSVC generates static initializers if we store a jsid here, even if
195
  // PropertyInfo has a constexpr constructor. See bug 1460341 and bug 1464036.
196
  uintptr_t mIdBits;
197
public:
198
  // One of PropertyType, will be used for accessing the corresponding Duo in
199
  // NativePropertiesN.duos[].
200
  uint32_t type: NUM_BITS_PROPERTY_INFO_TYPE;
201
  // The index to the corresponding Preable in Duo.mPrefables[].
202
  uint32_t prefIndex: NUM_BITS_PROPERTY_INFO_PREF_INDEX;
203
  // The index to the corresponding spec in Duo.mPrefables[prefIndex].specs[].
204
  uint32_t specIndex: NUM_BITS_PROPERTY_INFO_SPEC_INDEX;
205
206
28
  void SetId(jsid aId) {
207
28
    static_assert(sizeof(jsid) == sizeof(mIdBits), "jsid should fit in mIdBits");
208
28
    mIdBits = JSID_BITS(aId);
209
28
  }
210
200
  MOZ_ALWAYS_INLINE jsid Id() const {
211
200
    return jsid::fromRawBits(mIdBits);
212
200
  }
213
};
214
215
static_assert(ePropertyTypeCount <= 1ull << NUM_BITS_PROPERTY_INFO_TYPE,
216
    "We have property type count that is > (1 << NUM_BITS_PROPERTY_INFO_TYPE)");
217
218
// Conceptually, NativeProperties has seven (Prefable<T>*, PropertyInfo*) duos
219
// (where T is one of JSFunctionSpec, JSPropertySpec, or ConstantSpec), one for
220
// each of: static methods and attributes, methods and attributes, unforgeable
221
// methods and attributes, and constants.
222
//
223
// That's 14 pointers, but in most instances most of the duos are all null, and
224
// there are many instances. To save space we use a variable-length type,
225
// NativePropertiesN<N>, to hold the data and getters to access it. It has N
226
// actual duos (stored in duos[]), plus four bits for each of the 7 possible
227
// duos: 1 bit that states if that duo is present, and 3 that state that duo's
228
// offset (if present) in duos[].
229
//
230
// All duo accesses should be done via the getters, which contain assertions
231
// that check we don't overrun the end of the struct. (The duo data members are
232
// public only so they can be statically initialized.) These assertions should
233
// never fail so long as (a) accesses to the variable-length part are guarded by
234
// appropriate Has*() calls, and (b) all instances are well-formed, i.e. the
235
// value of N matches the number of mHas* members that are true.
236
//
237
// We store all the property ids a NativePropertiesN owns in a single array of
238
// PropertyInfo structs. Each struct contains an id and the information needed
239
// to find the corresponding Prefable for the enabled check, as well as the
240
// information needed to find the correct property descriptor in the
241
// Prefable. We also store an array of indices into the PropertyInfo array,
242
// sorted by bits of the corresponding jsid. Given a jsid, this allows us to
243
// binary search for the index of the corresponding PropertyInfo, if any.
244
//
245
// Finally, we define a typedef of NativePropertiesN<7>, NativeProperties, which
246
// we use as a "base" type used to refer to all instances of NativePropertiesN.
247
// (7 is used because that's the maximum valid parameter, though any other
248
// value 1..6 could also be used.) This is reasonable because of the
249
// aforementioned assertions in the getters. Upcast() is used to convert
250
// specific instances to this "base" type.
251
//
252
template <int N>
253
struct NativePropertiesN {
254
  // Duo structs are stored in the duos[] array, and each element in the array
255
  // could require a different T. Therefore, we can't use the correct type for
256
  // mPrefables. Instead we use void* and cast to the correct type in the
257
  // getters.
258
  struct Duo {
259
    const /*Prefable<const T>*/ void* const mPrefables;
260
    PropertyInfo* const mPropertyInfos;
261
  };
262
263
4
  constexpr const NativePropertiesN<7>* Upcast() const {
264
4
    return reinterpret_cast<const NativePropertiesN<7>*>(this);
265
4
  }
mozilla::dom::NativePropertiesN<1>::Upcast() const
Line
Count
Source
263
2
  constexpr const NativePropertiesN<7>* Upcast() const {
264
2
    return reinterpret_cast<const NativePropertiesN<7>*>(this);
265
2
  }
mozilla::dom::NativePropertiesN<2>::Upcast() const
Line
Count
Source
263
2
  constexpr const NativePropertiesN<7>* Upcast() const {
264
2
    return reinterpret_cast<const NativePropertiesN<7>*>(this);
265
2
  }
Unexecuted instantiation: mozilla::dom::NativePropertiesN<3>::Upcast() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<4>::Upcast() const
266
267
2
  const PropertyInfo* PropertyInfos() const {
268
2
    return duos[0].mPropertyInfos;
269
2
  }
270
271
#define DO(SpecT, FieldName) \
272
public: \
273
  /* The bitfields indicating the duo's presence and (if present) offset. */ \
274
  const uint32_t mHas##FieldName##s:1; \
275
  const uint32_t m##FieldName##sOffset:3; \
276
private: \
277
9
  const Duo* FieldName##sDuo() const { \
278
9
    MOZ_ASSERT(Has##FieldName##s()); \
279
9
    return &duos[m##FieldName##sOffset]; \
280
9
  } \
mozilla::dom::NativePropertiesN<7>::StaticMethodsDuo() const
Line
Count
Source
277
6
  const Duo* FieldName##sDuo() const { \
278
6
    MOZ_ASSERT(Has##FieldName##s()); \
279
6
    return &duos[m##FieldName##sOffset]; \
280
6
  } \
mozilla::dom::NativePropertiesN<7>::StaticAttributesDuo() const
Line
Count
Source
277
3
  const Duo* FieldName##sDuo() const { \
278
3
    MOZ_ASSERT(Has##FieldName##s()); \
279
3
    return &duos[m##FieldName##sOffset]; \
280
3
  } \
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::ConstantsDuo() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::MethodsDuo() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::AttributesDuo() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::UnforgeableMethodsDuo() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::UnforgeableAttributesDuo() const
281
public: \
282
20
  bool Has##FieldName##s() const { \
283
20
    return mHas##FieldName##s; \
284
20
  } \
mozilla::dom::NativePropertiesN<7>::HasStaticMethods() const
Line
Count
Source
282
4
  bool Has##FieldName##s() const { \
283
4
    return mHas##FieldName##s; \
284
4
  } \
mozilla::dom::NativePropertiesN<7>::HasStaticAttributes() const
Line
Count
Source
282
4
  bool Has##FieldName##s() const { \
283
4
    return mHas##FieldName##s; \
284
4
  } \
mozilla::dom::NativePropertiesN<7>::HasConstants() const
Line
Count
Source
282
4
  bool Has##FieldName##s() const { \
283
4
    return mHas##FieldName##s; \
284
4
  } \
mozilla::dom::NativePropertiesN<7>::HasMethods() const
Line
Count
Source
282
2
  bool Has##FieldName##s() const { \
283
2
    return mHas##FieldName##s; \
284
2
  } \
mozilla::dom::NativePropertiesN<7>::HasAttributes() const
Line
Count
Source
282
2
  bool Has##FieldName##s() const { \
283
2
    return mHas##FieldName##s; \
284
2
  } \
mozilla::dom::NativePropertiesN<7>::HasUnforgeableMethods() const
Line
Count
Source
282
2
  bool Has##FieldName##s() const { \
283
2
    return mHas##FieldName##s; \
284
2
  } \
mozilla::dom::NativePropertiesN<7>::HasUnforgeableAttributes() const
Line
Count
Source
282
2
  bool Has##FieldName##s() const { \
283
2
    return mHas##FieldName##s; \
284
2
  } \
285
6
  const Prefable<const SpecT>* FieldName##s() const { \
286
6
    return static_cast<const Prefable<const SpecT>*> \
287
6
                      (FieldName##sDuo()->mPrefables); \
288
6
  } \
mozilla::dom::NativePropertiesN<7>::StaticMethods() const
Line
Count
Source
285
4
  const Prefable<const SpecT>* FieldName##s() const { \
286
4
    return static_cast<const Prefable<const SpecT>*> \
287
4
                      (FieldName##sDuo()->mPrefables); \
288
4
  } \
mozilla::dom::NativePropertiesN<7>::StaticAttributes() const
Line
Count
Source
285
2
  const Prefable<const SpecT>* FieldName##s() const { \
286
2
    return static_cast<const Prefable<const SpecT>*> \
287
2
                      (FieldName##sDuo()->mPrefables); \
288
2
  } \
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::Constants() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::Methods() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::Attributes() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::UnforgeableMethods() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::UnforgeableAttributes() const
289
3
  PropertyInfo* FieldName##PropertyInfos() const { \
290
3
    return FieldName##sDuo()->mPropertyInfos; \
291
3
  }
mozilla::dom::NativePropertiesN<7>::StaticMethodPropertyInfos() const
Line
Count
Source
289
2
  PropertyInfo* FieldName##PropertyInfos() const { \
290
2
    return FieldName##sDuo()->mPropertyInfos; \
291
2
  }
mozilla::dom::NativePropertiesN<7>::StaticAttributePropertyInfos() const
Line
Count
Source
289
1
  PropertyInfo* FieldName##PropertyInfos() const { \
290
1
    return FieldName##sDuo()->mPropertyInfos; \
291
1
  }
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::MethodPropertyInfos() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::AttributePropertyInfos() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::UnforgeableMethodPropertyInfos() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::UnforgeableAttributePropertyInfos() const
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::ConstantPropertyInfos() const
292
293
  DO(JSFunctionSpec, StaticMethod)
294
  DO(JSPropertySpec, StaticAttribute)
295
  DO(JSFunctionSpec, Method)
296
  DO(JSPropertySpec, Attribute)
297
  DO(JSFunctionSpec, UnforgeableMethod)
298
  DO(JSPropertySpec, UnforgeableAttribute)
299
  DO(ConstantSpec,   Constant)
300
301
#undef DO
302
303
  // The index to the iterator method in MethodPropertyInfos() array.
304
  const int16_t iteratorAliasMethodIndex;
305
  // The number of PropertyInfo structs that the duos manage. This is the total
306
  // count across all duos.
307
  const uint16_t propertyInfoCount;
308
  // The sorted indices array from sorting property ids, which will be used when
309
  // we binary search for a property.
310
  uint16_t* sortedPropertyIndices;
311
312
  const Duo duos[N];
313
};
314
315
// Ensure the struct has the expected size. The 8 is for the bitfields plus
316
// iteratorAliasMethodIndex and idsLength; the rest is for the idsSortedIndex,
317
// and duos[].
318
static_assert(sizeof(NativePropertiesN<1>) == 8 +  3*sizeof(void*), "1 size");
319
static_assert(sizeof(NativePropertiesN<2>) == 8 +  5*sizeof(void*), "2 size");
320
static_assert(sizeof(NativePropertiesN<3>) == 8 +  7*sizeof(void*), "3 size");
321
static_assert(sizeof(NativePropertiesN<4>) == 8 +  9*sizeof(void*), "4 size");
322
static_assert(sizeof(NativePropertiesN<5>) == 8 + 11*sizeof(void*), "5 size");
323
static_assert(sizeof(NativePropertiesN<6>) == 8 + 13*sizeof(void*), "6 size");
324
static_assert(sizeof(NativePropertiesN<7>) == 8 + 15*sizeof(void*), "7 size");
325
326
// The "base" type.
327
typedef NativePropertiesN<7> NativeProperties;
328
329
struct NativePropertiesHolder
330
{
331
  const NativeProperties* regular;
332
  const NativeProperties* chromeOnly;
333
};
334
335
// Helper structure for Xrays for DOM binding objects. The same instance is used
336
// for instances, interface objects and interface prototype objects of a
337
// specific interface.
338
struct NativePropertyHooks
339
{
340
  // The hook to call for resolving indexed or named properties. May be null if
341
  // there can't be any.
342
  ResolveOwnProperty mResolveOwnProperty;
343
  // The hook to call for enumerating indexed or named properties. May be null
344
  // if there can't be any.
345
  EnumerateOwnProperties mEnumerateOwnProperties;
346
  // The hook to call to delete a named property.  May be null if there are no
347
  // named properties or no named property deleter.  On success (true return)
348
  // the "found" argument will be set to true if there was in fact such a named
349
  // property and false otherwise.  If it's set to false, the caller is expected
350
  // to proceed with whatever deletion behavior it would have if there were no
351
  // named properties involved at all (i.e. if the hook were null).  If it's set
352
  // to true, it will indicate via opresult whether the delete actually
353
  // succeeded.
354
  DeleteNamedProperty mDeleteNamedProperty;
355
356
  // The property arrays for this interface.
357
  NativePropertiesHolder mNativeProperties;
358
359
  // This will be set to the ID of the interface prototype object for the
360
  // interface, if it has one. If it doesn't have one it will be set to
361
  // prototypes::id::_ID_Count.
362
  prototypes::ID mPrototypeID;
363
364
  // This will be set to the ID of the interface object for the interface, if it
365
  // has one. If it doesn't have one it will be set to
366
  // constructors::id::_ID_Count.
367
  constructors::ID mConstructorID;
368
369
  // The NativePropertyHooks instance for the parent interface (for
370
  // ShimInterfaceInfo).
371
  const NativePropertyHooks* mProtoHooks;
372
373
  // The JSClass to use for expandos on our Xrays.  Can be null, in which case
374
  // Xrays will use a default class of their choice.
375
  const JSClass* mXrayExpandoClass;
376
};
377
378
enum DOMObjectType : uint8_t {
379
  eInstance,
380
  eGlobalInstance,
381
  eInterface,
382
  eInterfacePrototype,
383
  eGlobalInterfacePrototype,
384
  eNamedPropertiesObject
385
};
386
387
inline
388
bool
389
IsInstance(DOMObjectType type)
390
0
{
391
0
  return type == eInstance || type == eGlobalInstance;
392
0
}
393
394
inline
395
bool
396
IsInterfacePrototype(DOMObjectType type)
397
0
{
398
0
  return type == eInterfacePrototype || type == eGlobalInterfacePrototype;
399
0
}
400
401
typedef JSObject* (*AssociatedGlobalGetter)(JSContext* aCx,
402
                                            JS::Handle<JSObject*> aObj);
403
404
typedef JSObject* (*ProtoGetter)(JSContext* aCx);
405
406
/**
407
 * Returns a handle to the relevant WebIDL prototype object for the current
408
 * compartment global (which may be a handle to null on out of memory).  Once
409
 * allocated, the prototype object is guaranteed to exist as long as the global
410
 * does, since the global traces its array of WebIDL prototypes and
411
 * constructors.
412
 */
413
typedef JS::Handle<JSObject*> (*ProtoHandleGetter)(JSContext* aCx);
414
415
// Special JSClass for reflected DOM objects.
416
struct DOMJSClass
417
{
418
  // It would be nice to just inherit from JSClass, but that precludes pure
419
  // compile-time initialization of the form |DOMJSClass = {...};|, since C++
420
  // only allows brace initialization for aggregate/POD types.
421
  const js::Class mBase;
422
423
  // A list of interfaces that this object implements, in order of decreasing
424
  // derivedness.
425
  const prototypes::ID mInterfaceChain[MAX_PROTOTYPE_CHAIN_LENGTH];
426
427
  // We store the DOM object in reserved slot with index DOM_OBJECT_SLOT or in
428
  // the proxy private if we use a proxy object.
429
  // Sometimes it's an nsISupports and sometimes it's not; this class tells
430
  // us which it is.
431
  const bool mDOMObjectIsISupports;
432
433
  const NativePropertyHooks* mNativeHooks;
434
435
  // A callback to find the associated global for our C++ object.  Note that
436
  // this is used in cases when that global is _changing_, so it will not match
437
  // the global of the JSObject* passed in to this function!
438
  AssociatedGlobalGetter mGetAssociatedGlobal;
439
  ProtoHandleGetter mGetProto;
440
441
  // This stores the CC participant for the native, null if this class does not
442
  // implement cycle collection or if it inherits from nsISupports (we can get
443
  // the CC participant by QI'ing in that case).
444
  nsCycleCollectionParticipant* mParticipant;
445
446
3
  static const DOMJSClass* FromJSClass(const JSClass* base) {
447
3
    MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS);
448
3
    return reinterpret_cast<const DOMJSClass*>(base);
449
3
  }
450
451
3
  static const DOMJSClass* FromJSClass(const js::Class* base) {
452
3
    return FromJSClass(Jsvalify(base));
453
3
  }
454
455
3
  const JSClass* ToJSClass() const { return Jsvalify(&mBase); }
456
};
457
458
// Special JSClass for DOM interface and interface prototype objects.
459
struct DOMIfaceAndProtoJSClass
460
{
461
  // It would be nice to just inherit from js::Class, but that precludes pure
462
  // compile-time initialization of the form
463
  // |DOMJSInterfaceAndPrototypeClass = {...};|, since C++ only allows brace
464
  // initialization for aggregate/POD types.
465
  const js::Class mBase;
466
467
  // Either eInterface, eInterfacePrototype, eGlobalInterfacePrototype or
468
  // eNamedPropertiesObject.
469
  DOMObjectType mType; // uint8_t
470
471
  // Boolean indicating whether this object wants a @@hasInstance property
472
  // pointing to InterfaceHasInstance defined on it.  Only ever true for the
473
  // eInterface case.
474
  bool wantsInterfaceHasInstance;
475
476
  const prototypes::ID mPrototypeID; // uint16_t
477
  const uint32_t mDepth;
478
479
  const NativePropertyHooks* mNativeHooks;
480
481
  // The value to return for toString() on this interface or interface prototype
482
  // object.
483
  const char* mToString;
484
485
  ProtoGetter mGetParentProto;
486
487
2
  static const DOMIfaceAndProtoJSClass* FromJSClass(const JSClass* base) {
488
2
    MOZ_ASSERT(base->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS);
489
2
    return reinterpret_cast<const DOMIfaceAndProtoJSClass*>(base);
490
2
  }
491
2
  static const DOMIfaceAndProtoJSClass* FromJSClass(const js::Class* base) {
492
2
    return FromJSClass(Jsvalify(base));
493
2
  }
494
495
0
  const JSClass* ToJSClass() const { return Jsvalify(&mBase); }
496
};
497
498
class ProtoAndIfaceCache;
499
500
inline bool
501
DOMGlobalHasProtoAndIFaceCache(JSObject* global)
502
54
{
503
54
  MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL);
504
54
  // This can be undefined if we GC while creating the global
505
54
  return !js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).isUndefined();
506
54
}
507
508
inline bool
509
HasProtoAndIfaceCache(JSObject* global)
510
0
{
511
0
  if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
512
0
    return false;
513
0
  }
514
0
  return DOMGlobalHasProtoAndIFaceCache(global);
515
0
}
516
517
inline ProtoAndIfaceCache*
518
GetProtoAndIfaceCache(JSObject* global)
519
58
{
520
58
  MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL);
521
58
  return static_cast<ProtoAndIfaceCache*>(
522
58
    js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).toPrivate());
523
58
}
524
525
} // namespace dom
526
} // namespace mozilla
527
528
#endif /* mozilla_dom_DOMJSClass_h */