Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dom/bindings/PerformanceObserverBinding.cpp
Line
Count
Source (jump to first uncovered line)
1
/* THIS FILE IS AUTOGENERATED FROM PerformanceObserver.webidl BY Codegen.py - DO NOT EDIT */
2
3
#include "AtomList.h"
4
#include "PerformanceObserverBinding.h"
5
#include "WrapperFactory.h"
6
#include "mozilla/OwningNonNull.h"
7
#include "mozilla/dom/BindingUtils.h"
8
#include "mozilla/dom/DOMJSClass.h"
9
#include "mozilla/dom/DOMPrefs.h"
10
#include "mozilla/dom/NonRefcountedDOMObject.h"
11
#include "mozilla/dom/PerformanceEntry.h"
12
#include "mozilla/dom/PerformanceObserver.h"
13
#include "mozilla/dom/PerformanceObserverEntryList.h"
14
#include "mozilla/dom/PrimitiveConversions.h"
15
#include "mozilla/dom/ScriptSettings.h"
16
#include "mozilla/dom/SimpleGlobalObject.h"
17
#include "mozilla/dom/XrayExpandoClass.h"
18
19
namespace mozilla {
20
namespace dom {
21
22
namespace binding_detail {}; // Just to make sure it's known as a namespace
23
using namespace mozilla::dom::binding_detail;
24
25
26
27
PerformanceObserverInit::PerformanceObserverInit()
28
0
{
29
0
  // Safe to pass a null context if we pass a null value
30
0
  Init(nullptr, JS::NullHandleValue);
31
0
}
32
33
34
35
bool
36
PerformanceObserverInit::InitIds(JSContext* cx, PerformanceObserverInitAtoms* atomsCache)
37
0
{
38
0
  MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache));
39
0
40
0
  // Initialize these in reverse order so that any failure leaves the first one
41
0
  // uninitialized.
42
0
  if (!atomsCache->entryTypes_id.init(cx, "entryTypes") ||
43
0
      !atomsCache->buffered_id.init(cx, "buffered")) {
44
0
    return false;
45
0
  }
46
0
  return true;
47
0
}
48
49
bool
50
PerformanceObserverInit::Init(JSContext* cx, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
51
0
{
52
0
  // Passing a null JSContext is OK only if we're initing from null,
53
0
  // Since in that case we will not have to do any property gets
54
0
  // Also evaluate isNullOrUndefined in order to avoid false-positive
55
0
  // checkers by static analysis tools
56
0
  MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
57
0
  PerformanceObserverInitAtoms* atomsCache = nullptr;
58
0
  if (cx) {
59
0
    atomsCache = GetAtomCache<PerformanceObserverInitAtoms>(cx);
60
0
    if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
61
0
      return false;
62
0
    }
63
0
  }
64
0
65
0
  if (!IsConvertibleToDictionary(val)) {
66
0
    return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
67
0
  }
68
0
69
0
  bool isNull = val.isNullOrUndefined();
70
0
  // We only need these if !isNull, in which case we have |cx|.
71
0
  Maybe<JS::Rooted<JSObject *> > object;
72
0
  Maybe<JS::Rooted<JS::Value> > temp;
73
0
  if (!isNull) {
74
0
    MOZ_ASSERT(cx);
75
0
    object.emplace(cx, &val.toObject());
76
0
    temp.emplace(cx);
77
0
  }
78
0
  if (!isNull) {
79
0
    if (!JS_GetPropertyById(cx, *object, atomsCache->buffered_id, temp.ptr())) {
80
0
      return false;
81
0
    }
82
0
  }
83
0
  if (!isNull && !temp->isUndefined()) {
84
0
    if (!ValueToPrimitive<bool, eDefault>(cx, temp.ref(), &mBuffered)) {
85
0
      return false;
86
0
    }
87
0
  } else {
88
0
    mBuffered = false;
89
0
  }
90
0
  mIsAnyMemberPresent = true;
91
0
92
0
  if (!isNull) {
93
0
    if (!JS_GetPropertyById(cx, *object, atomsCache->entryTypes_id, temp.ptr())) {
94
0
      return false;
95
0
    }
96
0
  }
97
0
  if (!isNull && !temp->isUndefined()) {
98
0
    if (temp.ref().isObject()) {
99
0
      JS::ForOfIterator iter(cx);
100
0
      if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) {
101
0
        return false;
102
0
      }
103
0
      if (!iter.valueIsIterable()) {
104
0
        ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "'entryTypes' member of PerformanceObserverInit");
105
0
        return false;
106
0
      }
107
0
      Sequence<nsString> &arr = mEntryTypes;
108
0
      JS::Rooted<JS::Value> temp(cx);
109
0
      while (true) {
110
0
        bool done;
111
0
        if (!iter.next(&temp, &done)) {
112
0
          return false;
113
0
        }
114
0
        if (done) {
115
0
          break;
116
0
        }
117
0
        nsString* slotPtr = arr.AppendElement(mozilla::fallible);
118
0
        if (!slotPtr) {
119
0
          JS_ReportOutOfMemory(cx);
120
0
          return false;
121
0
        }
122
0
        nsString& slot = *slotPtr;
123
0
        if (!ConvertJSValueToString(cx, temp, eStringify, eStringify, slot)) {
124
0
          return false;
125
0
        }
126
0
      }
127
0
    } else {
128
0
      ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "'entryTypes' member of PerformanceObserverInit");
