Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dom/bindings/AudioWorkletNodeBinding.cpp
Line
Count
Source (jump to first uncovered line)
1
/* THIS FILE IS AUTOGENERATED FROM AudioWorkletNode.webidl BY Codegen.py - DO NOT EDIT */
2
3
#include "AtomList.h"
4
#include "AudioNodeBinding.h"
5
#include "AudioWorkletNodeBinding.h"
6
#include "EventHandlerBinding.h"
7
#include "WrapperFactory.h"
8
#include "mozilla/FloatingPoint.h"
9
#include "mozilla/OwningNonNull.h"
10
#include "mozilla/Preferences.h"
11
#include "mozilla/dom/AudioContext.h"
12
#include "mozilla/dom/AudioParamMap.h"
13
#include "mozilla/dom/AudioWorkletNode.h"
14
#include "mozilla/dom/BindingUtils.h"
15
#include "mozilla/dom/DOMJSClass.h"
16
#include "mozilla/dom/MessagePort.h"
17
#include "mozilla/dom/NonRefcountedDOMObject.h"
18
#include "mozilla/dom/Nullable.h"
19
#include "mozilla/dom/PrimitiveConversions.h"
20
#include "mozilla/dom/ScriptSettings.h"
21
#include "mozilla/dom/XrayExpandoClass.h"
22
23
namespace mozilla {
24
namespace dom {
25
26
namespace binding_detail {}; // Just to make sure it's known as a namespace
27
using namespace mozilla::dom::binding_detail;
28
29
30
31
AudioWorkletNodeOptions::AudioWorkletNodeOptions()
32
  : AudioNodeOptions(FastDictionaryInitializer()),
33
    mProcessorOptions(nullptr)
34
0
{
35
0
  // Safe to pass a null context if we pass a null value
36
0
  Init(nullptr, JS::NullHandleValue);
37
0
}
38
39
40
bool
41
AudioWorkletNodeOptions::InitIds(JSContext* cx, AudioWorkletNodeOptionsAtoms* atomsCache)
42
0
{
43
0
  MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache));
44
0
45
0
  // Initialize these in reverse order so that any failure leaves the first one
46
0
  // uninitialized.
47
0
  if (!atomsCache->processorOptions_id.init(cx, "processorOptions") ||
48
0
      !atomsCache->parameterData_id.init(cx, "parameterData") ||
49
0
      !atomsCache->outputChannelCount_id.init(cx, "outputChannelCount") ||
50
0
      !atomsCache->numberOfOutputs_id.init(cx, "numberOfOutputs") ||
51
0
      !atomsCache->numberOfInputs_id.init(cx, "numberOfInputs")) {
52
0
    return false;
53
0
  }
54
0
  return true;
55
0
}
56
57
bool
58
AudioWorkletNodeOptions::Init(JSContext* cx, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
59
0
{
60
0
  // Passing a null JSContext is OK only if we're initing from null,
61
0
  // Since in that case we will not have to do any property gets
62
0
  // Also evaluate isNullOrUndefined in order to avoid false-positive
63
0
  // checkers by static analysis tools
64
0
  MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
65
0
  AudioWorkletNodeOptionsAtoms* atomsCache = nullptr;
66
0
  if (cx) {
67
0
    atomsCache = GetAtomCache<AudioWorkletNodeOptionsAtoms>(cx);
68
0
    if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
69
0
      return false;
70
0
    }
71
0
  }
72
0
73
0
  // Per spec, we init the parent's members first
74
0
  if (!AudioNodeOptions::Init(cx, val)) {
75
0
    return false;
76
0
  }
77
0
78
0
  bool isNull = val.isNullOrUndefined();
79
0
  // We only need these if !isNull, in which case we have |cx|.
80
0
  Maybe<JS::Rooted<JSObject *> > object;
81
0
  Maybe<JS::Rooted<JS::Value> > temp;
82
0
  if (!isNull) {
83
0
    MOZ_ASSERT(cx);
84
0
    object.emplace(cx, &val.toObject());
85
0
    temp.emplace(cx);
86
0
  }
87
0
  if (!isNull) {
88
0
    if (!JS_GetPropertyById(cx, *object, atomsCache->numberOfInputs_id, temp.ptr())) {
89
0
      return false;
90
0
    }
91
0
  }
92
0
  if (!isNull && !temp->isUndefined()) {
93
0
    if (!ValueToPrimitive<uint32_t, eDefault>(cx, temp.ref(), &mNumberOfInputs)) {
94
0
      return false;
95
0
    }
96
0
  } else {
97
0
    mNumberOfInputs = 1U;
98
0
  }
99
0
  mIsAnyMemberPresent = true;
100
0
101
0
  if (!isNull) {
102
0
    if (!JS_GetPropertyById(cx, *object, atomsCache->numberOfOutputs_id, temp.ptr())) {
103
0
      return false;
104
0
    }
105
0
  }
106
0
  if (!isNull && !temp->isUndefined()) {
107
0
    if (!ValueToPrimitive<uint32_t, eDefault>(cx, temp.ref(), &mNumberOfOutputs)) {
108
0
      return false;
109
0
    }
110
0
  } else {
111
0
    mNumberOfOutputs = 1U;
112
0
  }
113
0
  mIsAnyMemberPresent = true;
114
0
115
0
  if (!isNull) {
116
0
    if (!JS_GetPropertyById(cx, *object, atomsCache->outputChannelCount_id, temp.ptr())) {
117
0
      return false;
118
0
    }
119
0
  }
120
0
  if (!isNull && !temp->isUndefined()) {
121
0
    mOutputChannelCount.Construct();
122
0
    if (temp.ref().isObject()) {
123
0
      JS::ForOfIterator iter(cx);
124
0
      if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) {
125
0
        return false;
126
0
      }
127
0
      if (!iter.valueIsIterable()) {
128
0
        ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "'outputChannelCount' member of AudioWorkletNodeOptions");
129
0
        return false;
130
0
      }
131
0
      Sequence<uint32_t> &arr = (mOutputChannelCount.Value());
132
0
      JS::Rooted<JS::Value> temp(cx);
133
0
      while (true) {
134
0
        bool done;
135
0
        if (!iter.next(&temp, &done)) {
136
0
          return false;
137
0
        }
138
0
        if (done) {
139
0
          break;
140
0
        }
141
0
        uint32_t* slotPtr = arr.AppendElement(mozilla::fallible);
142
0
        if (!slotPtr) {
143
0
          JS_ReportOutOfMemory(cx);
144
0
          return false;
145
0
        }
146
0
        uint32_t& slot = *slotPtr;
147
0
        if (!ValueToPrimitive<uint32_t, eDefault>(cx, temp, &slot)) {
148
0
          return false;
149
0
        }
150
0
      }
151
0
    } else {
152
0
      ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "'outputChannelCount' member of AudioWorkletNodeOptions");
