Source code

Revision control

Other Tools

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
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef builtin_Promise_h
8
#define builtin_Promise_h
9
10
#include "js/Promise.h"
11
12
#include "builtin/SelfHostingDefines.h"
13
#include "ds/Fifo.h"
14
#include "threading/ConditionVariable.h"
15
#include "threading/Mutex.h"
16
#include "vm/NativeObject.h"
17
18
namespace js {
19
20
enum PromiseSlots {
21
// Int32 value with PROMISE_FLAG_* flags below.
22
PromiseSlot_Flags = 0,
23
24
// * if this promise is pending, reaction objects
25
// * undefined if there's no reaction
26
// * maybe-wrapped PromiseReactionRecord if there's only one reacion
27
// * dense array if there are two or more more reactions
28
// * if this promise is fulfilled, the resolution value
29
// * if this promise is rejected, the reason for the rejection
30
PromiseSlot_ReactionsOrResult,
31
32
// * if this promise is pending, resolve/reject functions.
33
// This slot holds only the reject function. The resolve function is
34
// reachable from the reject function's extended slot.
35
// * if this promise is either fulfilled or rejected, undefined
36
PromiseSlot_RejectFunction,
37
38
// Promise object's debug info, which is created on demand.
39
// * if this promise has no debug info, undefined
40
// * if this promise contains only its process-unique ID, the ID's number
41
// value
42
// * otherwise a PromiseDebugInfo object
43
PromiseSlot_DebugInfo,
44
45
PromiseSlots,
46
};
47
48
// This promise is either fulfilled or rejected.
49
// If this flag is not set, this promise is pending.
50
#define PROMISE_FLAG_RESOLVED 0x1
51
52
// If this flag and PROMISE_FLAG_RESOLVED are set, this promise is fulfilled.
53
// If only PROMISE_FLAG_RESOLVED is set, this promise is rejected.
54
#define PROMISE_FLAG_FULFILLED 0x2
55
56
// Indicates the promise has ever had a fulfillment or rejection handler;
57
// used in unhandled rejection tracking.
58
#define PROMISE_FLAG_HANDLED 0x4
59
60
// This promise uses the default resolving functions.
61
// The PromiseSlot_RejectFunction slot is not used.
62
#define PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS 0x08
63
64
// This promise is either the return value of an async function invocation or
65
// an async generator's method.
66
#define PROMISE_FLAG_ASYNC 0x10
67
68
// This promise knows how to propagate information required to keep track of
69
// whether an activation behavior was in progress when the original promise in
70
// the promise chain was created. This is a concept defined in the HTML spec:
72
// It is used by the embedder in order to request SpiderMonkey to keep track of
73
// this information in a Promise, and also to propagate it to newly created
74
// promises while processing Promise#then.
75
#define PROMISE_FLAG_REQUIRES_USER_INTERACTION_HANDLING 0x20
76
77
// This flag indicates whether an activation behavior was in progress when the
78
// original promise in the promise chain was created. Activation behavior is a
79
// concept defined by the HTML spec:
81
// This flag is only effective when the
82
// PROMISE_FLAG_REQUIRES_USER_INTERACTION_HANDLING is set.
83
#define PROMISE_FLAG_HAD_USER_INTERACTION_UPON_CREATION 0x40
84
85
class AutoSetNewObjectMetadata;
86
87
class PromiseObject : public NativeObject {
88
public:
89
static const unsigned RESERVED_SLOTS = PromiseSlots;
90
static const JSClass class_;
91
static const JSClass protoClass_;
92
static PromiseObject* create(JSContext* cx, HandleObject executor,
93
HandleObject proto = nullptr,
94
bool needsWrapping = false);
95
96
static PromiseObject* createSkippingExecutor(JSContext* cx);
97
98
static JSObject* unforgeableResolve(JSContext* cx, HandleValue value);
99
static JSObject* unforgeableReject(JSContext* cx, HandleValue value);
100
101
int32_t flags() { return getFixedSlot(PromiseSlot_Flags).toInt32(); }
102
void setHandled() {
103
setFixedSlot(PromiseSlot_Flags, Int32Value(flags() | PROMISE_FLAG_HANDLED));
104
}
105
JS::PromiseState state() {
106
int32_t flags = this->flags();
107
if (!(flags & PROMISE_FLAG_RESOLVED)) {
108
MOZ_ASSERT(!(flags & PROMISE_FLAG_FULFILLED));
109
return JS::PromiseState::Pending;
110
}
111
if (flags & PROMISE_FLAG_FULFILLED) {
112
return JS::PromiseState::Fulfilled;
113
}
114
return JS::PromiseState::Rejected;
115
}
116
Value reactions() {
117
MOZ_ASSERT(state() == JS::PromiseState::Pending);
118
return getFixedSlot(PromiseSlot_ReactionsOrResult);
119
}
120
Value value() {
121
MOZ_ASSERT(state() == JS::PromiseState::Fulfilled);
122
return getFixedSlot(PromiseSlot_ReactionsOrResult);
123
}
124
Value reason() {
125
MOZ_ASSERT(state() == JS::PromiseState::Rejected);
126
return getFixedSlot(PromiseSlot_ReactionsOrResult);
127
}
128
Value valueOrReason() {
129
MOZ_ASSERT(state() != JS::PromiseState::Pending);
130
return getFixedSlot(PromiseSlot_ReactionsOrResult);
131
}
132
133
static MOZ_MUST_USE bool resolve(JSContext* cx,
134
Handle<PromiseObject*> promise,
135
HandleValue resolutionValue);
136
static MOZ_MUST_USE bool reject(JSContext* cx, Handle<PromiseObject*> promise,
137
HandleValue rejectionValue);
138
139
static void onSettled(JSContext* cx, Handle<PromiseObject*> promise);
140
141
double allocationTime();
142
double resolutionTime();
143
JSObject* allocationSite();
144
JSObject* resolutionSite();
145
double lifetime();
146
double timeToResolution() {
147
MOZ_ASSERT(state() != JS::PromiseState::Pending);
148
return resolutionTime() - allocationTime();
149
}
150
MOZ_MUST_USE bool dependentPromises(JSContext* cx,
151
MutableHandle<GCVector<Value>> values);
152
153
// Return the process-unique ID of this promise. Only used by the debugger.
154
uint64_t getID();
155
156
bool isUnhandled() {
157
MOZ_ASSERT(state() == JS::PromiseState::Rejected);
158
return !(flags() & PROMISE_FLAG_HANDLED);
159
}
160
161
bool requiresUserInteractionHandling() {
162
return (flags() & PROMISE_FLAG_REQUIRES_USER_INTERACTION_HANDLING);
163
}
164
165
void setRequiresUserInteractionHandling(bool state);
166
167
bool hadUserInteractionUponCreation() {
168
return (flags() & PROMISE_FLAG_HAD_USER_INTERACTION_UPON_CREATION);
169
}
170
171
void setHadUserInteractionUponCreation(bool state);
172
173
void copyUserInteractionFlagsFrom(PromiseObject& rhs);
174
};
175
176
/**
177
* Unforgeable version of the JS builtin Promise.all.
178
*
179
* Takes a HandleValueVector of Promise objects and returns a promise that's
180
* resolved with an array of resolution values when all those promises have
181
* been resolved, or rejected with the rejection value of the first rejected
182
* promise.
183
*
184
* Asserts that all objects in the `promises` vector are, maybe wrapped,
185
* instances of `Promise` or a subclass of `Promise`.
186
*/
187
MOZ_MUST_USE JSObject* GetWaitForAllPromise(JSContext* cx,
188
JS::HandleObjectVector promises);
189
190
// Whether to create a promise as the return value of Promise#{then,catch}.
191
// If the return value is known to be unused, and if the operation is known
192
// to be unobservable, we can skip creating the promise.
193
enum class CreateDependentPromise {
194
// The return value is not known to be unused.
195
Always,
196
197
// The return value is known to be unused.
198
SkipIfCtorUnobservable,
199
200
// The return value is known to be unused, and the operation is known
201
// to be unobservable.
202
Never
203
};
204
205
/**
206
* Enqueues resolve/reject reactions in the given Promise's reactions lists
207
* as though calling the original value of Promise.prototype.then.
208
*
209
* If the `createDependent` flag is not set, no dependent Promise will be
210
* created. This is used internally to implement DOM functionality.
211
* Note: In this case, the reactions pushed using this function contain a
212
* `promise` field that can contain null. That field is only ever used by
213
* devtools, which have to treat these reactions specially.
214
*
215
* Asserts that `promiseObj` is a, maybe wrapped, instance of Promise.
216
*/
217
MOZ_MUST_USE bool OriginalPromiseThen(JSContext* cx, HandleObject promiseObj,
218
HandleValue onFulfilled,
219
HandleValue onRejected,
220
MutableHandleObject dependent,
221
CreateDependentPromise createDependent);
222
223
/**
224
* PromiseResolve ( C, x )
225
*
226
* The abstract operation PromiseResolve, given a constructor and a value,
227
* returns a new promise resolved with that value.
228
*/
229
MOZ_MUST_USE JSObject* PromiseResolve(JSContext* cx, HandleObject constructor,
230
HandleValue value);
231
232
MOZ_MUST_USE bool RejectPromiseWithPendingError(JSContext* cx,
233
Handle<PromiseObject*> promise);
234
235
/**
236
* Create the promise object which will be used as the return value of an async
237
* function.
238
*/
239
MOZ_MUST_USE PromiseObject* CreatePromiseObjectForAsync(JSContext* cx);
240
241
/**
242
* Returns true if the given object is a promise created by
243
* either CreatePromiseObjectForAsync function or async generator's method.
244
*/
245
MOZ_MUST_USE bool IsPromiseForAsyncFunctionOrGenerator(JSObject* promise);
246
247
class AsyncFunctionGeneratorObject;
248
249
MOZ_MUST_USE bool AsyncFunctionReturned(JSContext* cx,
250
Handle<PromiseObject*> resultPromise,
251
HandleValue value);
252
253
MOZ_MUST_USE bool AsyncFunctionThrown(JSContext* cx,
254
Handle<PromiseObject*> resultPromise,
255
HandleValue reason);
256
257
// Start awaiting `value` in an async function (, but doesn't suspend the
258
// async function's execution!). Returns the async function's result promise.
259
MOZ_MUST_USE JSObject* AsyncFunctionAwait(
260
JSContext* cx, Handle<AsyncFunctionGeneratorObject*> genObj,
261
HandleValue value);
262
263
// If the await operation can be skipped and the resolution value for `val` can
264
// be acquired, stored the resolved value to `resolved` and `true` to
265
// `*canSkip`. Otherwise, stores `false` to `*canSkip`.
266
MOZ_MUST_USE bool TrySkipAwait(JSContext* cx, HandleValue val, bool* canSkip,
267
MutableHandleValue resolved);
268
269
class AsyncGeneratorObject;
270
271
MOZ_MUST_USE bool AsyncGeneratorAwait(JSContext* cx,
272
Handle<AsyncGeneratorObject*> asyncGenObj,
273
HandleValue value);
274
275
MOZ_MUST_USE bool AsyncGeneratorResolve(
276
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, HandleValue value,
277
bool done);
278
279
MOZ_MUST_USE bool AsyncGeneratorReject(
280
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
281
HandleValue exception);
282
283
MOZ_MUST_USE bool AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal,
284
CompletionKind completionKind,
285
HandleValue completionValue,
286
MutableHandleValue result);
287
288
bool AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args,
289
CompletionKind completionKind);
290
291
class MOZ_NON_TEMPORARY_CLASS PromiseLookup final {
292
// clang-format off
293
/*
294
* A PromiseLookup holds the following:
295
*
296
* Promise's shape (promiseConstructorShape_)
297
* To ensure that Promise has not been modified.
298
*
299
* Promise.prototype's shape (promiseProtoShape_)
300
* To ensure that Promise.prototype has not been modified.
301
*
302
* Promise's shape for the @@species getter. (promiseSpeciesShape_)
303
* To quickly retrieve the @@species getter for Promise.
304
*
305
* Promise's slot number for resolve (promiseResolveSlot_)
306
* To quickly retrieve the Promise.resolve function.
307
*
308
* Promise.prototype's slot number for constructor (promiseProtoConstructorSlot_)
309
* To quickly retrieve the Promise.prototype.constructor property.
310
*
311
* Promise.prototype's slot number for then (promiseProtoThenSlot_)
312
* To quickly retrieve the Promise.prototype.then function.
313
*
314
* MOZ_INIT_OUTSIDE_CTOR fields below are set in |initialize()|. The
315
* constructor only initializes a |state_| field, that defines whether the
316
* other fields are accessible.
317
*/
318
// clang-format on
319
320
// Shape of matching Promise object.
321
MOZ_INIT_OUTSIDE_CTOR Shape* promiseConstructorShape_;
322
323
#ifdef DEBUG
324
// Accessor Shape containing the @@species property.
325
// See isPromiseStateStillSane() for why this field is debug-only.
326
MOZ_INIT_OUTSIDE_CTOR Shape* promiseSpeciesShape_;
327
#endif
328
329
// Shape of matching Promise.prototype object.
330
MOZ_INIT_OUTSIDE_CTOR Shape* promiseProtoShape_;
331
332
// Slots Promise.resolve, Promise.prototype.constructor, and
333
// Promise.prototype.then.
334
MOZ_INIT_OUTSIDE_CTOR uint32_t promiseResolveSlot_;
335
MOZ_INIT_OUTSIDE_CTOR uint32_t promiseProtoConstructorSlot_;
336
MOZ_INIT_OUTSIDE_CTOR uint32_t promiseProtoThenSlot_;
337
338
enum class State : uint8_t {
339
// Flags marking the lazy initialization of the above fields.
340
Uninitialized,
341
Initialized,
342
343
// The disabled flag is set when we don't want to try optimizing
344
// anymore because core objects were changed.
345
Disabled
346
};
347
348
State state_ = State::Uninitialized;
349
350
// Initialize the internal fields.
351
//
352
// The cache is successfully initialized iff
353
// 1. Promise and Promise.prototype classes are initialized.
354
// 2. Promise.prototype.constructor is equal to Promise.
355
// 3. Promise.prototype.then is the original `then` function.
356
// 4. Promise[@@species] is the original @@species getter.
357
// 5. Promise.resolve is the original `resolve` function.
358
void initialize(JSContext* cx);
359
360
// Reset the cache.
361
void reset();
362
363
// Check if the global promise-related objects have not been messed with
364
// in a way that would disable this cache.
365
bool isPromiseStateStillSane(JSContext* cx);
366
367
// Flags to control whether or not ensureInitialized() is allowed to
368
// reinitialize the cache when the Promise state is no longer sane.
369
enum class Reinitialize : bool { Allowed, Disallowed };
370
371
// Return true if the lookup cache is properly initialized for usage.
372
bool ensureInitialized(JSContext* cx, Reinitialize reinitialize);
373
374
// Return true if the prototype of the given Promise object is
375
// Promise.prototype and the object doesn't shadow properties from
376
// Promise.prototype.
377
bool hasDefaultProtoAndNoShadowedProperties(JSContext* cx,
378
PromiseObject* promise);
379
380
// Return true if the given Promise object uses the default @@species,
381
// "constructor", and "then" properties.
382
bool isDefaultInstance(JSContext* cx, PromiseObject* promise,
383
Reinitialize reinitialize);
384
385
// Return the built-in Promise constructor or null if not yet initialized.
386
static JSFunction* getPromiseConstructor(JSContext* cx);
387
388
// Return the built-in Promise prototype or null if not yet initialized.
389
static NativeObject* getPromisePrototype(JSContext* cx);
390
391
// Return true if the slot contains the given native.
392
static bool isDataPropertyNative(JSContext* cx, NativeObject* obj,
393
uint32_t slot, JSNative native);
394
395
// Return true if the accessor shape contains the given native.
396
static bool isAccessorPropertyNative(JSContext* cx, Shape* shape,
397
JSNative native);
398
399
public:
400
/** Construct a |PromiseSpeciesLookup| in the uninitialized state. */
401
PromiseLookup() { reset(); }
402
403
// Return true if the Promise constructor and Promise.prototype still use
404
// the default built-in functions.
405
bool isDefaultPromiseState(JSContext* cx);
406
407
// Return true if the given Promise object uses the default @@species,
408
// "constructor", and "then" properties.
409
bool isDefaultInstance(JSContext* cx, PromiseObject* promise) {
410
return isDefaultInstance(cx, promise, Reinitialize::Allowed);
411
}
412
413
// Return true if the given Promise object uses the default @@species,
414
// "constructor", and "then" properties.
415
bool isDefaultInstanceWhenPromiseStateIsSane(JSContext* cx,
416
PromiseObject* promise) {
417
return isDefaultInstance(cx, promise, Reinitialize::Disallowed);
418
}
419
420
// Purge the cache and all info associated with it.
421
void purge() {
422
if (state_ == State::Initialized) {
423
reset();
424
}
425
}
426
};
427
428
class OffThreadPromiseRuntimeState;
429
430
// [SMDOC] OffThreadPromiseTask: an off-main-thread task that resolves a promise
431
//
432
// An OffThreadPromiseTask is an abstract base class holding a JavaScript
433
// promise that will be resolved (fulfilled or rejected) with the results of a
434
// task possibly performed by some other thread.
435
//
436
// An OffThreadPromiseTask's lifecycle is as follows:
437
//
438
// - Some JavaScript native wishes to return a promise of the result of some
439
// computation that might be performed by other threads (say, helper threads
440
// or the embedding's I/O threads), so it creates a PromiseObject to represent
441
// the result, and an OffThreadPromiseTask referring to it. After handing the
442
// OffThreadPromiseTask to the code doing the actual work, the native is free
443
// to return the PromiseObject to its caller.
444
//
445
// - When the computation is done, successfully or otherwise, it populates the
446
// OffThreadPromiseTask—which is actually an instance of some concrete
447
// subclass specific to the task—with the information needed to resolve the
448
// promise, and calls OffThreadPromiseTask::dispatchResolveAndDestroy. This
449
// enqueues a runnable on the JavaScript thread to which the promise belongs.
450
//
451
// - When it gets around to the runnable, the JavaScript thread calls the
452
// OffThreadPromiseTask's `resolve` method, which the concrete subclass has
453
// overriden to resolve the promise appropriately. This probably enqueues a
454
// promise reaction job.
455
//
456
// - The JavaScript thread then deletes the OffThreadPromiseTask.
457
//
458
// During shutdown, the process is slightly different. Enqueuing runnables to
459
// the JavaScript thread begins to fail. JSRuntime shutdown waits for all
460
// outstanding tasks to call dispatchResolveAndDestroy, and then deletes them on
461
// the main thread, without calling `resolve`.
462
//
463
// For example, the JavaScript function WebAssembly.compile uses
464
// OffThreadPromiseTask to manage the result of a helper thread task, accepting
465
// binary WebAssembly code and returning a promise of a compiled
466
// WebAssembly.Module. It would like to do this compilation work on a helper
467
// thread. When called by JavaScript, WebAssembly.compile creates a promise,
468
// builds a CompileBufferTask (the OffThreadPromiseTask concrete subclass) to
469
// keep track of it, and then hands that to a helper thread. When the helper
470
// thread is done, successfully or otherwise, it calls the CompileBufferTask's
471
// dispatchResolveAndDestroy method, which enqueues a runnable to the JavaScript
472
// thread to resolve the promise and delete the CompileBufferTask.
473
// (CompileBufferTask actually implements PromiseHelperTask, which implements
474
// OffThreadPromiseTask; PromiseHelperTask is what our helper thread scheduler
475
// requires.)
476
//
477
// OffThreadPromiseTasks are not limited to use with helper threads. For
478
// example, a function returning a promise of the result of a network operation
479
// could provide the code collecting the incoming data with an
480
// OffThreadPromiseTask for the promise, and let the embedding's network I/O
481
// threads call dispatchResolveAndDestroy.
482
//
483
// OffThreadPromiseTask may also be used purely on the main thread, as a way to
484
// "queue a task" in HTML terms. Note that a "task" is not the same as a
485
// "microtask" and there are separate queues for tasks and microtasks that are
486
// drained at separate times in the browser. The task queue is implemented by
487
// the browser's main event loop. The microtask queue is implemented
488
// by JS::JobQueue, used for promises and gets drained before returning to
489
// the event loop. Thus OffThreadPromiseTask can only be used when the spec
490
// says "queue a task", as the WebAssembly APIs do.
491
//
492
// An OffThreadPromiseTask has a JSContext, and must be constructed and have its
493
// 'init' method called on that JSContext's thread. Once initialized, its
494
// dispatchResolveAndDestroy method may be called from any thread. This is the
495
// only safe way to destruct an OffThreadPromiseTask; doing so ensures the
496
// OffThreadPromiseTask's destructor will run on the JSContext's thread, either
497
// from the event loop or during shutdown.
498
//
499
// OffThreadPromiseTask::dispatchResolveAndDestroy uses the
500
// JS::DispatchToEventLoopCallback provided by the embedding to enqueue
501
// runnables on the JavaScript thread. See the comments for
502
// DispatchToEventLoopCallback for details.
503
504
class OffThreadPromiseTask : public JS::Dispatchable {
505
friend class OffThreadPromiseRuntimeState;
506
507
JSRuntime* runtime_;
508
PersistentRooted<PromiseObject*> promise_;
509
bool registered_;
510
511
void operator=(const OffThreadPromiseTask&) = delete;
512
OffThreadPromiseTask(const OffThreadPromiseTask&) = delete;
513
514
void unregister(OffThreadPromiseRuntimeState& state);
515
516
protected:
517
OffThreadPromiseTask(JSContext* cx, Handle<PromiseObject*> promise);
518
519
// To be called by OffThreadPromiseTask and implemented by the derived class.
520
virtual bool resolve(JSContext* cx, Handle<PromiseObject*> promise) = 0;
521
522
// JS::Dispatchable implementation. Ends with 'delete this'.
523
void run(JSContext* cx, MaybeShuttingDown maybeShuttingDown) final;
524
525
public:
526
~OffThreadPromiseTask() override;
527
528
// Initializing an OffThreadPromiseTask informs the runtime that it must
529
// wait on shutdown for this task to rejoin the active JSContext by calling
530
// dispatchResolveAndDestroy().
531
bool init(JSContext* cx);
532
533
// An initialized OffThreadPromiseTask can be dispatched to an active
534
// JSContext of its Promise's JSRuntime from any thread. Normally, this will
535
// lead to resolve() being called on JSContext thread, given the Promise.
536
// However, if shutdown interrupts, resolve() may not be called, though the
537
// OffThreadPromiseTask will be destroyed on a JSContext thread.
538
void dispatchResolveAndDestroy();
539
};
540
541
using OffThreadPromiseTaskSet =
542
HashSet<OffThreadPromiseTask*, DefaultHasher<OffThreadPromiseTask*>,
543
SystemAllocPolicy>;
544
545
using DispatchableFifo = Fifo<JS::Dispatchable*, 0, SystemAllocPolicy>;
546
547
class OffThreadPromiseRuntimeState {
548
friend class OffThreadPromiseTask;
549
550
// These fields are initialized once before any off-thread usage and thus do
551
// not require a lock.
552
JS::DispatchToEventLoopCallback dispatchToEventLoopCallback_;
553
void* dispatchToEventLoopClosure_;
554
555
// All following fields are mutated by any thread and are guarded by mutex_.
556
Mutex mutex_;
557
558
// A set of all OffThreadPromiseTasks that have successfully called 'init'.
559
// OffThreadPromiseTask's destructor removes them from the set.
560
OffThreadPromiseTaskSet live_;
561
562
// The allCancelled_ condition is waited on and notified during engine
563
// shutdown, communicating when all off-thread tasks in live_ are safe to be
564
// destroyed from the (shutting down) main thread. This condition is met when
565
// live_.count() == numCanceled_ where "canceled" means "the
566
// DispatchToEventLoopCallback failed after this task finished execution".
567
ConditionVariable allCanceled_;
568
size_t numCanceled_;
569
570
// The queue of JS::Dispatchables used by the DispatchToEventLoopCallback that
571
// calling js::UseInternalJobQueues installs.
572
DispatchableFifo internalDispatchQueue_;
573
ConditionVariable internalDispatchQueueAppended_;
574
bool internalDispatchQueueClosed_;
575
576
static bool internalDispatchToEventLoop(void*, JS::Dispatchable*);
577
bool usingInternalDispatchQueue() const;
578
579
void operator=(const OffThreadPromiseRuntimeState&) = delete;
580
OffThreadPromiseRuntimeState(const OffThreadPromiseRuntimeState&) = delete;
581
582
public:
583
OffThreadPromiseRuntimeState();
584
~OffThreadPromiseRuntimeState();
585
void init(JS::DispatchToEventLoopCallback callback, void* closure);
586
void initInternalDispatchQueue();
587
bool initialized() const;
588
589
// If initInternalDispatchQueue() was called, internalDrain() can be
590
// called to periodically drain the dispatch queue before shutdown.
591
void internalDrain(JSContext* cx);
592
bool internalHasPending();
593
594
// shutdown() must be called by the JSRuntime while the JSRuntime is valid.
595
void shutdown(JSContext* cx);
596
};
597
598
} // namespace js
599
600
#endif /* builtin_Promise_h */