129
0
      return false;
130
0
    }
131
0
    mIsAnyMemberPresent = true;
132
0
  } else if (cx) {
133
0
    // Don't error out if we have no cx.  In that
134
0
    // situation the caller is default-constructing us and we'll
135
0
    // just assume they know what they're doing.
136
0
    return ThrowErrorMessage(cx, MSG_MISSING_REQUIRED_DICTIONARY_MEMBER,
137
0
                             "'entryTypes' member of PerformanceObserverInit");
138
0
  }
139
0
  return true;
140
0
}
141
142
bool
143
PerformanceObserverInit::Init(const nsAString& aJSON)
144
0
{
145
0
  AutoJSAPI jsapi;
146
0
  JSObject* cleanGlobal = SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail);
147
0
  if (!cleanGlobal) {
148
0
    return false;
149
0
  }
150
0
  if (!jsapi.Init(cleanGlobal)) {
151
0
    return false;
152
0
  }
153
0
  JSContext* cx = jsapi.cx();
154
0
  JS::Rooted<JS::Value> json(cx);
155
0
  bool ok = ParseJSON(cx, aJSON, &json);
156
0
  NS_ENSURE_TRUE(ok, false);
157
0
  return Init(cx, json);
158
0
}
159
160
bool
161
PerformanceObserverInit::ToObjectInternal(JSContext* cx, JS::MutableHandle<JS::Value> rval) const
162
0
{
163
0
  PerformanceObserverInitAtoms* atomsCache = GetAtomCache<PerformanceObserverInitAtoms>(cx);
164
0
  if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
165
0
    return false;
166
0
  }
167
0
168
0
  JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
169
0
  if (!obj) {
170
0
    return false;
171
0
  }
172
0
  rval.set(JS::ObjectValue(*obj));
173
0
174
0
  do {
175
0
    // block for our 'break' successCode and scope for 'temp' and 'currentValue'
176
0
    JS::Rooted<JS::Value> temp(cx);
177
0
    bool const & currentValue = mBuffered;
178
0
    temp.setBoolean(currentValue);
179
0
    if (!JS_DefinePropertyById(cx, obj, atomsCache->buffered_id, temp, JSPROP_ENUMERATE)) {
180
0
      return false;
181
0
    }
182
0
    break;
183
0
  } while(false);