153
0
      return false;
154
0
    }
155
0
    mIsAnyMemberPresent = true;
156
0
  }
157
0
158
0
  if (!isNull) {
159
0
    if (!JS_GetPropertyById(cx, *object, atomsCache->parameterData_id, temp.ptr())) {
160
0
      return false;
161
0
    }
162
0
  }
163
0
  if (!isNull && !temp->isUndefined()) {
164
0
    mParameterData.Construct();
165
0
    if (temp.ref().isObject()) {
166
0
      auto& recordEntries = (mParameterData.Value()).Entries();
167
0
168
0
      JS::Rooted<JSObject*> recordObj(cx, &temp.ref().toObject());
169
0
      JS::AutoIdVector ids(cx);
170
0
      if (!js::GetPropertyKeys(cx, recordObj,
171
0
                               JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) {
172
0
        return false;
173
0
      }
174
0
      if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) {
175
0
        JS_ReportOutOfMemory(cx);
176
0
        return false;
177
0
      }
178
0
      JS::Rooted<JS::Value> propNameValue(cx);
179
0
      JS::Rooted<JS::Value> temp(cx);
180
0
      JS::Rooted<jsid> curId(cx);
181
0
      JS::Rooted<JS::Value> idVal(cx);
182
0
      // Use a hashset to keep track of ids seen, to avoid
183
0
      // introducing nasty O(N^2) behavior scanning for them all the
184
0
      // time.  Ideally we'd use a data structure with O(1) lookup
185
0
      // _and_ ordering for the MozMap, but we don't have one lying
186
0
      // around.
187
0
      nsTHashtable<nsStringHashKey> idsSeen;
188
0
      for (size_t i = 0; i < ids.length(); ++i) {
189
0
        curId = ids[i];
190
0
191
0
        JS::Rooted<JS::PropertyDescriptor> desc(cx);
192
0
        if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId,
193
0
                                             &desc)) {
194
0
          return false;
195
0
        }
196
0
197
0
        if (!desc.object() /* == undefined in spec terms */ ||
198
0
            !desc.enumerable()) {
199
0
          continue;
200
0
        }
201
0
202
0
        idVal = js::IdToValue(curId);
203
0
        nsString propName;
204
0
        // This will just throw if idVal is a Symbol, like the spec says
205
0
        // to do.
206
0
        if (!ConvertJSValueToString(cx, idVal, propName)) {
207
0
          return false;
208
0
        }
209
0
210
0
        if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) {
211
0
          return false;
212
0
        }
213
0
214
0
        Record<nsString, double>::EntryType* entry;
215
0
        if (!idsSeen.EnsureInserted(propName)) {
216
0
          // Find the existing entry.
217
0
          auto idx = recordEntries.IndexOf(propName);
218
0
          MOZ_ASSERT(idx != recordEntries.NoIndex,
219
0
                     "Why is it not found?");
220
0
          // Now blow it away to make it look like it was just added
221
0
          // to the array, because it's not obvious that it's
222
0
          // safe to write to its already-initialized mValue via our
223
0
          // normal codegen conversions.  For example, the value
224
0
          // could be a union and this would change its type, but
225
0
          // codegen assumes we won't do that.
226
0
          entry = recordEntries.ReconstructElementAt(idx);
227
0
        } else {
228
0
          // Safe to do an infallible append here, because we did a
229
0
          // SetCapacity above to the right capacity.
230
0
          entry = recordEntries.AppendElement();
231
0
        }
232
0
        entry->mKey = propName;
233
0
        double& slot = entry->mValue;
234
0
        if (!ValueToPrimitive<double, eDefault>(cx, temp, &slot)) {
235
0
          return false;
236
0
        } else if (!mozilla::IsFinite(slot)) {
237
0
          ThrowErrorMessage(cx, MSG_NOT_FINITE, "Value in 'parameterData' member of AudioWorkletNodeOptions");
238
0
          return false;
239
0
        }
240
0
      }
241
0
    } else {
242
0
      ThrowErrorMessage(cx, MSG_NOT_OBJECT, "'parameterData' member of AudioWorkletNodeOptions");
243
0
      return false;
244
0
    }
