2020-01-21 15:15:35 +00:00
|
|
|
// Copyright 2019 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
#include 'src/builtins/builtins-promise.h'
|
|
|
|
#include 'src/builtins/builtins-promise-gen.h'
|
|
|
|
|
|
|
|
namespace promise {
|
2020-05-12 13:28:29 +00:00
|
|
|
const kPromiseBuiltinsPromiseContextLength: constexpr int31
|
|
|
|
generates 'PromiseBuiltins::kPromiseContextLength';
|
|
|
|
|
|
|
|
// Creates the context used by all Promise.all resolve element closures,
|
|
|
|
// together with the values array. Since all closures for a single Promise.all
|
|
|
|
// call use the same context, we need to store the indices for the individual
|
|
|
|
// closures somewhere else (we put them into the identity hash field of the
|
|
|
|
// closures), and we also need to have a separate marker for when the closure
|
|
|
|
// was called already (we slap the native context onto the closure in that
|
|
|
|
// case to mark it's done).
|
|
|
|
macro CreatePromiseAllResolveElementContext(implicit context: Context)(
|
|
|
|
capability: PromiseCapability, nativeContext: NativeContext): Context {
|
|
|
|
const resolveContext = AllocateSyntheticFunctionContext(
|
|
|
|
nativeContext,
|
|
|
|
PromiseAllResolveElementContextSlots::kPromiseAllResolveElementLength);
|
|
|
|
resolveContext[PromiseAllResolveElementContextSlots::
|
|
|
|
kPromiseAllResolveElementRemainingSlot] = SmiConstant(1);
|
|
|
|
resolveContext[PromiseAllResolveElementContextSlots::
|
|
|
|
kPromiseAllResolveElementCapabilitySlot] = capability;
|
|
|
|
resolveContext[PromiseAllResolveElementContextSlots::
|
2020-05-19 07:36:02 +00:00
|
|
|
kPromiseAllResolveElementValuesSlot] = kEmptyFixedArray;
|
2020-05-12 13:28:29 +00:00
|
|
|
return resolveContext;
|
|
|
|
}
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
macro CreatePromiseAllResolveElementFunction(implicit context: Context)(
|
|
|
|
resolveElementContext: Context, index: Smi, nativeContext: NativeContext,
|
|
|
|
resolveFunction: SharedFunctionInfo): JSFunction {
|
|
|
|
assert(index > 0);
|
|
|
|
assert(index < kPropertyArrayHashFieldMax);
|
|
|
|
|
|
|
|
const map = UnsafeCast<Map>(
|
|
|
|
nativeContext
|
|
|
|
[NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]);
|
|
|
|
const resolve = AllocateFunctionWithMapAndContext(
|
|
|
|
map, resolveFunction, resolveElementContext);
|
|
|
|
|
|
|
|
assert(kPropertyArrayNoHashSentinel == 0);
|
|
|
|
resolve.properties_or_hash = index;
|
|
|
|
return resolve;
|
|
|
|
}
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
@export
|
|
|
|
macro CreatePromiseResolvingFunctionsContext(implicit context: Context)(
|
|
|
|
promise: JSPromise, debugEvent: Object, nativeContext: NativeContext):
|
|
|
|
Context {
|
|
|
|
const resolveContext = AllocateSyntheticFunctionContext(
|
|
|
|
nativeContext, kPromiseBuiltinsPromiseContextLength);
|
|
|
|
resolveContext[kPromiseBuiltinsPromiseSlot] = promise;
|
|
|
|
resolveContext[kPromiseBuiltinsAlreadyResolvedSlot] = False;
|
|
|
|
resolveContext[kPromiseBuiltinsDebugEventSlot] = debugEvent;
|
|
|
|
return resolveContext;
|
|
|
|
}
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
macro IsPromiseThenLookupChainIntact(implicit context: Context)(
|
|
|
|
nativeContext: NativeContext, receiverMap: Map): bool {
|
|
|
|
if (IsForceSlowPath()) return false;
|
|
|
|
if (!IsJSPromiseMap(receiverMap)) return false;
|
|
|
|
if (receiverMap.prototype !=
|
|
|
|
nativeContext[NativeContextSlot::PROMISE_PROTOTYPE_INDEX])
|
|
|
|
return false;
|
|
|
|
return !IsPromiseThenProtectorCellInvalid();
|
|
|
|
}
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
struct PromiseAllResolveElementFunctor {
|
|
|
|
macro Call(implicit context: Context)(
|
|
|
|
resolveElementContext: Context, nativeContext: NativeContext, index: Smi,
|
|
|
|
_capability: PromiseCapability): Callable {
|
|
|
|
return CreatePromiseAllResolveElementFunction(
|
|
|
|
resolveElementContext, index, nativeContext,
|
|
|
|
PromiseAllResolveElementSharedFunConstant());
|
2020-01-21 15:15:35 +00:00
|
|
|
}
|
2020-05-12 13:28:29 +00:00
|
|
|
}
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
struct PromiseAllRejectElementFunctor {
|
|
|
|
macro Call(implicit context: Context)(
|
|
|
|
_resolveElementContext: Context, _nativeContext: NativeContext,
|
|
|
|
_index: Smi, capability: PromiseCapability): Callable {
|
|
|
|
return UnsafeCast<Callable>(capability.reject);
|
2020-01-21 15:15:35 +00:00
|
|
|
}
|
2020-05-12 13:28:29 +00:00
|
|
|
}
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
struct PromiseAllSettledResolveElementFunctor {
|
|
|
|
macro Call(implicit context: Context)(
|
|
|
|
resolveElementContext: Context, nativeContext: NativeContext, index: Smi,
|
|
|
|
_capability: PromiseCapability): Callable {
|
|
|
|
return CreatePromiseAllResolveElementFunction(
|
|
|
|
resolveElementContext, index, nativeContext,
|
|
|
|
PromiseAllSettledResolveElementSharedFunConstant());
|
2020-01-21 15:15:35 +00:00
|
|
|
}
|
2020-05-12 13:28:29 +00:00
|
|
|
}
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
struct PromiseAllSettledRejectElementFunctor {
|
|
|
|
macro Call(implicit context: Context)(
|
|
|
|
resolveElementContext: Context, nativeContext: NativeContext, index: Smi,
|
|
|
|
_capability: PromiseCapability): Callable {
|
|
|
|
return CreatePromiseAllResolveElementFunction(
|
|
|
|
resolveElementContext, index, nativeContext,
|
|
|
|
PromiseAllSettledRejectElementSharedFunConstant());
|
2020-01-21 15:15:35 +00:00
|
|
|
}
|
2020-05-12 13:28:29 +00:00
|
|
|
}
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
transitioning macro PerformPromiseAll<F1: type, F2: type>(
|
|
|
|
implicit context: Context)(
|
2020-06-05 12:51:25 +00:00
|
|
|
nativeContext: NativeContext, iter: iterator::IteratorRecord,
|
|
|
|
constructor: Constructor, capability: PromiseCapability,
|
|
|
|
promiseResolveFunction: JSAny, createResolveElementFunctor: F1,
|
2020-05-12 13:28:29 +00:00
|
|
|
createRejectElementFunctor: F2): JSAny labels
|
|
|
|
Reject(Object) {
|
|
|
|
const promise = capability.promise;
|
|
|
|
const resolve = capability.resolve;
|
|
|
|
const reject = capability.reject;
|
|
|
|
|
|
|
|
// For catch prediction, don't treat the .then calls as handling it;
|
|
|
|
// instead, recurse outwards.
|
|
|
|
if (IsDebugActive()) deferred {
|
|
|
|
SetPropertyStrict(context, reject, kPromiseForwardingHandlerSymbol, True);
|
|
|
|
}
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
const resolveElementContext =
|
|
|
|
CreatePromiseAllResolveElementContext(capability, nativeContext);
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
let index: Smi = 1;
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
try {
|
2020-06-05 12:51:25 +00:00
|
|
|
const fastIteratorResultMap = UnsafeCast<Map>(
|
|
|
|
nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]);
|
|
|
|
while (true) {
|
|
|
|
let nextValue: JSAny;
|
|
|
|
try {
|
|
|
|
// Let next be IteratorStep(iteratorRecord.[[Iterator]]).
|
|
|
|
// If next is an abrupt completion, set iteratorRecord.[[Done]] to
|
|
|
|
// true. ReturnIfAbrupt(next).
|
|
|
|
const next: JSReceiver = iterator::IteratorStep(
|
|
|
|
iter, fastIteratorResultMap) otherwise goto Done;
|
|
|
|
|
|
|
|
// Let nextValue be IteratorValue(next).
|
|
|
|
// If nextValue is an abrupt completion, set iteratorRecord.[[Done]]
|
|
|
|
// to true.
|
|
|
|
// ReturnIfAbrupt(nextValue).
|
|
|
|
nextValue = iterator::IteratorValue(next, fastIteratorResultMap);
|
|
|
|
} catch (e) {
|
|
|
|
goto Reject(e);
|
2020-01-21 15:15:35 +00:00
|
|
|
}
|
|
|
|
|
2020-06-05 12:51:25 +00:00
|
|
|
// Check if we reached the limit.
|
|
|
|
if (index == kPropertyArrayHashFieldMax) {
|
|
|
|
// If there are too many elements (currently more than 2**21-1),
|
|
|
|
// raise a RangeError here (which is caught below and turned into
|
|
|
|
// a rejection of the resulting promise). We could gracefully handle
|
|
|
|
// this case as well and support more than this number of elements
|
|
|
|
// by going to a separate function and pass the larger indices via a
|
|
|
|
// separate context, but it doesn't seem likely that we need this,
|
|
|
|
// and it's unclear how the rest of the system deals with 2**21 live
|
|
|
|
// Promises anyway.
|
|
|
|
ThrowRangeError(
|
|
|
|
MessageTemplate::kTooManyElementsInPromiseCombinator, 'all');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set remainingElementsCount.[[Value]] to
|
|
|
|
// remainingElementsCount.[[Value]] + 1.
|
|
|
|
const remainingElementsCount = UnsafeCast<Smi>(
|
|
|
|
resolveElementContext[PromiseAllResolveElementContextSlots::
|
|
|
|
kPromiseAllResolveElementRemainingSlot]);
|
|
|
|
resolveElementContext[PromiseAllResolveElementContextSlots::
|
|
|
|
kPromiseAllResolveElementRemainingSlot] =
|
|
|
|
remainingElementsCount + 1;
|
|
|
|
|
|
|
|
// Let resolveElement be CreateBuiltinFunction(steps,
|
|
|
|
// « [[AlreadyCalled]],
|
|
|
|
// [[Index]],
|
|
|
|
// [[Values]],
|
|
|
|
// [[Capability]],
|
|
|
|
// [[RemainingElements]]
|
|
|
|
// »).
|
|
|
|
// Set resolveElement.[[AlreadyCalled]] to a Record { [[Value]]: false
|
|
|
|
// }. Set resolveElement.[[Index]] to index. Set
|
|
|
|
// resolveElement.[[Values]] to values. Set
|
|
|
|
// resolveElement.[[Capability]] to resultCapability. Set
|
|
|
|
// resolveElement.[[RemainingElements]] to remainingElementsCount.
|
|
|
|
const resolveElementFun = createResolveElementFunctor.Call(
|
|
|
|
resolveElementContext, nativeContext, index, capability);
|
|
|
|
const rejectElementFun = createRejectElementFunctor.Call(
|
|
|
|
resolveElementContext, nativeContext, index, capability);
|
|
|
|
|
|
|
|
// We can skip the "then" lookup on the result of the "resolve" call and
|
|
|
|
// immediately chain the continuation onto the {next_value} if:
|
|
|
|
//
|
|
|
|
// (a) The {constructor} is the intrinsic %Promise% function, and
|
|
|
|
// looking up "resolve" on {constructor} yields the initial
|
|
|
|
// Promise.resolve() builtin, and
|
|
|
|
// (b) the promise @@species protector cell is valid, meaning that
|
|
|
|
// no one messed with the Symbol.species property on any
|
|
|
|
// intrinsic promise or on the Promise.prototype, and
|
|
|
|
// (c) the {next_value} is a JSPromise whose [[Prototype]] field
|
|
|
|
// contains the intrinsic %PromisePrototype%, and
|
|
|
|
// (d) we're not running with async_hooks or DevTools enabled.
|
|
|
|
//
|
|
|
|
// In that case we also don't need to allocate a chained promise for
|
|
|
|
// the PromiseReaction (aka we can pass undefined to
|
|
|
|
// PerformPromiseThen), since this is only necessary for DevTools and
|
|
|
|
// PromiseHooks.
|
|
|
|
if (promiseResolveFunction != Undefined ||
|
|
|
|
IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() ||
|
|
|
|
IsPromiseSpeciesProtectorCellInvalid() || Is<Smi>(nextValue) ||
|
|
|
|
!IsPromiseThenLookupChainIntact(
|
|
|
|
nativeContext, UnsafeCast<HeapObject>(nextValue).map)) {
|
|
|
|
// Let nextPromise be ? Call(constructor, _promiseResolve_, «
|
|
|
|
// nextValue »).
|
|
|
|
const nextPromise =
|
|
|
|
CallResolve(constructor, promiseResolveFunction, nextValue);
|
|
|
|
|
|
|
|
// Perform ? Invoke(nextPromise, "then", « resolveElement,
|
|
|
|
// resultCapability.[[Reject]] »).
|
|
|
|
const then = GetProperty(nextPromise, kThenString);
|
|
|
|
const thenResult = Call(
|
|
|
|
nativeContext, then, nextPromise, resolveElementFun,
|
|
|
|
rejectElementFun);
|
|
|
|
|
|
|
|
// For catch prediction, mark that rejections here are
|
|
|
|
// semantically handled by the combined Promise.
|
|
|
|
if (IsDebugActive() && Is<JSPromise>(thenResult)) deferred {
|
|
|
|
SetPropertyStrict(
|
|
|
|
context, thenResult, kPromiseHandledBySymbol, promise);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
PerformPromiseThenImpl(
|
|
|
|
UnsafeCast<JSPromise>(nextValue), resolveElementFun,
|
|
|
|
rejectElementFun, Undefined);
|
2020-05-12 13:28:29 +00:00
|
|
|
}
|
2020-06-05 12:51:25 +00:00
|
|
|
|
|
|
|
// Set index to index + 1.
|
|
|
|
index += 1;
|
2020-01-21 15:15:35 +00:00
|
|
|
}
|
2020-06-05 12:51:25 +00:00
|
|
|
} catch (e) deferred {
|
|
|
|
iterator::IteratorCloseOnException(iter);
|
|
|
|
goto Reject(e);
|
2020-05-12 13:28:29 +00:00
|
|
|
} label Done {}
|
|
|
|
|
|
|
|
// Set iteratorRecord.[[Done]] to true.
|
|
|
|
// Set remainingElementsCount.[[Value]] to
|
|
|
|
// remainingElementsCount.[[Value]] - 1.
|
|
|
|
let remainingElementsCount = UnsafeCast<Smi>(
|
|
|
|
resolveElementContext[PromiseAllResolveElementContextSlots::
|
|
|
|
kPromiseAllResolveElementRemainingSlot]);
|
|
|
|
remainingElementsCount -= 1;
|
|
|
|
resolveElementContext[PromiseAllResolveElementContextSlots::
|
|
|
|
kPromiseAllResolveElementRemainingSlot] =
|
|
|
|
remainingElementsCount;
|
|
|
|
if (remainingElementsCount > 0) {
|
2020-05-19 07:36:02 +00:00
|
|
|
// Pre-allocate the backing store for the {values} to the desired
|
|
|
|
// capacity. We may already have elements in "values" - this happens
|
|
|
|
// when the Thenable calls the resolve callback immediately.
|
|
|
|
let values = UnsafeCast<FixedArray>(
|
2020-05-12 13:28:29 +00:00
|
|
|
resolveElementContext[PromiseAllResolveElementContextSlots::
|
2020-05-19 07:36:02 +00:00
|
|
|
kPromiseAllResolveElementValuesSlot]);
|
|
|
|
// 'index' is a 1-based index and incremented after every Promise. Later we
|
|
|
|
// use 'values' as a 0-based array, so capacity 'index - 1' is enough.
|
|
|
|
const newCapacity = SmiUntag(index) - 1;
|
|
|
|
|
|
|
|
const oldCapacity = values.length_intptr;
|
2020-05-12 13:28:29 +00:00
|
|
|
if (oldCapacity < newCapacity) {
|
2020-05-19 07:36:02 +00:00
|
|
|
values = ExtractFixedArray(values, 0, oldCapacity, newCapacity);
|
|
|
|
resolveElementContext[PromiseAllResolveElementContextSlots::
|
|
|
|
kPromiseAllResolveElementValuesSlot] = values;
|
2020-05-12 13:28:29 +00:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
deferred {
|
2020-05-19 07:36:02 +00:00
|
|
|
assert(remainingElementsCount == 0);
|
2020-05-12 13:28:29 +00:00
|
|
|
// If remainingElementsCount.[[Value]] is 0, then
|
|
|
|
// Let valuesArray be CreateArrayFromList(values).
|
|
|
|
// Perform ? Call(resultCapability.[[Resolve]], undefined,
|
|
|
|
// « valuesArray »).
|
2020-05-19 07:36:02 +00:00
|
|
|
|
|
|
|
const values = UnsafeCast<FixedArray>(
|
2020-05-12 13:28:29 +00:00
|
|
|
resolveElementContext[PromiseAllResolveElementContextSlots::
|
2020-05-19 07:36:02 +00:00
|
|
|
kPromiseAllResolveElementValuesSlot]);
|
|
|
|
const arrayMap = UnsafeCast<Map>(
|
|
|
|
nativeContext[NativeContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX]);
|
|
|
|
const valuesArray = NewJSArray(arrayMap, values);
|
2020-05-12 13:28:29 +00:00
|
|
|
Call(nativeContext, UnsafeCast<JSAny>(resolve), Undefined, valuesArray);
|
|
|
|
}
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
// Return resultCapability.[[Promise]].
|
|
|
|
return promise;
|
|
|
|
}
|
2020-01-21 15:15:35 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
transitioning macro GeneratePromiseAll<F1: type, F2: type>(
|
|
|
|
implicit context: Context)(
|
|
|
|
receiver: JSAny, iterable: JSAny, createResolveElementFunctor: F1,
|
|
|
|
createRejectElementFunctor: F2): JSAny {
|
2020-06-05 12:51:25 +00:00
|
|
|
const nativeContext = LoadNativeContext(context);
|
2020-05-12 13:28:29 +00:00
|
|
|
// Let C be the this value.
|
|
|
|
// If Type(C) is not Object, throw a TypeError exception.
|
|
|
|
const receiver = Cast<JSReceiver>(receiver)
|
|
|
|
otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Promise.all');
|
|
|
|
|
|
|
|
// Let promiseCapability be ? NewPromiseCapability(C).
|
|
|
|
// Don't fire debugEvent so that forwarding the rejection through all does
|
|
|
|
// not trigger redundant ExceptionEvents
|
|
|
|
const capability = NewPromiseCapability(receiver, False);
|
|
|
|
|
2020-06-05 12:51:25 +00:00
|
|
|
// NewPromiseCapability guarantees that receiver is Constructor.
|
|
|
|
assert(Is<Constructor>(receiver));
|
|
|
|
const constructor = UnsafeCast<Constructor>(receiver);
|
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
try {
|
2020-06-05 12:51:25 +00:00
|
|
|
// Let promiseResolve be GetPromiseResolve(C).
|
|
|
|
// IfAbruptRejectPromise(promiseResolve, promiseCapability).
|
|
|
|
const promiseResolveFunction =
|
|
|
|
GetPromiseResolve(nativeContext, constructor);
|
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
// Let iterator be GetIterator(iterable).
|
|
|
|
// IfAbruptRejectPromise(iterator, promiseCapability).
|
|
|
|
let i = iterator::GetIterator(iterable);
|
|
|
|
|
|
|
|
// Let result be PerformPromiseAll(iteratorRecord, C,
|
|
|
|
// promiseCapability). If result is an abrupt completion, then
|
|
|
|
// If iteratorRecord.[[Done]] is false, let result be
|
|
|
|
// IteratorClose(iterator, result).
|
|
|
|
// IfAbruptRejectPromise(result, promiseCapability).
|
|
|
|
return PerformPromiseAll(
|
2020-06-05 12:51:25 +00:00
|
|
|
nativeContext, i, constructor, capability, promiseResolveFunction,
|
|
|
|
createResolveElementFunctor, createRejectElementFunctor)
|
|
|
|
otherwise Reject;
|
2020-05-12 13:28:29 +00:00
|
|
|
} catch (e) deferred {
|
|
|
|
goto Reject(e);
|
|
|
|
} label Reject(e: Object) deferred {
|
|
|
|
// Exception must be bound to a JS value.
|
|
|
|
const e = UnsafeCast<JSAny>(e);
|
|
|
|
const reject = UnsafeCast<JSAny>(capability.reject);
|
|
|
|
Call(context, reject, Undefined, e);
|
|
|
|
return capability.promise;
|
2020-01-21 15:15:35 +00:00
|
|
|
}
|
2020-05-12 13:28:29 +00:00
|
|
|
}
|
2020-05-12 07:17:49 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
// ES#sec-promise.all
|
|
|
|
transitioning javascript builtin PromiseAll(
|
|
|
|
js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny {
|
|
|
|
return GeneratePromiseAll(
|
|
|
|
receiver, iterable, PromiseAllResolveElementFunctor{},
|
|
|
|
PromiseAllRejectElementFunctor{});
|
|
|
|
}
|
|
|
|
|
|
|
|
// ES#sec-promise.allsettled
|
|
|
|
// Promise.allSettled ( iterable )
|
|
|
|
transitioning javascript builtin PromiseAllSettled(
|
|
|
|
js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny {
|
|
|
|
return GeneratePromiseAll(
|
|
|
|
receiver, iterable, PromiseAllSettledResolveElementFunctor{},
|
|
|
|
PromiseAllSettledRejectElementFunctor{});
|
|
|
|
}
|
2020-05-12 07:17:49 +00:00
|
|
|
|
2020-05-12 13:28:29 +00:00
|
|
|
extern macro PromiseAllResolveElementSharedFunConstant(): SharedFunctionInfo;
|
|
|
|
extern macro PromiseAllSettledRejectElementSharedFunConstant():
|
|
|
|
SharedFunctionInfo;
|
|
|
|
extern macro PromiseAllSettledResolveElementSharedFunConstant():
|
|
|
|
SharedFunctionInfo;
|
2020-01-21 15:15:35 +00:00
|
|
|
}
|