184
0
185
0
  do {
186
0
    // block for our 'break' successCode and scope for 'temp' and 'currentValue'
187
0
    JS::Rooted<JS::Value> temp(cx);
188
0
    Sequence<nsString> const & currentValue = mEntryTypes;
189
0
190
0
    uint32_t length = currentValue.Length();
191
0
    JS::Rooted<JSObject*> returnArray(cx, JS_NewArrayObject(cx, length));
192
0
    if (!returnArray) {
193
0
      return false;
194
0
    }
195
0
    // Scope for 'tmp'
196
0
    {
197
0
      JS::Rooted<JS::Value> tmp(cx);
198
0
      for (uint32_t sequenceIdx0 = 0; sequenceIdx0 < length; ++sequenceIdx0) {
199
0
        // Control block to let us common up the JS_DefineElement calls when there
200
0
        // are different ways to succeed at wrapping the object.
201
0
        do {
202
0
          if (!xpc::NonVoidStringToJsval(cx, currentValue[sequenceIdx0], &tmp)) {
203
0
            return false;
204
0
          }
205
0
          break;
206
0
        } while (false);
207
0
        if (!JS_DefineElement(cx, returnArray, sequenceIdx0, tmp,
208
0
                              JSPROP_ENUMERATE)) {
209
0
          return false;
210
0
        }
211
0
      }
212
0
    }
213
0
    temp.setObject(*returnArray);
214
0
    if (!JS_DefinePropertyById(cx, obj, atomsCache->entryTypes_id, temp, JSPROP_ENUMERATE)) {
215
0
      return false;
216
0
    }
217
0
    break;
218
0
  } while(false);
219
0
220
0
  return true;
221
0
}
222
223
bool
224
PerformanceObserverInit::ToJSON(nsAString& aJSON) const
225
0
{
226
0
  AutoJSAPI jsapi;
227
0
  jsapi.Init();
228
0
  JSContext *cx = jsapi.cx();
229
0
  // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
230
0
  // because we'll only be creating objects, in ways that have no
231
0
  // side-effects, followed by a call to JS::ToJSONMaybeSafely,
232
0
  // which likewise guarantees no side-effects for the sorts of
233
0
  // things we will pass it.
234
0
  JSAutoRealm ar(cx, UnprivilegedJunkScopeOrWorkerGlobal());
235
0
  JS::Rooted<JS::Value> val(cx);
236
0
  if (!ToObjectInternal(cx, &val)) {
237
0
    return false;
238
0
  }
239
0
  JS::Rooted<JSObject*> obj(cx, &val.toObject());
240
0
  return StringifyToJSON(cx, obj, aJSON);
241
0
}
242
243
void
244
PerformanceObserverInit::TraceDictionary(JSTracer* trc)
245
0
{
246
0
}
247
248
PerformanceObserverInit&
249
PerformanceObserverInit::operator=(const PerformanceObserverInit& aOther)
250
0
{
251
0
  DictionaryBase::operator=(aOther);
252
0
  mBuffered = aOther.mBuffered;
253
0
  mEntryTypes = aOther.mEntryTypes;
254
0
  return *this;
255
0
}
256
257
namespace binding_detail {
258
} // namespace binding_detail
259
260
261
void
262
PerformanceObserverCallback::Call(JSContext* cx, JS::Handle<JS::Value> aThisVal, PerformanceObserverEntryList& entries, PerformanceObserver& observer, ErrorResult& aRv)
263
0
{
264
0
  JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());
265
0
  JS::AutoValueVector argv(cx);
266
0
  if (!argv.resize(2)) {
267
0
    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
268
0
    return;
269
0
  }
270
0
  unsigned argc = 2;
271
0
272
0
  do {
273
0
    if (!GetOrCreateDOMReflector(cx, observer, argv[1])) {
274
0
      MOZ_ASSERT(JS_IsExceptionPending(cx));
275
0
      aRv.Throw(NS_ERROR_UNEXPECTED);
276
0
      return;
277
0
    }
278
0
    break;
279
0
  } while (false);
280
0
281
0
  do {
282
0
    if (!GetOrCreateDOMReflector(cx, entries, argv[0])) {
283
0
      MOZ_ASSERT(JS_IsExceptionPending(cx));
284
0
      aRv.Throw(NS_ERROR_UNEXPECTED);
285
0
      return;
286
0
    }
287
0
    break;
288
0
  } while (false);
289
0
290
0
  JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));
291
0
  if (!JS::Call(cx, aThisVal, callable,
292
0
                JS::HandleValueArray::subarray(argv, 0, argc), &rval)) {
293
0
    aRv.NoteJSContextException(cx);
294
0
    return;
295
0
  }