245
0
    mIsAnyMemberPresent = true;
246
0
  }
247
0
248
0
  if (!isNull) {
249
0
    if (!JS_GetPropertyById(cx, *object, atomsCache->processorOptions_id, temp.ptr())) {
250
0
      return false;
251
0
    }
252
0
  }
253
0
  if (!isNull && !temp->isUndefined()) {
254
0
    if (temp.ref().isObject()) {
255
0
#ifdef __clang__
256
0
#pragma clang diagnostic push
257
0
#pragma clang diagnostic ignored "-Wunreachable-code"
258
0
#pragma clang diagnostic ignored "-Wunreachable-code-return"
259
0
#endif // __clang__
260
0
      if ((passedToJSImpl) && !CallerSubsumes(temp.ref())) {
261
0
        ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "'processorOptions' member of AudioWorkletNodeOptions");
262
0
        return false;
263
0
      }
264
0
#ifdef __clang__
265
0
#pragma clang diagnostic pop
266
0
#endif // __clang__
267
0
      mProcessorOptions = &temp.ref().toObject();
268
0
    } else if (temp.ref().isNullOrUndefined()) {
269
0
      mProcessorOptions = nullptr;
270
0
    } else {
271
0
      ThrowErrorMessage(cx, MSG_NOT_OBJECT, "'processorOptions' member of AudioWorkletNodeOptions");
272
0
      return false;
273
0
    }
274
0
  } else {
275
0
    mProcessorOptions = nullptr;
276
0
  }
277
0
  mIsAnyMemberPresent = true;
278
0
  return true;
279
0
}
280
281
bool
282
AudioWorkletNodeOptions::ToObjectInternal(JSContext* cx, JS::MutableHandle<JS::Value> rval) const
283
0
{
284
0
  AudioWorkletNodeOptionsAtoms* atomsCache = GetAtomCache<AudioWorkletNodeOptionsAtoms>(cx);
285
0
  if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
286
0
    return false;
287
0
  }
288
0
289
0
  // Per spec, we define the parent's members first
290
0
  if (!AudioNodeOptions::ToObjectInternal(cx, rval)) {
291
0
    return false;
292
0
  }
293
0
  JS::Rooted<JSObject*> obj(cx, &rval.toObject());
294
0
295
0
  do {
296
0
    // block for our 'break' successCode and scope for 'temp' and 'currentValue'
297
0
    JS::Rooted<JS::Value> temp(cx);
298
0
    uint32_t const & currentValue = mNumberOfInputs;
299
0
    temp.setNumber(currentValue);
300
0
    if (!JS_DefinePropertyById(cx, obj, atomsCache->numberOfInputs_id, temp, JSPROP_ENUMERATE)) {
301
0
      return false;
302
0
    }
303
0
    break;
304
0
  } while(false);
305
0
306
0
  do {
307
0
    // block for our 'break' successCode and scope for 'temp' and 'currentValue'
308
0
    JS::Rooted<JS::Value> temp(cx);
309
0
    uint32_t const & currentValue = mNumberOfOutputs;
310
0
    temp.setNumber(currentValue);
311
0
    if (!JS_DefinePropertyById(cx, obj, atomsCache->numberOfOutputs_id, temp, JSPROP_ENUMERATE)) {
312
0
      return false;
313
0
    }
314
0
    break;
315
0
  } while(false);
316
0
317
0
  if (mOutputChannelCount.WasPassed()) {
318
0
    do {
319
0
      // block for our 'break' successCode and scope for 'temp' and 'currentValue'
320
0
      JS::Rooted<JS::Value> temp(cx);
321
0
      Sequence<uint32_t> const & currentValue = mOutputChannelCount.InternalValue();
322
0
323
0
      uint32_t length = currentValue.Length();
324
0
      JS::Rooted<JSObject*> returnArray(cx, JS_NewArrayObject(cx, length));
325
0
      if (!returnArray) {
326
0
        return false;
327
0
      }
328
0
      // Scope for 'tmp'
329
0
      {
330
0
        JS::Rooted<JS::Value> tmp(cx);
331
0
        for (uint32_t sequenceIdx0 = 0; sequenceIdx0 < length; ++sequenceIdx0) {
332
0
          // Control block to let us common up the JS_DefineElement calls when there
333
0
          // are different ways to succeed at wrapping the object.
334
0
          do {
335
0
            tmp.setNumber(currentValue[sequenceIdx0]);
336
0
            break;
337
0
          } while (false);
338
0
          if (!JS_DefineElement(cx, returnArray, sequenceIdx0, tmp,
339
0
                                JSPROP_ENUMERATE)) {
340
0
            return false;
341
0
          }
342
0
        }
343
0
      }
344
0
      temp.setObject(*returnArray);
345
0
      if (!JS_DefinePropertyById(cx, obj, atomsCache->outputChannelCount_id, temp, JSPROP_ENUMERATE)) {
346
0
        return false;
347
0
      }
348
0
      break;
349
0
    } while(false);
350
0
  }
