Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/builtins/promise-any.tq')
-rw-r--r--deps/v8/src/builtins/promise-any.tq372
1 files changed, 372 insertions, 0 deletions
diff --git a/deps/v8/src/builtins/promise-any.tq b/deps/v8/src/builtins/promise-any.tq
new file mode 100644
index 00000000000..1046ed0a89c
--- /dev/null
+++ b/deps/v8/src/builtins/promise-any.tq
@@ -0,0 +1,372 @@
+// Copyright 2020 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-gen.h'
+
+namespace promise {
+extern enum PromiseAnyRejectElementContextSlots extends int31
+constexpr 'PromiseBuiltins::PromiseAnyRejectElementContextSlots' {
+ kPromiseAnyRejectElementRemainingSlot,
+ kPromiseAnyRejectElementCapabilitySlot,
+ kPromiseAnyRejectElementErrorsArraySlot,
+ kPromiseAnyRejectElementLength
+}
+
+extern operator '[]=' macro StoreContextElement(
+ Context, constexpr PromiseAnyRejectElementContextSlots, Object): void;
+extern operator '[]' macro LoadContextElement(
+ Context, constexpr PromiseAnyRejectElementContextSlots): Object;
+
+// Creates the context used by all Promise.any reject element closures,
+// together with the errors array. Since all closures for a single Promise.any
+// 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). See Promise.all which uses the same approach.
+transitioning macro CreatePromiseAnyRejectElementContext(
+ implicit context: Context)(
+ capability: PromiseCapability, nativeContext: NativeContext): Context {
+ const rejectContext = AllocateSyntheticFunctionContext(
+ nativeContext,
+ PromiseAnyRejectElementContextSlots::kPromiseAnyRejectElementLength);
+ rejectContext[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementRemainingSlot] = SmiConstant(1);
+ rejectContext[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementCapabilitySlot] = capability;
+ // Will be set later.
+ rejectContext[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementErrorsArraySlot] = Undefined;
+ return rejectContext;
+}
+
+macro CreatePromiseAnyRejectElementFunction(implicit context: Context)(
+ rejectElementContext: Context, index: Smi,
+ nativeContext: NativeContext): JSFunction {
+ assert(index > 0);
+ assert(index < kPropertyArrayHashFieldMax);
+ const map = UnsafeCast<Map>(
+ nativeContext
+ [NativeContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]);
+ const rejectInfo = PromiseAnyRejectElementSharedFunConstant();
+ const reject =
+ AllocateFunctionWithMapAndContext(map, rejectInfo, rejectElementContext);
+ assert(kPropertyArrayNoHashSentinel == 0);
+ reject.properties_or_hash = index;
+ return reject;
+}
+
+// https://tc39.es/proposal-promise-any/#sec-promise.any-reject-element-functions
+transitioning javascript builtin
+PromiseAnyRejectElementClosure(
+ js-implicit context: Context, receiver: JSAny,
+ target: JSFunction)(value: JSAny): JSAny {
+ // 1. Let F be the active function object.
+
+ // 2. Let alreadyCalled be F.[[AlreadyCalled]].
+
+ // 3. If alreadyCalled.[[Value]] is true, return undefined.
+
+ // We use the function's context as the marker to remember whether this
+ // reject element closure was already called. It points to the reject
+ // element context (which is a FunctionContext) until it was called the
+ // first time, in which case we make it point to the native context here
+ // to mark this reject element closure as done.
+ if (IsNativeContext(context)) deferred {
+ return Undefined;
+ }
+
+ assert(
+ context.length ==
+ PromiseAnyRejectElementContextSlots::kPromiseAnyRejectElementLength);
+
+ // 4. Set alreadyCalled.[[Value]] to true.
+ const nativeContext = LoadNativeContext(context);
+ target.context = nativeContext;
+
+ // 5. Let index be F.[[Index]].
+ assert(kPropertyArrayNoHashSentinel == 0);
+ const identityHash = LoadJSReceiverIdentityHash(target) otherwise unreachable;
+ assert(identityHash > 0);
+ const index = identityHash - 1;
+
+ // 6. Let errors be F.[[Errors]].
+ if (context[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementErrorsArraySlot] == Undefined) {
+ // We're going to reject the Promise with a more fundamental error (e.g.,
+ // something went wrong with iterating the Promises). We don't need to
+ // construct the "errors" array.
+ return Undefined;
+ }
+
+ const errorsArray = UnsafeCast<FixedArray>(
+ context[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementErrorsArraySlot]);
+
+ // 7. Let promiseCapability be F.[[Capability]].
+
+ // 8. Let remainingElementsCount be F.[[RemainingElements]].
+ let remainingElementsCount =
+ UnsafeCast<Smi>(context[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementRemainingSlot]);
+ // 9. Set errors[index] to x.
+ errorsArray.objects[index] = value;
+
+ // 10. Set remainingElementsCount.[[Value]] to
+ // remainingElementsCount.[[Value]] - 1.
+ remainingElementsCount = remainingElementsCount - 1;
+ context[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementRemainingSlot] = remainingElementsCount;
+
+ // 11. If remainingElementsCount.[[Value]] is 0, then
+ if (remainingElementsCount == 0) {
+ // a. Let error be a newly created AggregateError object.
+
+ // b. Set error.[[AggregateErrors]] to errors.
+ const error = ConstructAggregateError(errorsArray);
+ // c. Return ? Call(promiseCapability.[[Reject]], undefined, « error »).
+ const capability = UnsafeCast<PromiseCapability>(
+ context[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementCapabilitySlot]);
+ Call(context, UnsafeCast<Callable>(capability.reject), Undefined, error);
+ }
+
+ // 12. Return undefined.
+ return Undefined;
+}
+
+transitioning macro PerformPromiseAny(implicit context: Context)(
+ iteratorRecord: iterator::IteratorRecord, constructor: Constructor,
+ resultCapability: PromiseCapability): JSAny labels
+Reject(Object) {
+ // 1. Assert: ! IsConstructor(constructor) is true.
+ // 2. Assert: resultCapability is a PromiseCapability Record.
+
+ const nativeContext = LoadNativeContext(context);
+
+ // 3. Let errors be a new empty List.
+ let growableErrorsArray = growable_fixed_array::NewGrowableFixedArray();
+
+ // 4. Let remainingElementsCount be a new Record { [[Value]]: 1 }.
+ const rejectElementContext =
+ CreatePromiseAnyRejectElementContext(resultCapability, nativeContext);
+
+ // 5. Let index be 0.
+ // (We subtract 1 in the PromiseAnyRejectElementClosure).
+ let index: Smi = 1;
+
+ try {
+ // We can skip the "resolve" lookup on {constructor} if it's the
+ // Promise constructor and the Promise.resolve protector is intact,
+ // as that guards the lookup path for the "resolve" property on the
+ // Promise constructor.
+ let promiseResolveFunction: JSAny = Undefined;
+ if (!IsPromiseResolveLookupChainIntact(nativeContext, constructor))
+ deferred {
+ // 6. Let promiseResolve be ? Get(constructor, `"resolve"`).
+ const promiseResolve = GetProperty(constructor, kResolveString);
+ // 7. If IsCallable(promiseResolve) is false, throw a
+ // TypeError exception.
+ promiseResolveFunction = Cast<Callable>(promiseResolve)
+ otherwise ThrowTypeError(
+ MessageTemplate::kCalledNonCallable, 'resolve');
+ }
+ const fastIteratorResultMap = UnsafeCast<Map>(
+ nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]);
+ // 8. Repeat,
+ while (true) {
+ let nextValue: JSAny;
+ try {
+ // a. Let next be IteratorStep(iteratorRecord).
+
+ // b. If next is an abrupt completion, set
+ // iteratorRecord.[[Done]] to true.
+
+ // c. ReturnIfAbrupt(next).
+
+ // d. if next is false, then [continues below in "Done"]
+ const next: JSReceiver = iterator::IteratorStep(
+ iteratorRecord, fastIteratorResultMap) otherwise goto Done;
+ // e. Let nextValue be IteratorValue(next).
+
+ // f. If nextValue is an abrupt completion, set
+ // iteratorRecord.[[Done]] to true.
+
+ // g. ReturnIfAbrupt(nextValue).
+ nextValue = iterator::IteratorValue(next, fastIteratorResultMap);
+ } catch (e) {
+ goto Reject(e);
+ }
+
+ // We store the indices as identity hash on the reject element
+ // closures. Thus, we need this limit.
+ if (index == kPropertyArrayHashFieldMax) {
+ // If there are too many elements (currently more than
+ // 2**21-1), raise a RangeError here (which is caught later 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, 'any');
+ }
+
+ // h. Append undefined to errors.
+ growableErrorsArray.Push(Undefined);
+
+ let nextPromise: JSAny;
+ // i. Let nextPromise be ? Call(constructor, promiseResolve,
+ // «nextValue »).
+ nextPromise = CallResolve(constructor, promiseResolveFunction, nextValue);
+
+ // j. Let steps be the algorithm steps defined in Promise.any
+ // Reject Element Functions.
+
+ // k. Let rejectElement be ! CreateBuiltinFunction(steps, «
+ // [[AlreadyCalled]], [[Index]],
+ // [[Errors]], [[Capability]], [[RemainingElements]] »).
+
+ // l. Set rejectElement.[[AlreadyCalled]] to a new Record {
+ // [[Value]]: false }.
+
+ // m. Set rejectElement.[[Index]] to index.
+
+ // n. Set rejectElement.[[Errors]] to errors.
+
+ // o. Set rejectElement.[[Capability]] to resultCapability.
+
+ // p. Set rejectElement.[[RemainingElements]] to
+ // remainingElementsCount.
+ const rejectElement = CreatePromiseAnyRejectElementFunction(
+ rejectElementContext, index, nativeContext);
+ // q. Set remainingElementsCount.[[Value]] to
+ // remainingElementsCount.[[Value]] + 1.
+ const remainingElementsCount = UnsafeCast<Smi>(
+ rejectElementContext[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementRemainingSlot]);
+ rejectElementContext[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementRemainingSlot] =
+ remainingElementsCount + 1;
+
+ // r. Perform ? Invoke(nextPromise, "then", «
+ // resultCapability.[[Resolve]], rejectElement »).
+ let thenResult: JSAny;
+
+ const then = GetProperty(nextPromise, kThenString);
+ thenResult = Call(
+ context, then, nextPromise,
+ UnsafeCast<JSAny>(resultCapability.resolve), rejectElement);
+
+ // s. Increase index by 1.
+ index += 1;
+
+ // For catch prediction, mark that rejections here are
+ // semantically handled by the combined Promise.
+ if (IsDebugActive() && Is<JSPromise>(thenResult)) deferred {
+ SetPropertyStrict(
+ context, thenResult, kPromiseHandledBySymbol,
+ resultCapability.promise);
+ SetPropertyStrict(
+ context, rejectElement, kPromiseForwardingHandlerSymbol, True);
+ }
+ }
+ } catch (e) deferred {
+ iterator::IteratorCloseOnException(iteratorRecord);
+ goto Reject(e);
+ } label Done {}
+
+ // (8.d)
+ // i. Set iteratorRecord.[[Done]] to true.
+ // ii. Set remainingElementsCount.[[Value]] to
+ // remainingElementsCount.[[Value]] - 1.
+ let remainingElementsCount = UnsafeCast<Smi>(
+ rejectElementContext[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementRemainingSlot]);
+ remainingElementsCount -= 1;
+ rejectElementContext[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementRemainingSlot] =
+ remainingElementsCount;
+
+ const errorsArray = growableErrorsArray.ToFixedArray();
+ rejectElementContext[PromiseAnyRejectElementContextSlots::
+ kPromiseAnyRejectElementErrorsArraySlot] =
+ errorsArray;
+
+ // iii. If remainingElementsCount.[[Value]] is 0, then
+ if (remainingElementsCount == 0) deferred {
+ // 1. Let error be a newly created AggregateError object.
+ // 2. Set error.[[AggregateErrors]] to errors.
+ const error = ConstructAggregateError(errorsArray);
+ // 3. Return ThrowCompletion(error).
+ goto Reject(error);
+ }
+ // iv. Return resultCapability.[[Promise]].
+ return resultCapability.promise;
+}
+
+// https://tc39.es/proposal-promise-any/#sec-promise.any
+transitioning javascript builtin
+PromiseAny(
+ js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny {
+ // 1. Let C be the this value.
+ const receiver = Cast<JSReceiver>(receiver)
+ otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Promise.any');
+
+ // 2. Let promiseCapability be ? NewPromiseCapability(C).
+ const capability = NewPromiseCapability(receiver, False);
+
+ // NewPromiseCapability guarantees that receiver is Constructor
+ assert(Is<Constructor>(receiver));
+ const constructor = UnsafeCast<Constructor>(receiver);
+
+ try {
+ let iteratorRecord: iterator::IteratorRecord;
+ try {
+ // 3. Let iteratorRecord be GetIterator(iterable).
+
+ // 4. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
+ // (catch below)
+ iteratorRecord = iterator::GetIterator(iterable);
+
+ // 5. Let result be PerformPromiseAny(iteratorRecord, C,
+ // promiseCapability).
+
+ // 6. If result is an abrupt completion, then
+
+ // a. If iteratorRecord.[[Done]] is false, set result to
+ // IteratorClose(iteratorRecord, result).
+
+ // b. IfAbruptRejectPromise(result, promiseCapability).
+
+ // [Iterator closing handled by PerformPromiseAny]
+
+ // 7. Return Completion(result).
+ return PerformPromiseAny(iteratorRecord, constructor, capability)
+ otherwise Reject;
+ } catch (e) deferred {
+ goto Reject(e);
+ }
+ } label Reject(e: Object) deferred {
+ // Exception must be bound to a JS value.
+ assert(e != TheHole);
+ Call(
+ context, UnsafeCast<Callable>(capability.reject), Undefined,
+ UnsafeCast<JSAny>(e));
+ return capability.promise;
+ }
+}
+
+transitioning macro ConstructAggregateError(implicit context: Context)(
+ errorsArray: FixedArray): JSObject {
+ const obj: JSAggregateError = error::ConstructInternalAggregateErrorHelper(
+ context, SmiConstant(MessageTemplate::kAllPromisesRejected));
+ obj.errors = errorsArray;
+ return obj;
+}
+
+extern macro PromiseAnyRejectElementSharedFunConstant(): SharedFunctionInfo;
+}