296
0
}
297
298
299
300
namespace binding_detail {
301
} // namespace binding_detail
302
303
304
namespace PerformanceObserver_Binding {
305
306
MOZ_CAN_RUN_SCRIPT static bool
307
observe(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::PerformanceObserver* self, const JSJitMethodCallArgs& args)
308
0
{
309
0
  AUTO_PROFILER_LABEL_FAST("PerformanceObserver.observe", DOM, cx);
310
0
311
0
  if (MOZ_UNLIKELY(args.length() < 1)) {
312
0
    return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "PerformanceObserver.observe");
313
0
  }
314
0
  binding_detail::FastPerformanceObserverInit arg0;
315
0
  if (!arg0.Init(cx, args[0],  "Argument 1 of PerformanceObserver.observe", false)) {
316
0
    return false;
317
0
  }
318
0
  self->Observe(Constify(arg0));
319
0
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
320
0
  args.rval().setUndefined();
321
0
  return true;
322
0
}
323
324
static const JSJitInfo observe_methodinfo = {
325
  { (JSJitGetterOp)observe },
326
  { prototypes::id::PerformanceObserver },
327
  { PrototypeTraits<prototypes::id::PerformanceObserver>::Depth },
328
  JSJitInfo::Method,
329
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
330
  JSVAL_TYPE_UNDEFINED,  /* returnType.  Not relevant for setters. */
331
  false,  /* isInfallible. False in setters. */
332
  false,  /* isMovable.  Not relevant for setters. */
333
  false, /* isEliminatable.  Not relevant for setters. */
334
  false, /* isAlwaysInSlot.  Only relevant for getters. */
335
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
336
  false,  /* isTypedMethod.  Only relevant for methods. */
337
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
338
};
339
static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
340
static_assert(0 < 1, "There is no slot for us");
341
342
MOZ_CAN_RUN_SCRIPT static bool
343
disconnect(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::PerformanceObserver* self, const JSJitMethodCallArgs& args)
344
0
{
345
0
  AUTO_PROFILER_LABEL_FAST("PerformanceObserver.disconnect", DOM, cx);
346
0
347
0
  self->Disconnect();
348
0
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
349
0
  args.rval().setUndefined();
350
0
  return true;
351
0
}
352
353
static const JSJitInfo disconnect_methodinfo = {
354
  { (JSJitGetterOp)disconnect },
355
  { prototypes::id::PerformanceObserver },
356
  { PrototypeTraits<prototypes::id::PerformanceObserver>::Depth },
357
  JSJitInfo::Method,
358
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
359
  JSVAL_TYPE_UNDEFINED,  /* returnType.  Not relevant for setters. */
360
  true,  /* isInfallible. False in setters. */
361
  false,  /* isMovable.  Not relevant for setters. */
362
  false, /* isEliminatable.  Not relevant for setters. */
363
  false, /* isAlwaysInSlot.  Only relevant for getters. */
364
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
365
  false,  /* isTypedMethod.  Only relevant for methods. */
366
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
367
};
368
static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
369
static_assert(0 < 1, "There is no slot for us");
370
371
MOZ_CAN_RUN_SCRIPT static bool
372
takeRecords(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::PerformanceObserver* self, const JSJitMethodCallArgs& args)
373
0
{
374
0
  AUTO_PROFILER_LABEL_FAST("PerformanceObserver.takeRecords", DOM, cx);
375
0
376
0
  nsTArray<StrongPtrForMember<mozilla::dom::PerformanceEntry>::Type> result;
377
0
  self->TakeRecords(result);
378
0
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
379
0
380
0
  uint32_t length = result.Length();
381
0
  JS::Rooted<JSObject*> returnArray(cx, JS_NewArrayObject(cx, length));
382
0
  if (!returnArray) {
383
0
    return false;
384
0
  }
385
0
  // Scope for 'tmp'
386
0
  {
387
0
    JS::Rooted<JS::Value> tmp(cx);
388
0
    for (uint32_t sequenceIdx0 = 0; sequenceIdx0 < length; ++sequenceIdx0) {
389
0
      // Control block to let us common up the JS_DefineElement calls when there
390
0
      // are different ways to succeed at wrapping the object.
391
0
      do {
392
0
        if (!GetOrCreateDOMReflector(cx, result[sequenceIdx0], &tmp)) {
393
0
          MOZ_ASSERT(JS_IsExceptionPending(cx));
394
0
          return false;
395
0
        }
396
0
        break;
397
0
      } while (false);
398
0
      if (!JS_DefineElement(cx, returnArray, sequenceIdx0, tmp,
399
0
                            JSPROP_ENUMERATE)) {
400
0
        return false;
401
0
      }
402
0
    }
403
0
  }
404
0
  args.rval().setObject(*returnArray);
405
0
  return true;
406
0
}
407
408
static const JSJitInfo takeRecords_methodinfo = {
409
  { (JSJitGetterOp)takeRecords },
410
  { prototypes::id::PerformanceObserver },
411
  { PrototypeTraits<prototypes::id::PerformanceObserver>::Depth },
412
  JSJitInfo::Method,
413
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
414
  JSVAL_TYPE_OBJECT,  /* returnType.  Not relevant for setters. */
415
  false,  /* isInfallible. False in setters. */
416
  false,  /* isMovable.  Not relevant for setters. */
417
  false, /* isEliminatable.  Not relevant for setters. */
418
  false, /* isAlwaysInSlot.  Only relevant for getters. */
419
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
420
  false,  /* isTypedMethod.  Only relevant for methods. */
421
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
422
};
423
static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
424
static_assert(0 < 1, "There is no slot for us");
425
426
static bool
427
_addProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> val)
428
0
{
429
0
  mozilla::dom::PerformanceObserver* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::PerformanceObserver>(obj);
430
0
  // We don't want to preserve if we don't have a wrapper, and we
431
0
  // obviously can't preserve if we're not initialized.
432
0
  if (self && self->GetWrapperPreserveColor()) {
433
0
    PreserveWrapper(self);
434
0
  }
435
0
  return true;
436
0
}
437
438
static void
439
_finalize(js::FreeOp* fop, JSObject* obj)
440
0
{
441
0
  mozilla::dom::PerformanceObserver* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::PerformanceObserver>(obj);
442
0
  if (self) {
443
0
    ClearWrapper(self, self, obj);
444
0
    AddForDeferredFinalization<mozilla::dom::PerformanceObserver>(self);
445
0
  }
446
0
}
447
448
static size_t
449
_objectMoved(JSObject* obj, JSObject* old)
450
0
{
451
0
  mozilla::dom::PerformanceObserver* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::PerformanceObserver>(obj);
452
0
  if (self) {
453
0
    UpdateWrapper(self, self, obj, old);
454
0
  }
455
0
456
0
  return 0;
457
0
}
458
459
// We deliberately use brace-elision to make Visual Studio produce better initalization code.
460
#if defined(__clang__)
461
#pragma clang diagnostic push
462
#pragma clang diagnostic ignored "-Wmissing-braces"
463
#endif
464
static const JSFunctionSpec sMethods_specs[] = {
465
  JS_FNSPEC("observe", (GenericMethod<NormalThisPolicy, ThrowExceptions>), reinterpret_cast<const JSJitInfo*>(&observe_methodinfo), 1, JSPROP_ENUMERATE, nullptr),
466
  JS_FNSPEC("disconnect", (GenericMethod<NormalThisPolicy, ThrowExceptions>), reinterpret_cast<const JSJitInfo*>(&disconnect_methodinfo), 0, JSPROP_ENUMERATE, nullptr),
467
  JS_FNSPEC("takeRecords", (GenericMethod<NormalThisPolicy, ThrowExceptions>), reinterpret_cast<const JSJitInfo*>(&takeRecords_methodinfo), 0, JSPROP_ENUMERATE, nullptr),
468
  JS_FS_END
469
};
470
#if defined(__clang__)
471
#pragma clang diagnostic pop
472
#endif
473
474
475
static const Prefable<const JSFunctionSpec> sMethods[] = {
476
  { nullptr, &sMethods_specs[0] },
477
  { nullptr, nullptr }
478
};
479
480
static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
481
    "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