351
0
352
0
  if (mParameterData.WasPassed()) {
353
0
    do {
354
0
      // block for our 'break' successCode and scope for 'temp' and 'currentValue'
355
0
      JS::Rooted<JS::Value> temp(cx);
356
0
      Record<nsString, double> const & currentValue = mParameterData.InternalValue();
357
0
358
0
      JS::Rooted<JSObject*> returnObj(cx, JS_NewPlainObject(cx));
359
0
      if (!returnObj) {
360
0
        return false;
361
0
      }
362
0
      // Scope for 'tmp'
363
0
      {
364
0
        JS::Rooted<JS::Value> tmp(cx);
365
0
        for (auto& entry : currentValue.Entries()) {
366
0
          auto& recordValue0 = entry.mValue;
367
0
          // Control block to let us common up the JS_DefineUCProperty calls when there
368
0
          // are different ways to succeed at wrapping the value.
369
0
          do {
370
0
            tmp.set(JS_NumberValue(double(recordValue0)));
371
0
            break;
372
0
          } while (false);
373
0
          if (!JS_DefineUCProperty(cx, returnObj,
374
0
                                   entry.mKey.BeginReading(),
375
0
                                   entry.mKey.Length(), tmp,
376
0
                                   JSPROP_ENUMERATE)) {
377
0
            return false;
378
0
          }
379
0
        }
380
0
      }
381
0
      temp.setObject(*returnObj);
382
0
      if (!JS_DefinePropertyById(cx, obj, atomsCache->parameterData_id, temp, JSPROP_ENUMERATE)) {
383
0
        return false;
384
0
      }
385
0
      break;
386
0
    } while(false);
387
0
  }
388
0
389
0
  do {
390
0
    // block for our 'break' successCode and scope for 'temp' and 'currentValue'
391
0
    JS::Rooted<JS::Value> temp(cx);
392
0
    JSObject* const & currentValue = mProcessorOptions;
393
0
    if (currentValue) {
394
0
                  JS::ExposeObjectToActiveJS(currentValue);
395
0
                }
396
0
                temp.setObjectOrNull(currentValue);
397
0
    if (!MaybeWrapObjectOrNullValue(cx, &temp)) {
398
0
      return false;
399
0
    }
400
0
    if (!JS_DefinePropertyById(cx, obj, atomsCache->processorOptions_id, temp, JSPROP_ENUMERATE)) {
401
0
      return false;
402
0
    }
403
0
    break;
404
0
  } while(false);
405
0
406
0
  return true;
407
0
}
408
409
void
410
AudioWorkletNodeOptions::TraceDictionary(JSTracer* trc)
411
0
{
412
0
  AudioNodeOptions::TraceDictionary(trc);
413
0
  if (mProcessorOptions) {
414
0
    JS::UnsafeTraceRoot(trc, &mProcessorOptions, "AudioWorkletNodeOptions.mProcessorOptions");
415
0
  }
416
0
}
417
418
namespace binding_detail {
419
} // namespace binding_detail
420
421
422
namespace AudioWorkletNode_Binding {
423
424
static_assert(IsRefcounted<NativeType>::value == IsRefcounted<AudioNode_Binding::NativeType>::value,
425
              "Can't inherit from an interface with a different ownership model.");
426
427
MOZ_CAN_RUN_SCRIPT static bool
428
get_parameters(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::AudioWorkletNode* self, JSJitGetterCallArgs args)
429
0
{
430
0
  AUTO_PROFILER_LABEL_FAST("get AudioWorkletNode.parameters", DOM, cx);
431
0
432
0
  FastErrorResult rv;
433
0
  auto result(StrongOrRawPtr<mozilla::dom::AudioParamMap>(self->GetParameters(rv)));
434
0
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
435
0
    return false;
436
0
  }
437
0
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
438
0
  if (!GetOrCreateDOMReflector(cx, result, args.rval())) {
439
0
    MOZ_ASSERT(JS_IsExceptionPending(cx));
440
0
    return false;
441
0
  }
442
0
  return true;
443
0
}
444
445
static const JSJitInfo parameters_getterinfo = {
446
  { (JSJitGetterOp)get_parameters },
447
  { prototypes::id::AudioWorkletNode },
448
  { PrototypeTraits<prototypes::id::AudioWorkletNode>::Depth },
449
  JSJitInfo::Getter,
450
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
451
  JSVAL_TYPE_OBJECT,  /* returnType.  Not relevant for setters. */
452
  false,  /* isInfallible. False in setters. */
453
  false,  /* isMovable.  Not relevant for setters. */
454
  false, /* isEliminatable.  Not relevant for setters. */
455
  false, /* isAlwaysInSlot.  Only relevant for getters. */
456
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
457
  false,  /* isTypedMethod.  Only relevant for methods. */
458
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
459
};
460
static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
461
static_assert(0 < 1, "There is no slot for us");
462
463
MOZ_CAN_RUN_SCRIPT static bool
464
get_port(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::AudioWorkletNode* self, JSJitGetterCallArgs args)
465
0
{
466
0
  AUTO_PROFILER_LABEL_FAST("get AudioWorkletNode.port", DOM, cx);
467
0
468
0
  FastErrorResult rv;
469
0
  auto result(StrongOrRawPtr<mozilla::dom::MessagePort>(self->GetPort(rv)));
470
0
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
471
0
    return false;
472
0
  }
473
0
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
474
0
  if (!GetOrCreateDOMReflector(cx, result, args.rval())) {
475
0
    MOZ_ASSERT(JS_IsExceptionPending(cx));
476
0
    return false;
477
0
  }
478
0
  return true;
