https://github.com/mozilla/gecko-dev
Tip revision: 317ad88a80dcda805c1504d3ecfe5146b0dbce72 authored by ffxbld on 06 February 2017, 09:11:29 UTC
Added FENNEC_51_0_2_RELEASE FENNEC_51_0_2_BUILD1 tag(s) for changeset 1da1e8b121ca. DONTBUILD CLOSED TREE a=release
Added FENNEC_51_0_2_RELEASE FENNEC_51_0_2_BUILD1 tag(s) for changeset 1da1e8b121ca. DONTBUILD CLOSED TREE a=release
Tip revision: 317ad88
Promise.js
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// ES6, 25.4.1.2.
// This object is used to verify that an object is a PromiseReaction record.
var PromiseReactionRecordProto = {__proto__: null};
function PromiseReactionRecord(promise, resolve, reject, fulfillHandler, rejectHandler,
incumbentGlobal) {
this.promise = promise;
this.resolve = resolve;
this.reject = reject;
this.fulfillHandler = fulfillHandler;
this.rejectHandler = rejectHandler;
this.incumbentGlobal = incumbentGlobal;
}
MakeConstructible(PromiseReactionRecord, PromiseReactionRecordProto);
// Used to verify that an object is a PromiseCapability record.
var PromiseCapabilityRecordProto = {__proto__: null};
// ES2016, 25.4.1.3, implemented in Promise.cpp.
// ES2016, 25.4.1.4, implemented in Promise.cpp.
// ES2016, 25.4.1.5.
// Creates PromiseCapability records, see 25.4.1.1.
function NewPromiseCapability(C) {
// Steps 1-2.
if (!IsConstructor(C))
ThrowTypeError(JSMSG_NOT_CONSTRUCTOR, 0);
// Step 3. Replaced by individual fields, combined in step 11.
let resolve;
let reject;
// Steps 4-5.
// ES6, 25.4.1.5.1. Inlined here so we can use an upvar instead of a slot to
// store promiseCapability.
function GetCapabilitiesExecutor(resolve_, reject_) {
// Steps 1-2 (implicit).
// Steps 3-4.
if (resolve !== undefined || reject !== undefined)
ThrowTypeError(JSMSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY);
resolve = resolve_;
reject = reject_;
}
// Steps 6-7.
let promise = new C(GetCapabilitiesExecutor);
// Step 8.
if (!IsCallable(resolve))
ThrowTypeError(JSMSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE);
// Step 9.
if (!IsCallable(reject))
ThrowTypeError(JSMSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE);
// Steps 10-11.
return {
__proto__: PromiseCapabilityRecordProto,
promise,
resolve,
reject
};
}
// ES2016, 25.4.1.6, implemented in SelfHosting.cpp.
// ES2016, 25.4.1.7, implemented in Promise.cpp.
// ES2016, 25.4.1.8, implemented in Promise.cpp.
// ES2016, 25.4.1.9, implemented in SelfHosting.cpp.
// ES6, 25.4.2.1.
function EnqueuePromiseReactionJob(reaction, jobType, argument) {
// Reaction records contain handlers for both fulfillment and rejection.
// The `jobType` parameter allows us to retrieves the right one.
assert(jobType === PROMISE_JOB_TYPE_FULFILL || jobType === PROMISE_JOB_TYPE_REJECT,
"Invalid job type");
_EnqueuePromiseReactionJob(reaction[jobType],
argument,
reaction.resolve,
reaction.reject,
reaction.promise,
reaction.incumbentGlobal || null);
}
// ES6, 25.4.2.2. (Implemented in C++).
// ES6, 25.4.3.1. (Implemented in C++).
// ES2016, 25.4.4.1.
function Promise_static_all(iterable) {
// Step 1.
let C = this;
// Step 2.
if (!IsObject(C))
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, "Receiver of Promise.all call");
// Step 3.
let promiseCapability = NewPromiseCapability(C);
// Steps 4-5.
let iterator;
try {
iterator = GetIterator(iterable);
} catch (e) {
callContentFunction(promiseCapability.reject, undefined, e);
return promiseCapability.promise;
}
// Step 6.
let iteratorRecord = {__proto__: null, iterator, done: false};
// Steps 7-9.
try {
// Steps 7,9.
return PerformPromiseAll(iteratorRecord, C, promiseCapability);
} catch (e) {
// Step 8.a.
// TODO: implement iterator closing.
// Step 8.b.
callContentFunction(promiseCapability.reject, undefined, e);
return promiseCapability.promise;
}
}
// ES6, 25.4.4.1.1.
function PerformPromiseAll(iteratorRecord, constructor, resultCapability) {
// Step 1.
assert(IsConstructor(constructor), "PerformPromiseAll called with non-constructor");
// Step 2.
assert(IsPromiseCapability(resultCapability), "Invalid promise capability record");
// Step 3.
// Immediately create an Array instead of a List, so we can skip step 6.d.iii.1.
//
// We might be dealing with a wrapped instance from another Realm. In that
// case, we want to create the `values` array in that other Realm so if
// it's less-privileged than the current one, code in that Realm can still
// work with the array.
let values = IsPromise(resultCapability.promise) || !IsWrappedPromise(resultCapability.promise)
? []
: NewArrayInCompartment(constructor);
let valuesCount = 0;
// Step 4.
let remainingElementsCount = {value: 1};
// Step 5.
let index = 0;
// Step 6.
let iterator = iteratorRecord.iterator;
let next;
let nextValue;
let allPromise = resultCapability.promise;
while (true) {
try {
// Step 6.a.
next = callContentFunction(iterator.next, iterator);
if (!IsObject(next))
ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE);
} catch (e) {
// Step 6.b.
iteratorRecord.done = true;
// Step 6.c.
throw (e);
}
// Step 6.d.
if (next.done) {
// Step 6.d.i.
iteratorRecord.done = true;
// Step 6.d.ii.
remainingElementsCount.value--;
assert(remainingElementsCount.value >= 0,
"remainingElementsCount mustn't be negative.");
// Step 6.d.iii.
if (remainingElementsCount.value === 0)
callContentFunction(resultCapability.resolve, undefined, values);
// Step 6.d.iv.
return allPromise;
}
try {
// Step 6.e.
nextValue = next.value;
} catch (e) {
// Step 6.f.
iteratorRecord.done = true;
// Step 6.g.
throw e;
}
// Step 6.h.
_DefineDataProperty(values, valuesCount++, undefined);
// Steps 6.i-j.
let nextPromise = callContentFunction(constructor.resolve, constructor, nextValue);
// Steps 6.k-p.
let resolveElement = CreatePromiseAllResolveElementFunction(index, values,
resultCapability,
remainingElementsCount);
// Step 6.q.
remainingElementsCount.value++;
// Steps 6.r-s.
BlockOnPromise(nextPromise, allPromise, resolveElement, resultCapability.reject);
// Step 6.t.
index++;
}
}
/**
* Unforgeable version of Promise.all for internal use.
*
* Takes a dense array of Promise objects and returns a promise that's
* resolved with an array of resolution values when all those promises ahve
* been resolved, or rejected with the rejection value of the first rejected
* promise.
*
* Asserts if the array isn't dense or one of the entries isn't a Promise.
*/
function GetWaitForAllPromise(promises) {
let resultCapability = NewPromiseCapability(GetBuiltinConstructor('Promise'));
let allPromise = resultCapability.promise;
// Step 3.
// Immediately create an Array instead of a List, so we can skip step 6.d.iii.1.
let values = [];
let valuesCount = 0;
// Step 4.
let remainingElementsCount = {value: 0};
// Step 6.
for (let i = 0; i < promises.length; i++) {
// Parts of step 6 for deriving next promise, vastly simplified.
assert(callFunction(std_Object_hasOwnProperty, promises, i),
"GetWaitForAllPromise must be called with a dense array of promises");
let nextPromise = promises[i];
assert(IsPromise(nextPromise) || IsWrappedPromise(nextPromise),
"promises list must only contain possibly wrapped promises");
// Step 6.h.
_DefineDataProperty(values, valuesCount++, undefined);
// Steps 6.k-p.
let resolveElement = CreatePromiseAllResolveElementFunction(i, values,
resultCapability,
remainingElementsCount);
// Step 6.q.
remainingElementsCount.value++;
// Steps 6.r-s, very roughly.
EnqueuePromiseReactions(nextPromise, allPromise, resolveElement, resultCapability.reject);
}
if (remainingElementsCount.value === 0)
callFunction(resultCapability.resolve, undefined, values);
return allPromise;
}
// ES6, 25.4.4.1.2.
function CreatePromiseAllResolveElementFunction(index, values, promiseCapability,
remainingElementsCount)
{
var alreadyCalled = false;
return function PromiseAllResolveElementFunction(x) {
// Steps 1-2.
if (alreadyCalled)
return undefined;
// Step 3.
alreadyCalled = true;
// Steps 4-7 (implicit).
// Step 8.
// Note: this can't throw because the slot was initialized to `undefined` earlier.
values[index] = x;
// Step 9.
remainingElementsCount.value--;
assert(remainingElementsCount.value >= 0, "remainingElementsCount mustn't be negative.");
// Step 10.
if (remainingElementsCount.value === 0) {
// Step 10.a (implicit).
// Step 10.b.
return callContentFunction(promiseCapability.resolve, undefined, values);
}
// Step 11 (implicit).
};
}
// ES2016, 25.4.4.3.
function Promise_static_race(iterable) {
// Step 1.
let C = this;
// Step 2.
if (!IsObject(C))
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, "Receiver of Promise.race call");
// step 3.
let promiseCapability = NewPromiseCapability(C);
// Steps 4-5.
let iterator;
try {
iterator = GetIterator(iterable);
} catch (e) {
callContentFunction(promiseCapability.reject, undefined, e);
return promiseCapability.promise;
}
// Step 6.
let iteratorRecord = {__proto__: null, iterator, done: false};
// Steps 7-9.
try {
// Steps 7,9.
return PerformPromiseRace(iteratorRecord, promiseCapability, C);
} catch (e) {
// Step 8.a.
// TODO: implement iterator closing.
// Step 8.b.
callContentFunction(promiseCapability.reject, undefined, e);
return promiseCapability.promise;
}
}
// ES2016, 25.4.4.3.1.
function PerformPromiseRace(iteratorRecord, resultCapability, C) {
assert(IsConstructor(C), "PerformPromiseRace called with non-constructor");
assert(IsPromiseCapability(resultCapability), "Invalid promise capability record");
// Step 1.
let iterator = iteratorRecord.iterator;
let racePromise = resultCapability.promise;
let next;
let nextValue;
while (true) {
try {
// Step 1.a.
next = callContentFunction(iterator.next, iterator);
if (!IsObject(next))
ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE);
} catch (e) {
// Step 1.b.
iteratorRecord.done = true;
// Step 1.c.
throw (e);
}
// Step 1.d.
if (next.done) {
// Step 1.d.i.
iteratorRecord.done = true;
// Step 1.d.ii.
return racePromise;
}
try {
// Step 1.e.
nextValue = next.value;
} catch (e) {
// Step 1.f.
iteratorRecord.done = true;
// Step 1.g.
throw e;
}
// Step 1.h.
let nextPromise = callContentFunction(C.resolve, C, nextValue);
// Steps 1.i.
BlockOnPromise(nextPromise, racePromise, resultCapability.resolve,
resultCapability.reject);
}
assert(false, "Shouldn't reach the end of PerformPromiseRace");
}
/**
* Calls |promise.then| with the provided hooks and adds |blockedPromise| to
* its list of dependent promises. Used by |Promise.all| and |Promise.race|.
*
* If |promise.then| is the original |Promise.prototype.then| function and
* the call to |promise.then| would use the original |Promise| constructor to
* create the resulting promise, this function skips the call to |promise.then|
* and thus creating a new promise that would not be observable by content.
*/
function BlockOnPromise(promise, blockedPromise, onResolve, onReject) {
let then = promise.then;
// By default, the blocked promise is added as an extra entry to the
// rejected promises list.
let addToDependent = true;
if (then === Promise_then && IsObject(promise) && IsPromise(promise)) {
// |then| is the original |Promise.prototype.then|, inline it here.
// 25.4.5.3., steps 3-4.
let PromiseCtor = GetBuiltinConstructor('Promise');
let C = SpeciesConstructor(promise, PromiseCtor);
let resultCapability;
if (C === PromiseCtor) {
resultCapability = {
__proto__: PromiseCapabilityRecordProto,
promise: blockedPromise,
reject: NullFunction,
resolve: NullFunction
};
addToDependent = false;
} else {
// 25.4.5.3., steps 5-6.
resultCapability = NewPromiseCapability(C);
}
// 25.4.5.3., step 7.
PerformPromiseThen(promise, onResolve, onReject, resultCapability);
} else {
// Optimization failed, do the normal call.
callContentFunction(then, promise, onResolve, onReject);
}
if (!addToDependent)
return;
// The object created by the |promise.then| call or the inlined version
// of it above is visible to content (either because |promise.then| was
// overridden by content and could leak it, or because a constructor
// other than the original value of |Promise| was used to create it).
// To have both that object and |blockedPromise| show up as dependent
// promises in the debugger, add a dummy reaction to the list of reject
// reactions that contains |blockedPromise|, but otherwise does nothing.
// If the object isn't a maybe-wrapped instance of |Promise|, we ignore
// it. All this does is lose some small amount of debug information
// in scenarios that are highly unlikely to occur in useful code.
if (IsPromise(promise))
return callFunction(AddDependentPromise, promise, blockedPromise);
if (IsWrappedPromise(promise))
callFunction(CallPromiseMethodIfWrapped, promise, blockedPromise, "AddDependentPromise");
}
/**
* Invoked with a Promise as the receiver, AddDependentPromise adds an entry
* to the reactions list.
*
* This is only used to make dependent promises visible in the devtools, so no
* callbacks are provided. To make handling that case easier elsewhere,
* they're all set to NullFunction.
*
* The reason for the target Promise to be passed as the receiver is so the
* same function can be used for wrapped and unwrapped Promise objects.
*/
function AddDependentPromise(dependentPromise) {
assert(IsPromise(this), "AddDependentPromise expects an unwrapped Promise as the receiver");
if (GetPromiseState(this) !== PROMISE_STATE_PENDING)
return;
let reaction = new PromiseReactionRecord(dependentPromise, NullFunction, NullFunction,
NullFunction, NullFunction, null);
let reactions = UnsafeGetReservedSlot(this, PROMISE_REACTIONS_OR_RESULT_SLOT);
// The reactions list might not have been allocated yet.
if (!reactions)
UnsafeSetReservedSlot(dependentPromise, PROMISE_REACTIONS_OR_RESULT_SLOT, [reaction]);
else
_DefineDataProperty(reactions, reactions.length, reaction);
}
// ES2016, 25.4.4.4 (implemented in C++).
// ES2016, 25.4.4.5 (implemented in C++).
// ES6, 25.4.4.6.
function Promise_static_get_species() {
// Step 1.
return this;
}
_SetCanonicalName(Promise_static_get_species, "get [Symbol.species]");
// ES6, 25.4.5.1.
function Promise_catch(onRejected) {
// Steps 1-2.
return callContentFunction(this.then, this, undefined, onRejected);
}
// ES6, 25.4.5.3.
function Promise_then(onFulfilled, onRejected) {
// Step 1.
let promise = this;
// Step 2.
if (!IsObject(promise))
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, "Receiver of Promise.prototype.then call");
let isPromise = IsPromise(promise);
let isWrappedPromise = isPromise ? false : IsWrappedPromise(promise);
if (!(isPromise || isWrappedPromise))
ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "Promise", "then", "value");
// Steps 3-4.
let C = SpeciesConstructor(promise, GetBuiltinConstructor('Promise'));
// Steps 5-6.
let resultCapability = NewPromiseCapability(C);
// Step 7.
if (isWrappedPromise) {
// See comment above GetPromiseHandlerForwarders for why this is needed.
let handlerForwarders = GetPromiseHandlerForwarders(onFulfilled, onRejected);
return callFunction(CallPromiseMethodIfWrapped, promise,
handlerForwarders[0], handlerForwarders[1],
resultCapability.promise, resultCapability.resolve,
resultCapability.reject, "UnwrappedPerformPromiseThen");
}
return PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability);
}
/**
* Enqueues resolve/reject reactions in the given Promise's reactions lists
* in a content-invisible way.
*
* Used internally to implement DOM functionality.
*
* Note: the reactions pushed using this function contain a `promise` field
* that can contain null. That field is only ever used by devtools, which have
* to treat these reactions specially.
*/
function EnqueuePromiseReactions(promise, dependentPromise, onFulfilled, onRejected) {
let isWrappedPromise = false;
if (!IsPromise(promise)) {
assert(IsWrappedPromise(promise),
"EnqueuePromiseReactions must be provided with a possibly wrapped promise");
isWrappedPromise = true;
}
assert(dependentPromise === null || IsPromise(dependentPromise),
"EnqueuePromiseReactions's dependentPromise argument must be a Promise or null");
if (isWrappedPromise) {
// See comment above GetPromiseHandlerForwarders for why this is needed.
let handlerForwarders = GetPromiseHandlerForwarders(onFulfilled, onRejected);
return callFunction(CallPromiseMethodIfWrapped, promise, handlerForwarders[0],
handlerForwarders[1], dependentPromise, NullFunction, NullFunction,
"UnwrappedPerformPromiseThen");
}
let capability = {
__proto__: PromiseCapabilityRecordProto,
promise: dependentPromise,
resolve: NullFunction,
reject: NullFunction
};
return PerformPromiseThen(promise, onFulfilled, onRejected, capability);
}
/**
* Returns a set of functions that are (1) self-hosted, and (2) exact
* forwarders of the passed-in functions, for use by
* UnwrappedPerformPromiseThen.
*
* When calling `then` on an xray-wrapped promise, the receiver isn't
* unwrapped. Instead, Promise_then operates on the wrapped Promise. Just
* calling PerformPromiseThen from Promise_then as we normally would doesn't
* work in this case: PerformPromiseThen can only deal with unwrapped
* Promises. Instead, we use the CallPromiseMethodIfWrapped intrinsic to
* switch compartments before calling PerformPromiseThen, via
* UnwrappedPerformPromiseThen.
*
* This is almost enough, but there's an additional wrinkle: when calling the
* fulfillment and rejection handlers, we might pass in Object-type arguments
* from within the xray-ed, lower-privileged compartment. By default, this
* doesn't work, because they're wrapped into wrappers that disallow passing
* in Object-typed arguments (so the higher-privileged code doesn't
* accidentally operate on objects assuming they're higher-privileged, too.)
* So instead UnwrappedPerformPromiseThen adds another level of indirection:
* it closes over the, by now cross-compartment-wrapped, handler forwarders
* created by GetPromiseHandlerForwarders and creates a second set of
* forwarders around them, which use UnsafeCallWrappedFunction to call the
* initial forwarders.
* Note that both above-mentioned guarantees are required: while it may seem
* as though the original handlers would always be wrappers once they reach
* UnwrappedPerformPromiseThen (because the call to `then` originated in the
* higher-privileged compartment, and after unwrapping we end up in the
* lower-privileged one), that's not necessarily the case. One or both of the
* handlers can originate from the lower-privileged compartment, so they'd
* actually be unwrapped functions when they reach
* UnwrappedPerformPromiseThen.
*/
function GetPromiseHandlerForwarders(fulfilledHandler, rejectedHandler) {
// If non-callable values are passed, we have to preserve them so steps
// 3 and 4 of PerformPromiseThen work as expected.
return [
IsCallable(fulfilledHandler) ? function onFulfilled(argument) {
return callContentFunction(fulfilledHandler, this, argument);
} : fulfilledHandler,
IsCallable(rejectedHandler) ? function onRejected(argument) {
return callContentFunction(rejectedHandler, this, argument);
} : rejectedHandler
];
}
/**
* Forwarder used to invoke PerformPromiseThen on an unwrapped Promise, while
* wrapping the resolve/reject callbacks into functions that invoke them in
* their original compartment. See the comment for GetPromiseHandlerForwarders
* for details.
*/
function UnwrappedPerformPromiseThen(fulfilledHandler, rejectedHandler, promise, resolve, reject) {
let resultCapability = {
__proto__: PromiseCapabilityRecordProto,
promise,
resolve(resolution) {
// Under some circumstances, we have an unwrapped `resolve`
// function here. One way this happens is if the constructor
// passed to `NewPromiseCapability` is from the same global as the
// Promise object on which `Promise_then` was called, but where
// `Promise_then` is from a different global, so we end up here.
// In that case, the `resolve` and `reject` functions aren't
// wrappers in the current global.
if (IsFunctionObject(resolve))
return resolve(resolution);
return UnsafeCallWrappedFunction(resolve, undefined, resolution);
},
reject(reason) {
// See comment inside `resolve` above.
if (IsFunctionObject(reject))
return reject(reason);
return UnsafeCallWrappedFunction(reject, undefined, reason);
}
};
function onFulfilled(argument) {
return UnsafeCallWrappedFunction(fulfilledHandler, undefined, argument);
}
function onRejected(argument) {
return UnsafeCallWrappedFunction(rejectedHandler, undefined, argument);
}
return PerformPromiseThen(this, IsCallable(fulfilledHandler) ? onFulfilled : fulfilledHandler,
IsCallable(rejectedHandler) ? onRejected : rejectedHandler,
resultCapability);
}
// ES2016, 25.4.5.3.1.
function PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability) {
// Step 1.
assert(IsPromise(promise), "Can't call PerformPromiseThen on non-Promise objects");
// Step 2.
assert(IsPromiseCapability(resultCapability), "Invalid promise capability record");
// Step 3.
if (!IsCallable(onFulfilled))
onFulfilled = PROMISE_HANDLER_IDENTITY;
// Step 4.
if (!IsCallable(onRejected))
onRejected = PROMISE_HANDLER_THROWER;
let incumbentGlobal = _GetObjectFromIncumbentGlobal();
// Steps 5,6.
// Instead of creating separate reaction records for fulfillment and
// rejection, we create a combined record. All places we use the record
// can handle that.
let reaction = new PromiseReactionRecord(resultCapability.promise,
resultCapability.resolve,
resultCapability.reject,
onFulfilled,
onRejected,
incumbentGlobal);
// Step 7.
let state = GetPromiseState(promise);
let flags = UnsafeGetInt32FromReservedSlot(promise, PROMISE_FLAGS_SLOT);
if (state === PROMISE_STATE_PENDING) {
// Steps 7.a,b.
// We only have a single list for fulfill and reject reactions.
let reactions = UnsafeGetReservedSlot(promise, PROMISE_REACTIONS_OR_RESULT_SLOT);
if (!reactions)
UnsafeSetReservedSlot(promise, PROMISE_REACTIONS_OR_RESULT_SLOT, [reaction]);
else
_DefineDataProperty(reactions, reactions.length, reaction);
}
// Step 8.
else if (state === PROMISE_STATE_FULFILLED) {
// Step 8.a.
let value = UnsafeGetReservedSlot(promise, PROMISE_REACTIONS_OR_RESULT_SLOT);
// Step 8.b.
EnqueuePromiseReactionJob(reaction, PROMISE_JOB_TYPE_FULFILL, value);
}
// Step 9.
else {
// Step 9.a.
assert(state === PROMISE_STATE_REJECTED, "Invalid Promise state " + state);
// Step 9.b.
let reason = UnsafeGetReservedSlot(promise, PROMISE_REACTIONS_OR_RESULT_SLOT);
// Step 9.c.
if (!(flags & PROMISE_FLAG_HANDLED))
HostPromiseRejectionTracker(promise, PROMISE_REJECTION_TRACKER_OPERATION_HANDLE);
// Step 9.d.
EnqueuePromiseReactionJob(reaction, PROMISE_JOB_TYPE_REJECT, reason);
}
// Step 10.
UnsafeSetReservedSlot(promise, PROMISE_FLAGS_SLOT, flags | PROMISE_FLAG_HANDLED);
// Step 11.
return resultCapability.promise;
}
/// Utility functions below.
function IsPromiseReaction(record) {
return std_Reflect_getPrototypeOf(record) === PromiseReactionRecordProto;
}
function IsPromiseCapability(capability) {
return std_Reflect_getPrototypeOf(capability) === PromiseCapabilityRecordProto;
}
function GetPromiseState(promise) {
let flags = UnsafeGetInt32FromReservedSlot(promise, PROMISE_FLAGS_SLOT);
if (!(flags & PROMISE_FLAG_RESOLVED)) {
assert(!(flags & PROMISE_STATE_FULFILLED), "Fulfilled promises are resolved, too");
return PROMISE_STATE_PENDING;
}
if (flags & PROMISE_FLAG_FULFILLED)
return PROMISE_STATE_FULFILLED;
return PROMISE_STATE_REJECTED;
}