482
static_assert(3 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
483
    "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");
484
485
486
static uint16_t sNativeProperties_sortedPropertyIndices[3];
487
static PropertyInfo sNativeProperties_propertyInfos[3];
488
489
static const NativePropertiesN<1> sNativeProperties = {
490
  false, 0,
491
  false, 0,
492
  true,  0 /* sMethods */,
493
  false, 0,
494
  false, 0,
495
  false, 0,
496
  false, 0,
497
  -1,
498
  3,
499
  sNativeProperties_sortedPropertyIndices,
500
  {
501
    { sMethods, &sNativeProperties_propertyInfos[0] }
502
  }
503
};
504
static_assert(3 < 1ull << CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount),
505
    "We have a property info count that is oversized");
506
507
static bool
508
_constructor(JSContext* cx, unsigned argc, JS::Value* vp)
509
0
{
510
0
  AUTO_PROFILER_LABEL_FAST("PerformanceObserver constructor", DOM, cx);
511
0
512
0
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
513
0
  JS::Rooted<JSObject*> obj(cx, &args.callee());
514
0
  if (!args.isConstructing()) {
515
0
    // XXXbz wish I could get the name from the callee instead of
516
0
    // Adding more relocations
517
0
    return ThrowConstructorWithoutNew(cx, "PerformanceObserver");
518
0
  }
519
0
520
0
  JS::Rooted<JSObject*> desiredProto(cx);
521
0
  if (!GetDesiredProto(cx, args, &desiredProto)) {
522
0
    return false;
523
0
  }
524
0
525
0
  if (MOZ_UNLIKELY(args.length() < 1)) {
526
0
    return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "PerformanceObserver");
527
0
  }