479
0
}
480
481
static const JSJitInfo port_getterinfo = {
482
  { (JSJitGetterOp)get_port },
483
  { prototypes::id::AudioWorkletNode },
484
  { PrototypeTraits<prototypes::id::AudioWorkletNode>::Depth },
485
  JSJitInfo::Getter,
486
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
487
  JSVAL_TYPE_OBJECT,  /* returnType.  Not relevant for setters. */
488
  false,  /* isInfallible. False in setters. */
489
  false,  /* isMovable.  Not relevant for setters. */
490
  false, /* isEliminatable.  Not relevant for setters. */
491
  false, /* isAlwaysInSlot.  Only relevant for getters. */
492
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
493
  false,  /* isTypedMethod.  Only relevant for methods. */
494
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
495
};
496
static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
497
static_assert(0 < 1, "There is no slot for us");
498
499
MOZ_CAN_RUN_SCRIPT static bool
500
get_onprocessorerror(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::AudioWorkletNode* self, JSJitGetterCallArgs args)
501
0
{
502
0
  AUTO_PROFILER_LABEL_FAST("get AudioWorkletNode.onprocessorerror", DOM, cx);
503
0
504
0
  RefPtr<EventHandlerNonNull> result(self->GetOnprocessorerror());
505
0
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
506
0
  if (result) {
507
0
    args.rval().setObjectOrNull(GetCallbackFromCallbackObject(cx, result));
508
0
    if (!MaybeWrapObjectOrNullValue(cx, args.rval())) {
509
0
      return false;
510
0
    }
511
0
    return true;
512
0
  } else {
513
0
    args.rval().setNull();
514
0
    return true;
515
0
  }
516
0
}
517
518
MOZ_CAN_RUN_SCRIPT static bool
519
set_onprocessorerror(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::AudioWorkletNode* self, JSJitSetterCallArgs args)
520
0
{
521
0
  AUTO_PROFILER_LABEL_FAST("set AudioWorkletNode.onprocessorerror", DOM, cx);
522
0
523
0
  RootedCallback<RefPtr<binding_detail::FastEventHandlerNonNull>> arg0(cx);
524
0
  if (args[0].isObject()) {
525
0
    { // scope for tempRoot and tempGlobalRoot if needed
526
0
      arg0 = new binding_detail::FastEventHandlerNonNull(&args[0].toObject(), JS::CurrentGlobalOrNull(cx));
527
0
    }
528
0
  } else {
529
0
    arg0 = nullptr;
530
0
  }
531
0
  self->SetOnprocessorerror(Constify(arg0));
532
0
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
533
0
534
0
  return true;
535
0
}
536
537
static const JSJitInfo onprocessorerror_getterinfo = {
538
  { (JSJitGetterOp)get_onprocessorerror },
539
  { prototypes::id::AudioWorkletNode },
540
  { PrototypeTraits<prototypes::id::AudioWorkletNode>::Depth },
541
  JSJitInfo::Getter,
542
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
543
  JSVAL_TYPE_UNKNOWN,  /* returnType.  Not relevant for setters. */
544
  false,  /* isInfallible. False in setters. */
545
  false,  /* isMovable.  Not relevant for setters. */
546
  false, /* isEliminatable.  Not relevant for setters. */
547
  false, /* isAlwaysInSlot.  Only relevant for getters. */
548
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
549
  false,  /* isTypedMethod.  Only relevant for methods. */
550
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
551
};
552
static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
553
static_assert(0 < 1, "There is no slot for us");
554
static const JSJitInfo onprocessorerror_setterinfo = {
555
  { (JSJitGetterOp)set_onprocessorerror },
556
  { prototypes::id::AudioWorkletNode },
557
  { PrototypeTraits<prototypes::id::AudioWorkletNode>::Depth },
558
  JSJitInfo::Setter,
559
  JSJitInfo::AliasEverything, /* aliasSet.  Not relevant for setters. */
560
  JSVAL_TYPE_UNDEFINED,  /* returnType.  Not relevant for setters. */
561
  false,  /* isInfallible. False in setters. */
562
  false,  /* isMovable.  Not relevant for setters. */
563
  false, /* isEliminatable.  Not relevant for setters. */
564
  false, /* isAlwaysInSlot.  Only relevant for getters. */
565
  false, /* isLazilyCachedInSlot.  Only relevant for getters. */
566
  false,  /* isTypedMethod.  Only relevant for methods. */
567
  0   /* Reserved slot index, if we're stored in a slot, else 0. */
568
};
569
static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
570
static_assert(0 < 1, "There is no slot for us");
571
572
static bool
573
_addProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> val)
574
0
{
575
0
  mozilla::dom::AudioWorkletNode* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::AudioWorkletNode>(obj);
576
0
  // We don't want to preserve if we don't have a wrapper, and we
577
0
  // obviously can't preserve if we're not initialized.
578
0
  if (self && self->GetWrapperPreserveColor()) {
579
0
    PreserveWrapper(self);
580
0
  }
581
0
  return true;
582
0
}
583
584
static void
585
_finalize(js::FreeOp* fop, JSObject* obj)
586
0
{
587
0
  mozilla::dom::AudioWorkletNode* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::AudioWorkletNode>(obj);
588
0
  if (self) {
589
0
    ClearWrapper(self, self, obj);
590
0
    AddForDeferredFinalization<mozilla::dom::AudioWorkletNode>(self);
591
0
  }
592
0
}
593
594
static size_t
595
_objectMoved(JSObject* obj, JSObject* old)
596
0
{
597
0
  mozilla::dom::AudioWorkletNode* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::AudioWorkletNode>(obj);
598
0
  if (self) {
599
0
    UpdateWrapper(self, self, obj, old);
600
0
  }
601
0
602
0
  return 0;
603
0
}
604
605
// We deliberately use brace-elision to make Visual Studio produce better initalization code.
606
#if defined(__clang__)
607
#pragma clang diagnostic push
608
#pragma clang diagnostic ignored "-Wmissing-braces"
609
#endif
610
static const JSPropertySpec sAttributes_specs[] = {
611
  { "parameters", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &parameters_getterinfo, nullptr, nullptr },
612
  { "port", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &port_getterinfo, nullptr, nullptr },
613
  { "onprocessorerror", JSPROP_ENUMERATE, GenericGetter<NormalThisPolicy, ThrowExceptions>, &onprocessorerror_getterinfo, GenericSetter<NormalThisPolicy>, &onprocessorerror_setterinfo },
614
  { nullptr, 0, nullptr, nullptr, nullptr, nullptr }
615
};
616
#if defined(__clang__)
617
#pragma clang diagnostic pop
618
#endif
619
620
// Can't be const because the pref-enabled boolean needs to be writable
621
static PrefableDisablers sAttributes_disablers0 = {
622
  true, true, 0, nullptr
623
};
624
625
static const Prefable<const JSPropertySpec> sAttributes[] = {
626
  { &sAttributes_disablers0, &sAttributes_specs[0] },
627
  { nullptr, nullptr }
628
};
629
630
static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
631
    "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
632
static_assert(3 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
633
    "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");
634
635
636
static uint16_t sNativeProperties_sortedPropertyIndices[3];
637
static PropertyInfo sNativeProperties_propertyInfos[3];
638
639
static const NativePropertiesN<1> sNativeProperties = {
640
  false, 0,
641
  false, 0,
642
  false, 0,
643
  true,  0 /* sAttributes */,
644
  false, 0,
645
  false, 0,
646
  false, 0,
647
  -1,
648
  3,
649
  sNativeProperties_sortedPropertyIndices,
650
  {
651
    { sAttributes, &sNativeProperties_propertyInfos[0] }
652
  }
653
};
654
static_assert(3 < 1ull << CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount),
655
    "We have a property info count that is oversized");
656
657
static bool
658
_constructor(JSContext* cx, unsigned argc, JS::Value* vp)
659
0
{
660
0
  AUTO_PROFILER_LABEL_FAST("AudioWorkletNode constructor", DOM, cx);
661
0
662
0
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
663
0
  JS::Rooted<JSObject*> obj(cx, &args.callee());
664
0
  if (!args.isConstructing()) {
665
0
    // XXXbz wish I could get the name from the callee instead of
666
0
    // Adding more relocations
667
0
    return ThrowConstructorWithoutNew(cx, "AudioWorkletNode");
668
0
  }
669
0
670
0
  JS::Rooted<JSObject*> desiredProto(cx);
671
0
  if (!GetDesiredProto(cx, args, &desiredProto)) {
672
0
    return false;
673
0
  }
674
0
675
0
  if (MOZ_UNLIKELY(args.length() < 2)) {
676
0
    return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "AudioWorkletNode");
677
0
  }
678
0
  GlobalObject global(cx, obj);
679
0
  if (global.Failed()) {
680
0
    return false;
681
0
  }
682
0
683
0
  bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
684
0
  NonNull<mozilla::dom::AudioContext> arg0;
685
0
  if (args[0].isObject()) {
686
0
    {
687
0
      nsresult rv = UnwrapObject<prototypes::id::BaseAudioContext, mozilla::dom::AudioContext>(args[0], arg0);
688
0
      if (NS_FAILED(rv)) {
689
0
        ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "Argument 1 of AudioWorkletNode.constructor", "BaseAudioContext");
690
0
        return false;
691
0
      }
692
0
    }
693
0
  } else {
694
0
    ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 1 of AudioWorkletNode.constructor");
695
0
    return false;
696
0
  }
697
0
  binding_detail::FakeString arg1;
698
0
  if (!ConvertJSValueToString(cx, args[1], eStringify, eStringify, arg1)) {
699
0
    return false;
700
0
  }
701
0
  RootedDictionary<binding_detail::FastAudioWorkletNodeOptions> arg2(cx);
702
0
  if (!arg2.Init(cx, (args.hasDefined(2)) ? args[2] : JS::NullHandleValue,  "Argument 3 of AudioWorkletNode.constructor", false)) {
703
0
    return false;
704
0
  }
705
0
  Maybe<JSAutoRealm> ar;
706
0
  if (objIsXray) {
707
0
    obj = js::CheckedUnwrap(obj);
708
0
    if (!obj) {
709
0
      return false;
710
0
    }
711
0
    ar.emplace(cx, obj);
712
0
    if (!JS_WrapObject(cx, &desiredProto)) {
713
0
      return false;
714
0
    }
715
0
    if (!JS_WrapObject(cx, JS::MutableHandle<JSObject*>::fromMarkedLocation(&arg2.mProcessorOptions))) {
716
0
      return false;
717
0
    }
718
0
  }
719
0
  FastErrorResult rv;
720
0
  auto result(StrongOrRawPtr<mozilla::dom::AudioWorkletNode>(mozilla::dom::AudioWorkletNode::Constructor(global, MOZ_KnownLive(NonNullHelper(arg0)), NonNullHelper(Constify(arg1)), Constify(arg2), rv)));
721
0
  if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
722
0
    return false;
723
0
  }
724
0
  MOZ_ASSERT(!JS_IsExceptionPending(cx));