528
0
  GlobalObject global(cx, obj);
529
0
  if (global.Failed()) {
530
0
    return false;
531
0
  }
532
0
533
0
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
534
0
  RootedCallback<OwningNonNull<binding_detail::FastPerformanceObserverCallback>> arg0(cx);
535
0
  if (args[0].isObject()) {
536
0
    if (JS::IsCallable(&args[0].toObject())) {
537
0
    { // scope for tempRoot and tempGlobalRoot if needed
538
0
      arg0 = new binding_detail::FastPerformanceObserverCallback(&args[0].toObject(), JS::CurrentGlobalOrNull(cx));
539
0
    }
540
0
    } else {
541
0
      ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "Argument 1 of PerformanceObserver.constructor");
542
0
      return false;
543
0
    }
544
0
  } else {
545
0
    ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 1 of PerformanceObserver.constructor");
546
0
    return false;
547
0
  }
548
0
  Maybe<JSAutoRealm> ar;
549
0
  if (objIsXray) {
550
0
    obj = js::CheckedUnwrap(obj);
551
0
    if (!obj) {
552
0
      return false;
553
0
    }
554
0
    ar.emplace(cx, obj);
555
0
    if (!JS_WrapObject(cx, &desiredProto)) {
556
0
      return false;
557
0
    }
558
0
  }
559
0
  FastErrorResult rv;
560
0
  auto result(StrongOrRawPtr<mozilla::dom::PerformanceObserver>(mozilla::dom::PerformanceObserver::Constructor(global, NonNullHelper(arg0), rv)));
561
0
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
562
0
    return false;
563
0
  }
564
0
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
565
0
  static_assert(!IsPointer<decltype(result)>::value,
566
0
                "NewObject implies that we need to keep the object alive with a strong reference.");
567
0
  if (!GetOrCreateDOMReflector(cx, result, args.rval(), desiredProto)) {
568
0
    MOZ_ASSERT(JS_IsExceptionPending(cx));
569
0
    return false;
570
0
  }
571
0
  return true;
572
0
}
573
574
static const js::ClassOps sInterfaceObjectClassOps = {
575
    nullptr,               /* addProperty */
576
    nullptr,               /* delProperty */
577
    nullptr,               /* enumerate */
578
    nullptr,               /* newEnumerate */
579
    nullptr,               /* resolve */
580
    nullptr,               /* mayResolve */
581
    nullptr,               /* finalize */
582
    _constructor, /* call */
583
    nullptr,               /* hasInstance */
584
    _constructor, /* construct */
585
    nullptr,               /* trace */
586
};
587
588
static const DOMIfaceAndProtoJSClass sInterfaceObjectClass = {
589
  {
590
    "Function",
591
    JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_SLOTS_BASE),
592
    &sInterfaceObjectClassOps,
593
    JS_NULL_CLASS_SPEC,
594
    JS_NULL_CLASS_EXT,
595
    &sInterfaceObjectClassObjectOps
596
  },
597
  eInterface,
598
  true,
599
  prototypes::id::PerformanceObserver,
600
  PrototypeTraits<prototypes::id::PerformanceObserver>::Depth,