725
0
  static_assert(!IsPointer<decltype(result)>::value,
726
0
                "NewObject implies that we need to keep the object alive with a strong reference.");
727
0
  if (!GetOrCreateDOMReflector(cx, result, args.rval(), desiredProto)) {
728
0
    MOZ_ASSERT(JS_IsExceptionPending(cx));
729
0
    return false;
730
0
  }
731
0
  return true;
732
0
}
733
734
static const js::ClassOps sInterfaceObjectClassOps = {
735
    nullptr,               /* addProperty */
736
    nullptr,               /* delProperty */
737
    nullptr,               /* enumerate */
738
    nullptr,               /* newEnumerate */
739
    nullptr,               /* resolve */
740
    nullptr,               /* mayResolve */
741
    nullptr,               /* finalize */
742
    _constructor, /* call */
743
    nullptr,               /* hasInstance */
744
    _constructor, /* construct */
745
    nullptr,               /* trace */
746
};
747
748
static const DOMIfaceAndProtoJSClass sInterfaceObjectClass = {
749
  {
750
    "Function",
751
    JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_SLOTS_BASE),
752
    &sInterfaceObjectClassOps,
753
    JS_NULL_CLASS_SPEC,
754
    JS_NULL_CLASS_EXT,
755
    &sInterfaceObjectClassObjectOps
756
  },
757
  eInterface,
758
  true,
759
  prototypes::id::AudioWorkletNode,
760
  PrototypeTraits<prototypes::id::AudioWorkletNode>::Depth,
761
  sNativePropertyHooks,
762
  "function AudioWorkletNode() {\n    [native code]\n}",
763
  AudioNode_Binding::GetConstructorObject
764
};
765
766
static const DOMIfaceAndProtoJSClass sPrototypeClass = {
767
  {
768
    "AudioWorkletNodePrototype",
769
    JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE),
770
    JS_NULL_CLASS_OPS,
771
    JS_NULL_CLASS_SPEC,
772
    JS_NULL_CLASS_EXT,
773
    JS_NULL_OBJECT_OPS
774
  },
775
  eInterfacePrototype,
776
  false,
777
  prototypes::id::AudioWorkletNode,
778
  PrototypeTraits<prototypes::id::AudioWorkletNode>::Depth,
779
  sNativePropertyHooks,
780
  "[object AudioWorkletNodePrototype]",
781
  AudioNode_Binding::GetProtoObject
782
};
783
784
bool
785
ConstructorEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj)
786
0
{
787
0
  static bool sPrefValue;
788
0
  static bool sPrefCacheSetUp = false;
789
0
  if (!sPrefCacheSetUp) {
790
0
    sPrefCacheSetUp = true;
791
0
    Preferences::AddBoolVarCache(&sPrefValue, "dom.audioworklet.enabled");
792
0
  }
793
0
794
0
  return sPrefValue &&
795
0
         mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj);
796
0
}
797
798
static const js::ClassOps sClassOps = {
799
  _addProperty, /* addProperty */
800
  nullptr,               /* delProperty */
801
  nullptr,               /* enumerate */
802
  nullptr, /* newEnumerate */
803
  nullptr, /* resolve */
804
  nullptr, /* mayResolve */
805
  _finalize, /* finalize */
806
  nullptr, /* call */
807
  nullptr,               /* hasInstance */
808
  nullptr,               /* construct */
809
  nullptr, /* trace */
810
};
811
812
static const js::ClassExtension sClassExtension = {
813
  nullptr, /* weakmapKeyDelegateOp */
814
  _objectMoved /* objectMovedOp */
815
};
816
817
static const DOMJSClass sClass = {
818
  { "AudioWorkletNode",
819
    JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1),
820
    &sClassOps,
821
    JS_NULL_CLASS_SPEC,
822
    &sClassExtension,
823
    JS_NULL_OBJECT_OPS
824
  },
825
  { prototypes::id::EventTarget, prototypes::id::AudioNode, prototypes::id::AudioWorkletNode, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count },
826
  IsBaseOf<nsISupports, mozilla::dom::AudioWorkletNode >::value,
827
  sNativePropertyHooks,
828
  FindAssociatedGlobalForNative<mozilla::dom::AudioWorkletNode>::Get,
829
  GetProtoObjectHandle,
830
  GetCCParticipant<mozilla::dom::AudioWorkletNode>::Get()
831
};
832
static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS,
833
              "Must have the right minimal number of reserved slots.");
834
static_assert(1 >= 1,
835
              "Must have enough reserved slots.");
836
837
const JSClass*
838
GetJSClass()
839
0
{
840
0
  return sClass.ToJSClass();
841
0
}
842
843
bool
844
Wrap(JSContext* aCx, mozilla::dom::AudioWorkletNode* aObject, nsWrapperCache* aCache, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
845
0
{
846
0
  static_assert(!IsBaseOf<NonRefcountedDOMObject, mozilla::dom::AudioWorkletNode>::value,
847
0
                "Shouldn't have wrappercached things that are not refcounted.");
848
0
  MOZ_ASSERT(static_cast<mozilla::dom::AudioWorkletNode*>(aObject) ==
849
0
             reinterpret_cast<mozilla::dom::AudioWorkletNode*>(aObject),
850
0
             "Multiple inheritance for mozilla::dom::AudioWorkletNode is broken.");
851
0
  MOZ_ASSERT(static_cast<mozilla::dom::AudioNode*>(aObject) ==
852
0
             reinterpret_cast<mozilla::dom::AudioNode*>(aObject),
853
0
             "Multiple inheritance for mozilla::dom::AudioNode is broken.");
854
0
  MOZ_ASSERT(static_cast<mozilla::dom::EventTarget*>(aObject) ==
855
0
             reinterpret_cast<mozilla::dom::EventTarget*>(aObject),
856
0
             "Multiple inheritance for mozilla::dom::EventTarget is broken.");
857
0
  MOZ_ASSERT(ToSupportsIsCorrect(aObject));
858
0
  MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
859
0
  MOZ_ASSERT(!aCache->GetWrapper(),
860
0
             "You should probably not be using Wrap() directly; use "
861
0
             "GetOrCreateDOMReflector instead");
862
0
863
0
  MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
864
0
             "nsISupports must be on our primary inheritance chain");
865
0
866
0
  JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
867
0
  if (!global) {
868
0
    return false;
869
0
  }
870
0
  MOZ_ASSERT(JS_IsGlobalObject(global));
871
0
  MOZ_ASSERT(JS::ObjectIsNotGray(global));
872
0
873
0
  // That might have ended up wrapping us already, due to the wonders
874
0
  // of XBL.  Check for that, and bail out as needed.
875
0
  aReflector.set(aCache->GetWrapper());
876
0
  if (aReflector) {
877
#ifdef DEBUG
878
    AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
879
#endif // DEBUG
880
    return true;
881
0
  }
882
0
883
0
  JSAutoRealm ar(aCx, global);
884
0
  JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
885
0
  if (!canonicalProto) {
886
0
    return false;
887
0
  }
888
0
  JS::Rooted<JSObject*> proto(aCx);
889
0
  if (aGivenProto) {
890
0
    proto = aGivenProto;
891
0
    // Unfortunately, while aGivenProto was in the compartment of aCx
892
0
    // coming in, we changed compartments to that of "parent" so may need
893
0
    // to wrap the proto here.
894
0
    if (js::GetContextCompartment(aCx) != js::GetObjectCompartment(proto)) {
895
0
      if (!JS_WrapObject(aCx, &proto)) {
896
0
        return false;
897
0
      }
898
0
    }
899
0
  } else {
900
0
    proto = canonicalProto;
901
0
  }
902
0
903
0
  BindingJSObjectCreator<mozilla::dom::AudioWorkletNode> creator(aCx);
904
0
  creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
905
0
  if (!aReflector) {
906
0
    return false;
907
0
  }
908
0
909
0
  aCache->SetWrapper(aReflector);
910
0
  creator.InitializationSucceeded();
911
0
912
0
  MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
913
0
             aCache->GetWrapperPreserveColor() == aReflector);
914
0
  // If proto != canonicalProto, we have to preserve our wrapper;
915
0
  // otherwise we won't be able to properly recreate it later, since
916
0
  // we won't know what proto to use.  Note that we don't check
917
0
  // aGivenProto here, since it's entirely possible (and even
918
0
  // somewhat common) to have a non-null aGivenProto which is the
919
0
  // same as canonicalProto.
920
0
  if (proto != canonicalProto) {
921
0
    PreserveWrapper(aObject);
922
0
  }
923
0
924
0
  return true;
925
0
}
926
927
const NativePropertyHooks sNativePropertyHooks[] = { {
928
  nullptr,
929
  nullptr,
930
  nullptr,
931
  { sNativeProperties.Upcast(), nullptr },
932
  prototypes::id::AudioWorkletNode,
933
  constructors::id::AudioWorkletNode,
934
  AudioNode_Binding::sNativePropertyHooks,
935
  &DefaultXrayExpandoObjectClass
936
} };
937
938
void
939
CreateInterfaceObjects(JSContext* aCx, JS::Handle<JSObject*> aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, bool aDefineOnGlobal)
940
0
{
941
0
  JS::Handle<JSObject*> parentProto(AudioNode_Binding::GetProtoObjectHandle(aCx));
942
0
  if (!parentProto) {
943
0
    return;
944
0
  }
945
0
946
0
  JS::Handle<JSObject*> constructorProto(AudioNode_Binding::GetConstructorObjectHandle(aCx));
947
0
  if (!constructorProto) {
948
0
    return;
949
0
  }
950
0
951
0
  static bool sIdsInited = false;
952
0
  if (!sIdsInited && NS_IsMainThread()) {
953
0
    if (!InitIds(aCx, sNativeProperties.Upcast())) {
954
0
      return;
955
0
    }
956
0
    sIdsInited = true;
957
0
  }
958
0
959
0
  JS::Heap<JSObject*>* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::AudioWorkletNode);
960
0
  JS::Heap<JSObject*>* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::AudioWorkletNode);
961
0
  dom::CreateInterfaceObjects(aCx, aGlobal, parentProto,
962
0
                              &sPrototypeClass.mBase, protoCache,
963
0
                              nullptr,
964
0
                              constructorProto, &sInterfaceObjectClass.mBase, 2, nullptr,
965
0
                              interfaceCache,
966
0
                              sNativeProperties.Upcast(),
967
0
                              nullptr,
968
0
                              "AudioWorkletNode", aDefineOnGlobal,
969
0
                              nullptr,
970
0
                              false);
971
0
}
972
973
JSObject*
974
GetConstructorObject(JSContext* aCx)
975
0
{
976
0
  return GetConstructorObjectHandle(aCx);
977
0
}
978
979
} // namespace AudioWorkletNode_Binding
980
981
982
983
} // namespace dom
984
} // namespace mozilla