601
  sNativePropertyHooks,
602
  "function PerformanceObserver() {\n    [native code]\n}",
603
  JS::GetRealmFunctionPrototype
604
};
605
606
static const DOMIfaceAndProtoJSClass sPrototypeClass = {
607
  {
608
    "PerformanceObserverPrototype",
609
    JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE),
610
    JS_NULL_CLASS_OPS,
611
    JS_NULL_CLASS_SPEC,
612
    JS_NULL_CLASS_EXT,
613
    JS_NULL_OBJECT_OPS
614
  },
615
  eInterfacePrototype,
616
  false,
617
  prototypes::id::PerformanceObserver,
618
  PrototypeTraits<prototypes::id::PerformanceObserver>::Depth,
619
  sNativePropertyHooks,
620
  "[object PerformanceObserverPrototype]",
621
  JS::GetRealmObjectPrototype
622
};
623
624
bool
625
ConstructorEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj)
626
0
{
627
0
  return mozilla::dom::DOMPrefs::dom_enable_performance_observer(aCx, aObj);
628
0
}
629
630
static const js::ClassOps sClassOps = {
631
  _addProperty, /* addProperty */
632
  nullptr,               /* delProperty */
633
  nullptr,               /* enumerate */
634
  nullptr, /* newEnumerate */
635
  nullptr, /* resolve */
636
  nullptr, /* mayResolve */
637
  _finalize, /* finalize */
638
  nullptr, /* call */
639
  nullptr,               /* hasInstance */
640
  nullptr,               /* construct */
641
  nullptr, /* trace */
642
};
643
644
static const js::ClassExtension sClassExtension = {
645
  nullptr, /* weakmapKeyDelegateOp */
646
  _objectMoved /* objectMovedOp */
647
};
648
649
static const DOMJSClass sClass = {
650
  { "PerformanceObserver",
651
    JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1),
652
    &sClassOps,
653
    JS_NULL_CLASS_SPEC,
654
    &sClassExtension,
655
    JS_NULL_OBJECT_OPS
656
  },
657
  { prototypes::id::PerformanceObserver, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count },
658
  IsBaseOf<nsISupports, mozilla::dom::PerformanceObserver >::value,
659
  sNativePropertyHooks,
660
  FindAssociatedGlobalForNative<mozilla::dom::PerformanceObserver>::Get,
661
  GetProtoObjectHandle,
662
  GetCCParticipant<mozilla::dom::PerformanceObserver>::Get()
663
};
664
static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS,
665
              "Must have the right minimal number of reserved slots.");
666
static_assert(1 >= 1,
667
              "Must have enough reserved slots.");
668
669
const JSClass*
670
GetJSClass()
671
0
{
672
0
  return sClass.ToJSClass();
673
0
}
674
675
bool
676
Wrap(JSContext* aCx, mozilla::dom::PerformanceObserver* aObject, nsWrapperCache* aCache, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
677
0
{
678
0
  static_assert(!IsBaseOf<NonRefcountedDOMObject, mozilla::dom::PerformanceObserver>::value,
679
0
                "Shouldn't have wrappercached things that are not refcounted.");
680
0
  MOZ_ASSERT(static_cast<mozilla::dom::PerformanceObserver*>(aObject) ==
681
0
             reinterpret_cast<mozilla::dom::PerformanceObserver*>(aObject),
682
0
             "Multiple inheritance for mozilla::dom::PerformanceObserver is broken.");
683
0
  MOZ_ASSERT(ToSupportsIsCorrect(aObject));
684
0
  MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
685
0
  MOZ_ASSERT(!aCache->GetWrapper(),
686
0
             "You should probably not be using Wrap() directly; use "
687
0
             "GetOrCreateDOMReflector instead");
688
0
689
0
  MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
690
0
             "nsISupports must be on our primary inheritance chain");
691
0
692
0
  JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
693
0
  if (!global) {
694
0
    return false;
695
0
  }
696
0
  MOZ_ASSERT(JS_IsGlobalObject(global));
697
0
  MOZ_ASSERT(JS::ObjectIsNotGray(global));
698
0
699
0
  // That might have ended up wrapping us already, due to the wonders
700
0
  // of XBL.  Check for that, and bail out as needed.
701
0
  aReflector.set(aCache->GetWrapper());
702
0
  if (aReflector) {
703
#ifdef DEBUG
704
    AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
705
#endif // DEBUG
706
    return true;
707
0
  }
708
0
709
0
  JSAutoRealm ar(aCx, global);
710
0
  JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
711
0
  if (!canonicalProto) {
712
0
    return false;
713
0
  }
714
0
  JS::Rooted<JSObject*> proto(aCx);
715
0
  if (aGivenProto) {
716
0
    proto = aGivenProto;
717
0
    // Unfortunately, while aGivenProto was in the compartment of aCx
718
0
    // coming in, we changed compartments to that of "parent" so may need
719
0
    // to wrap the proto here.
720
0
    if (js::GetContextCompartment(aCx) != js::GetObjectCompartment(proto)) {
721
0
      if (!JS_WrapObject(aCx, &proto)) {
722
0
        return false;
723
0
      }
724
0
    }
725
0
  } else {
726
0
    proto = canonicalProto;
727
0
  }
728
0
729
0
  BindingJSObjectCreator<mozilla::dom::PerformanceObserver> creator(aCx);
730
0
  creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
731
0
  if (!aReflector) {
732
0
    return false;
733
0
  }
734
0
735
0
  aCache->SetWrapper(aReflector);
736
0
  creator.InitializationSucceeded();
737
0
738
0
  MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
739
0
             aCache->GetWrapperPreserveColor() == aReflector);
740
0
  // If proto != canonicalProto, we have to preserve our wrapper;
741
0
  // otherwise we won't be able to properly recreate it later, since
742
0
  // we won't know what proto to use.  Note that we don't check
743
0
  // aGivenProto here, since it's entirely possible (and even
744
0
  // somewhat common) to have a non-null aGivenProto which is the
745
0
  // same as canonicalProto.
746
0
  if (proto != canonicalProto) {
747
0
    PreserveWrapper(aObject);
748
0
  }
749
0
750
0
  return true;
751
0
}
752
753
const NativePropertyHooks sNativePropertyHooks[] = { {
754
  nullptr,
755
  nullptr,
756
  nullptr,
757
  { sNativeProperties.Upcast(), nullptr },
758
  prototypes::id::PerformanceObserver,
759
  constructors::id::PerformanceObserver,
760
  nullptr,
761
  &DefaultXrayExpandoObjectClass
762
} };
763
764
void
765
CreateInterfaceObjects(JSContext* aCx, JS::Handle<JSObject*> aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, bool aDefineOnGlobal)
766
0
{
767
0
  JS::Rooted<JSObject*> parentProto(aCx, JS::GetRealmObjectPrototype(aCx));
768
0
  if (!parentProto) {
769
0
    return;
770
0
  }
771
0
772
0
  JS::Rooted<JSObject*> constructorProto(aCx, JS::GetRealmFunctionPrototype(aCx));
773
0
  if (!constructorProto) {
774
0
    return;
775
0
  }
776
0
777
0
  static bool sIdsInited = false;
778
0
  if (!sIdsInited && NS_IsMainThread()) {
779
0
    if (!InitIds(aCx, sNativeProperties.Upcast())) {
780
0
      return;
781
0
    }
782
0
    sIdsInited = true;
783
0
  }
784
0
785
0
  JS::Heap<JSObject*>* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::PerformanceObserver);
786
0
  JS::Heap<JSObject*>* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::PerformanceObserver);
787
0
  dom::CreateInterfaceObjects(aCx, aGlobal, parentProto,
788
0
                              &sPrototypeClass.mBase, protoCache,
789
0
                              nullptr,
790
0
                              constructorProto, &sInterfaceObjectClass.mBase, 1, nullptr,
791
0
                              interfaceCache,
792
0
                              sNativeProperties.Upcast(),
793
0
                              nullptr,
794
0
                              "PerformanceObserver", aDefineOnGlobal,
795
0
                              nullptr,
796
0
                              false);
797
0
}
798
799
JSObject*
800
GetConstructorObject(JSContext* aCx)
801
0
{
802
0
  return GetConstructorObjectHandle(aCx);
803
0
}
804
805
} // namespace PerformanceObserver_Binding
806
807
808
809
} // namespace dom
810
} // namespace mozilla