diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 697c665bad..7787eb4614 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -2140,9 +2140,6 @@ void Genesis::InitializeGlobal(Handle global_object, InstallSpeciesGetter(promise_fun); - SimpleInstallFunction(promise_fun, "all", Builtins::kPromiseAll, 1, true, - DONT_ENUM); - SimpleInstallFunction(promise_fun, "resolve", Builtins::kPromiseResolve, 1, true, DONT_ENUM); @@ -2225,16 +2222,6 @@ void Genesis::InitializeGlobal(Handle global_object, info->set_length(1); native_context()->set_promise_reject_shared_fun(*info); } - - { - Handle code = - isolate->builtins()->PromiseAllResolveElementClosure(); - Handle info = - factory->NewSharedFunctionInfo(factory->empty_string(), code, false); - info->set_internal_formal_parameter_count(1); - info->set_length(1); - native_context()->set_promise_all_resolve_element_shared_fun(*info); - } } { // -- R e g E x p diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h index cc202c3266..bc29bd8f1d 100644 --- a/src/builtins/builtins-definitions.h +++ b/src/builtins/builtins-definitions.h @@ -718,7 +718,6 @@ namespace internal { TFJ(PromiseResolveClosure, 1, kValue) \ /* ES #sec-promise-reject-functions */ \ TFJ(PromiseRejectClosure, 1, kValue) \ - TFJ(PromiseAllResolveElementClosure, 1, kValue) \ /* ES #sec-promise.prototype.then */ \ TFJ(PromiseThen, 2, kOnFullfilled, kOnRejected) \ /* ES #sec-promise.prototype.catch */ \ @@ -738,8 +737,6 @@ namespace internal { TFJ(PromiseCatchFinally, 1, kReason) \ TFJ(PromiseValueThunkFinally, 0) \ TFJ(PromiseThrowerFinally, 0) \ - /* ES #sec-promise.all */ \ - TFJ(PromiseAll, 1, kIterable) \ \ /* Proxy */ \ CPP(ProxyConstructor) \ @@ -1032,7 +1029,6 @@ namespace internal { V(AsyncGeneratorAwaitCaught) \ V(AsyncGeneratorAwaitUncaught) \ V(PerformNativePromiseThen) \ - V(PromiseAll) \ V(PromiseConstructor) \ V(PromiseHandle) \ V(PromiseResolve) \ diff --git a/src/builtins/builtins-promise-gen.cc b/src/builtins/builtins-promise-gen.cc index cdcee23c48..a050f18d66 100644 --- a/src/builtins/builtins-promise-gen.cc +++ b/src/builtins/builtins-promise-gen.cc @@ -1799,328 +1799,5 @@ TF_BUILTIN(PerformNativePromiseThen, PromiseBuiltinsAssembler) { Return(result_promise); } -Node* PromiseBuiltinsAssembler::MutableHeapNumberInc(Node* number) { - Node* const value = LoadHeapNumberValue(number); - Node* const result = Float64Add(value, Float64Constant(1.0)); - StoreHeapNumberValue(number, result); - return result; -} - -Node* PromiseBuiltinsAssembler::MutableHeapNumberDec(Node* number) { - Node* const value = LoadHeapNumberValue(number); - Node* const result = Float64Sub(value, Float64Constant(1.0)); - StoreHeapNumberValue(number, result); - return result; -} - -Node* PromiseBuiltinsAssembler::PerformPromiseAll( - Node* context, Node* constructor, Node* capability, Node* iterator, - Label* if_exception, Variable* var_exception) { - Label close_iterator(this, Label::kDeferred); - -#define HANDLE_EXCEPTION(__node__, __close_iterator__) \ - do { \ - if (if_exception != nullptr) { \ - Node* const node = (__node__); \ - const bool should_close_iterator = (__close_iterator__); \ - if (should_close_iterator) { \ - GotoIfException(node, &close_iterator, var_exception); \ - } else { \ - GotoIfException(node, if_exception, var_exception); \ - } \ - } \ - } while (0) - - Node* const native_context = LoadNativeContext(context); - Node* const array_map = LoadContextElement( - native_context, Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX); - Node* const fast_iterator_result_map = - LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX); - Node* const values_array = AllocateJSArray(FAST_ELEMENTS, array_map, - IntPtrConstant(0), SmiConstant(0)); - Node* const remaining_elements = - AllocateHeapNumberWithValue(Float64Constant(1.0), MUTABLE); - - VARIABLE(var_index, MachineRepresentation::kTagged, SmiConstant(0)); - - Node* const instrumenting = IsDebugActive(); - - // For catch prediction, don't treat the .then calls as handling it; - // instead, recurse outwards. - Label did_set_forwarding_handler(this); - GotoIfNot(instrumenting, &did_set_forwarding_handler); - CallRuntime(Runtime::kSetProperty, context, - LoadObjectField(capability, JSPromiseCapability::kRejectOffset), - HeapConstant(factory()->promise_forwarding_handler_symbol()), - TrueConstant(), SmiConstant(STRICT)); - Goto(&did_set_forwarding_handler); - BIND(&did_set_forwarding_handler); - - Label loop(this, &var_index), break_loop(this); - Goto(&loop); - BIND(&loop); - { - // Let next be IteratorStep(iteratorRecord.[[Iterator]]). - // If next is an abrupt completion, set iteratorRecord.[[Done]] to true. - // ReturnIfAbrupt(next). - Node* const next = - IteratorStep(context, iterator, &break_loop, fast_iterator_result_map, - if_exception, var_exception); - - // Let nextValue be IteratorValue(next). - // If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to - // true. - // ReturnIfAbrupt(nextValue). - Node* const next_value = IteratorValue( - context, next, fast_iterator_result_map, if_exception, var_exception); - - // Let nextPromise be ? Invoke(constructor, "resolve", « nextValue »). - Node* const promise_resolve = - GetProperty(context, constructor, factory()->resolve_string()); - HANDLE_EXCEPTION(promise_resolve, true); - - Node* const next_promise = CallJS(CodeFactory::Call(isolate()), context, - promise_resolve, constructor, next_value); - HANDLE_EXCEPTION(next_promise, true); - - // Let resolveElement be a new built-in function object as defined in - // Promise.all Resolve Element Functions. - Node* const resolve_context = CreatePromiseContext( - native_context, - static_cast(PromiseAllResolveElementContext::kLength)); - StoreContextElementNoWriteBarrier( - resolve_context, - static_cast(PromiseAllResolveElementContext::kAlreadyVisitedSlot), - SmiConstant(0)); - StoreContextElementNoWriteBarrier( - resolve_context, - static_cast(PromiseAllResolveElementContext::kIndexSlot), - var_index.value()); - StoreContextElement( - resolve_context, - static_cast(PromiseAllResolveElementContext::kCapabilitySlot), - capability); - StoreContextElement( - resolve_context, - static_cast( - PromiseAllResolveElementContext::kRemainingElementsSlot), - remaining_elements); - StoreContextElement( - resolve_context, - static_cast(PromiseAllResolveElementContext::kValuesArraySlot), - values_array); - - Node* const map = LoadContextElement( - native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); - Node* const resolve_info = LoadContextElement( - native_context, Context::PROMISE_ALL_RESOLVE_ELEMENT_SHARED_FUN); - Node* const resolve = - AllocateFunctionWithMapAndContext(map, resolve_info, resolve_context); - - // Set remainingElementsCount.[[Value]] to - // remainingElementsCount.[[Value]] + 1. - MutableHeapNumberInc(remaining_elements); - - // Perform ? Invoke(nextPromise, "then", « resolveElement, - // resultCapability.[[Reject]] »). - Node* const then = - GetProperty(context, next_promise, factory()->then_string()); - HANDLE_EXCEPTION(then, true); - - Node* const then_call = CallJS( - CodeFactory::Call(isolate()), context, then, next_promise, resolve, - LoadObjectField(capability, JSPromiseCapability::kRejectOffset)); - HANDLE_EXCEPTION(then_call, true); - - // For catch prediction, mark that rejections here are semantically - // handled by the combined Promise. - Label did_set_handled_by(this); - GotoIfNot(instrumenting, &did_set_handled_by); - GotoIf(TaggedIsSmi(then_call), &did_set_handled_by); - GotoIfNot(HasInstanceType(then_call, JS_PROMISE_TYPE), &did_set_handled_by); - CallRuntime( - Runtime::kSetProperty, context, then_call, - HeapConstant(factory()->promise_handled_by_symbol()), - LoadObjectField(capability, JSPromiseCapability::kPromiseOffset), - SmiConstant(STRICT)); - Goto(&did_set_handled_by); - BIND(&did_set_handled_by); - - // Set index to index + 1 - var_index.Bind(NumberInc(var_index.value())); - Goto(&loop); - } - - Label resolve_promise(this), return_promise(this); - BIND(&close_iterator); - { - Node* exception = var_exception->value(); - CSA_ASSERT(this, WordNotEqual(exception, UndefinedConstant())); - IteratorClose(context, iterator, if_exception, var_exception); - Node* const reject = - LoadObjectField(capability, JSPromiseCapability::kRejectOffset); - CallJS(CodeFactory::Call(isolate()), context, reject, UndefinedConstant(), - exception); - Goto(&return_promise); - } - - BIND(&break_loop); - - // Update array length - Label did_set_length(this); - // If length is not a positive Smi, it will be updated by - // %CreateDataProperty() in PromiseAllResolveElementClosure - GotoIfNot(TaggedIsPositiveSmi(var_index.value()), &did_set_length); - StoreObjectFieldNoWriteBarrier(values_array, JSArray::kLengthOffset, - var_index.value()); - Goto(&did_set_length); - BIND(&did_set_length); - - // Set iteratorRecord.[[Done]] to true. - // Set remainingElementsCount.[[Value]] to - // remainingElementsCount.[[Value]] - 1. - Node* const remaining = MutableHeapNumberDec(remaining_elements); - Branch(Float64Equal(remaining, Float64Constant(0.0)), &resolve_promise, - &return_promise); - - // If remainingElementsCount.[[Value]] is 0, then - // Let valuesArray be CreateArrayFromList(values). - // Perform ? Call(resultCapability.[[Resolve]], undefined, - // « valuesArray »). - BIND(&resolve_promise); - - Node* const resolve = - LoadObjectField(capability, JSPromiseCapability::kResolveOffset); - Node* const resolve_call = CallJS(CodeFactory::Call(isolate()), context, - resolve, UndefinedConstant(), values_array); - HANDLE_EXCEPTION(resolve_call, false); - Goto(&return_promise); - - // Return resultCapability.[[Promise]]. - BIND(&return_promise); - Node* const promise = - LoadObjectField(capability, JSPromiseCapability::kPromiseOffset); - return promise; - -#undef HANDLE_EXCEPTION -} - -// ES#sec-promise.all -// Promise.all ( iterable ) -TF_BUILTIN(PromiseAll, PromiseBuiltinsAssembler) { - // Let C be the this value. - // If Type(C) is not Object, throw a TypeError exception. - Node* const receiver = Parameter(Descriptor::kReceiver); - Node* const context = Parameter(Descriptor::kContext); - ThrowIfNotJSReceiver(context, receiver, 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 - Node* const debug_event = FalseConstant(); - Node* const capability = NewPromiseCapability(context, receiver, debug_event); - - VARIABLE(var_exception, MachineRepresentation::kTagged, UndefinedConstant()); - Label reject_promise(this, &var_exception, Label::kDeferred); - - // Let iterator be GetIterator(iterable). - // IfAbruptRejectPromise(iterator, promiseCapability). - Node* const iterable = Parameter(Descriptor::kIterable); - Node* const iterator = - GetIterator(context, iterable, &reject_promise, &var_exception); - - // 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). - Node* const result = PerformPromiseAll( - context, receiver, capability, iterator, &reject_promise, &var_exception); - - Return(result); - - BIND(&reject_promise); - { - Node* const reject = - LoadObjectField(capability, JSPromiseCapability::kRejectOffset); - Callable callable = CodeFactory::Call(isolate()); - CallJS(callable, context, reject, UndefinedConstant(), - var_exception.value()); - - Node* const promise = - LoadObjectField(capability, JSPromiseCapability::kPromiseOffset); - Return(promise); - } -} - -TF_BUILTIN(PromiseAllResolveElementClosure, PromiseBuiltinsAssembler) { - Node* const value = Parameter(Descriptor::kValue); - Node* const context = Parameter(Descriptor::kContext); - - CSA_ASSERT(this, SmiEqual(LoadFixedArrayBaseLength(context), - SmiConstant(static_cast( - PromiseAllResolveElementContext::kLength)))); - - Label already_called(this), resolve_promise(this); - GotoIf( - SmiEqual(LoadContextElement( - context, - static_cast( - PromiseAllResolveElementContext::kAlreadyVisitedSlot)), - SmiConstant(1)), - &already_called); - StoreContextElementNoWriteBarrier( - context, - static_cast(PromiseAllResolveElementContext::kAlreadyVisitedSlot), - SmiConstant(1)); - - Node* const index = LoadContextElement( - context, static_cast(PromiseAllResolveElementContext::kIndexSlot)); - Node* const values_array = LoadContextElement( - context, - static_cast(PromiseAllResolveElementContext::kValuesArraySlot)); - - // Set element in FixedArray - Label runtime_set_element(this), did_set_element(this); - GotoIfNot(TaggedIsPositiveSmi(index), &runtime_set_element); - { - VARIABLE(var_elements, MachineRepresentation::kTagged, - LoadElements(values_array)); - PossiblyGrowElementsCapacity(SMI_PARAMETERS, FAST_ELEMENTS, values_array, - index, &var_elements, SmiConstant(1), - &runtime_set_element); - StoreFixedArrayElement(var_elements.value(), index, value, - UPDATE_WRITE_BARRIER, 0, SMI_PARAMETERS); - } - Goto(&did_set_element); - BIND(&runtime_set_element); - // New-space filled up or index too large, set element via runtime - CallRuntime(Runtime::kCreateDataProperty, context, values_array, index, - value); - Goto(&did_set_element); - BIND(&did_set_element); - - Node* const remaining_elements = LoadContextElement( - context, static_cast( - PromiseAllResolveElementContext::kRemainingElementsSlot)); - Node* const result = MutableHeapNumberDec(remaining_elements); - GotoIf(Float64Equal(result, Float64Constant(0)), &resolve_promise); - Return(UndefinedConstant()); - - BIND(&resolve_promise); - Node* const capability = LoadContextElement( - context, - static_cast(PromiseAllResolveElementContext::kCapabilitySlot)); - Node* const resolve = - LoadObjectField(capability, JSPromiseCapability::kResolveOffset); - CallJS(CodeFactory::Call(isolate()), context, resolve, UndefinedConstant(), - values_array); - Return(UndefinedConstant()); - - BIND(&already_called); - Return(UndefinedConstant()); -} - } // namespace internal } // namespace v8 diff --git a/src/builtins/builtins-promise-gen.h b/src/builtins/builtins-promise-gen.h index 06dbfd26a1..a03132d6a6 100644 --- a/src/builtins/builtins-promise-gen.h +++ b/src/builtins/builtins-promise-gen.h @@ -28,25 +28,6 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler { kPromiseContextLength, }; - enum class PromiseAllResolveElementContext { - // Whether the resolve callback was already called. - kAlreadyVisitedSlot = Context::MIN_CONTEXT_SLOTS, - - // Index into the values array - kIndexSlot, - - // Remaining elements count (mutable HeapNumber) - kRemainingElementsSlot, - - // Promise capability from Promise.all - kCapabilitySlot, - - // Values array from Promise.all - kValuesArraySlot, - - kLength - }; - enum FunctionContextSlot { kCapabilitySlot = Context::MIN_CONTEXT_SLOTS, @@ -99,10 +80,6 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler { Node* NewPromiseCapability(Node* context, Node* constructor, Node* debug_event = nullptr); - // Load heap number value, increment/decrement, and return the value component - Node* MutableHeapNumberInc(Node* number); - Node* MutableHeapNumberDec(Node* number); - protected: void PromiseInit(Node* promise); @@ -158,10 +135,6 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler { Node* CreateThrowerFunctionContext(Node* reason, Node* native_context); Node* CreateThrowerFunction(Node* reason, Node* native_context); - Node* PerformPromiseAll(Node* context, Node* constructor, Node* capability, - Node* iterator, Label* if_exception, - Variable* var_exception); - private: Node* AllocateJSPromise(Node* context); }; diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc index d05d4aa27d..94567c824c 100644 --- a/src/code-stub-assembler.cc +++ b/src/code-stub-assembler.cc @@ -4642,161 +4642,6 @@ Node* CodeStubAssembler::ToInteger(Node* context, Node* input, return var_arg.value(); } -#define HANDLE_EXCEPTION(__node__) \ - do { \ - if (if_exception != nullptr) { \ - Node* const node = (__node__); \ - GotoIfException(node, if_exception, exception); \ - } \ - } while (0) - -Node* CodeStubAssembler::GetIterator(Node* context, Node* object, - Label* if_exception, Variable* exception) { - Node* method = GetProperty(context, object, factory()->iterator_symbol()); - HANDLE_EXCEPTION(method); - - Callable callable = CodeFactory::Call(isolate()); - Node* iterator = CallJS(callable, context, method, object); - HANDLE_EXCEPTION(iterator); - - Label done(this), if_notobject(this, Label::kDeferred); - Branch(IsJSReceiver(iterator), &done, &if_notobject); - - BIND(&if_notobject); - { - Node* ret = - CallRuntime(Runtime::kThrowTypeError, context, - SmiConstant(MessageTemplate::kNotAnIterator), iterator); - HANDLE_EXCEPTION(ret); - Goto(&done); - } - - BIND(&done); - return iterator; -} - -Node* CodeStubAssembler::IteratorStep(Node* context, Node* iterator, - Label* if_done, - Node* fast_iterator_result_map, - Label* if_exception, - Variable* exception) { - DCHECK_NOT_NULL(if_done); - Node* next_method = GetProperty(context, iterator, factory()->next_string()); - HANDLE_EXCEPTION(next_method); - - Callable callable = CodeFactory::Call(isolate()); - Node* result = CallJS(callable, context, next_method, iterator); - HANDLE_EXCEPTION(result); - - Label if_notobject(this, Label::kDeferred), return_result(this); - GotoIf(TaggedIsSmi(result), &if_notobject); - GotoIfNot(IsJSReceiver(result), &if_notobject); - - auto IfFastIteratorResult = [=]() { - Node* done = LoadObjectField(result, JSIteratorResult::kDoneOffset); - CSA_ASSERT(this, IsBoolean(done)); - return done; - }; - - auto IfGenericIteratorResult = [=]() { - Node* done = GetProperty(context, result, factory()->done_string()); - HANDLE_EXCEPTION(done); - VARIABLE(var_done, MachineRepresentation::kTagged, done); - Label to_boolean(this, Label::kDeferred), return_result(this); - GotoIf(TaggedIsSmi(done), &to_boolean); - Branch(IsBoolean(done), &return_result, &to_boolean); - BIND(&to_boolean); - var_done.Bind(CallStub(CodeFactory::ToBoolean(isolate()), context, done)); - - Goto(&return_result); - BIND(&return_result); - return var_done.value(); - }; - - Node* done; - if (fast_iterator_result_map != nullptr) { - Node* map = LoadMap(result); - done = - Select(WordEqual(map, fast_iterator_result_map), IfFastIteratorResult, - IfGenericIteratorResult, MachineRepresentation::kTagged); - } else { - done = IfGenericIteratorResult(); - } - Goto(&return_result); - - BIND(&if_notobject); - { - Node* ret = - CallRuntime(Runtime::kThrowIteratorResultNotAnObject, context, result); - HANDLE_EXCEPTION(ret); - Goto(if_done); - } - - BIND(&return_result); - GotoIf(IsTrue(done), if_done); - return result; -} - -Node* CodeStubAssembler::IteratorValue(Node* context, Node* result, - Node* fast_iterator_result_map, - Label* if_exception, - Variable* exception) { - CSA_ASSERT(this, IsJSReceiver(result)); - - auto IfFastIteratorResult = [=]() { - return LoadObjectField(result, JSIteratorResult::kValueOffset); - }; - - auto IfGenericIteratorResult = [=]() { - Node* value = GetProperty(context, result, factory()->value_string()); - HANDLE_EXCEPTION(value); - return value; - }; - - if (fast_iterator_result_map != nullptr) { - Node* map = LoadMap(result); - return Select(WordEqual(map, fast_iterator_result_map), - IfFastIteratorResult, IfGenericIteratorResult, - MachineRepresentation::kTagged); - } else { - return IfGenericIteratorResult(); - } -} - -void CodeStubAssembler::IteratorClose(Node* context, Node* iterator, - Label* if_exception, - Variable* exception) { - CSA_ASSERT(this, IsJSReceiver(iterator)); - - Node* method = GetProperty(context, iterator, factory()->return_string()); - HANDLE_EXCEPTION(method); - - Label done(this); - GotoIf(IsNull(method), &done); - GotoIf(IsUndefined(method), &done); - - Node* inner_result = - CallJS(CodeFactory::Call(isolate()), context, method, iterator); - HANDLE_EXCEPTION(inner_result); - - Label if_notobject(this, Label::kDeferred); - - GotoIf(TaggedIsSmi(inner_result), &if_notobject); - Branch(IsJSReceiver(inner_result), &done, &if_notobject); - - BIND(&if_notobject); - { - Node* ret = CallRuntime(Runtime::kThrowIteratorResultNotAnObject, context, - inner_result); - HANDLE_EXCEPTION(ret); - Goto(&done); - } - - BIND(&done); -} - -#undef HANDLE_EXCEPTION - Node* CodeStubAssembler::DecodeWord32(Node* word32, uint32_t shift, uint32_t mask) { return Word32Shr(Word32And(word32, Int32Constant(mask)), diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h index 88eead8e96..8ac4f35968 100644 --- a/src/code-stub-assembler.h +++ b/src/code-stub-assembler.h @@ -879,35 +879,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* ToInteger(Node* context, Node* input, ToIntegerTruncationMode mode = kNoTruncation); - // https://tc39.github.io/ecma262/#sec-getiterator --- never used for - // @@asyncIterator. - Node* GetIterator(Node* context, Node* object, Label* if_exception = nullptr, - Variable* exception = nullptr); - - // https://tc39.github.io/ecma262/#sec-iteratorstep - // Returns `false` if the iterator is done, otherwise returns an - // iterator result. - // `fast_iterator_result_map` refers to the map for the JSIteratorResult - // object, loaded from the native context. - Node* IteratorStep(Node* context, Node* iterator, Label* if_done, - Node* fast_iterator_result_map = nullptr, - Label* if_exception = nullptr, - Variable* exception = nullptr); - - // https://tc39.github.io/ecma262/#sec-iteratorvalue - // Return the `value` field from an iterator. - // `fast_iterator_result_map` refers to the map for the JSIteratorResult - // object, loaded from the native context. - Node* IteratorValue(Node* context, Node* result, - Node* fast_iterator_result_map = nullptr, - Label* if_exception = nullptr, - Variable* exception = nullptr); - - // https://tc39.github.io/ecma262/#sec-iteratorclose - void IteratorClose(Node* context, Node* iterator, - Label* if_exception = nullptr, - Variable* exception = nullptr); - // Returns a node that contains a decoded (unsigned!) value of a bit // field |T| in |word32|. Returns result as an uint32 node. template diff --git a/src/contexts.h b/src/contexts.h index 401ecf61ee..8377139edd 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -320,8 +320,6 @@ enum ContextLookupFlags { promise_value_thunk_finally_shared_fun) \ V(PROMISE_THROWER_FINALLY_SHARED_FUN, SharedFunctionInfo, \ promise_thrower_finally_shared_fun) \ - V(PROMISE_ALL_RESOLVE_ELEMENT_SHARED_FUN, SharedFunctionInfo, \ - promise_all_resolve_element_shared_fun) \ V(PROMISE_PROTOTYPE_MAP_INDEX, Map, promise_prototype_map) \ V(REGEXP_EXEC_FUNCTION_INDEX, JSFunction, regexp_exec_function) \ V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \ diff --git a/src/js/promise.js b/src/js/promise.js index 53167a7406..27571daabb 100644 --- a/src/js/promise.js +++ b/src/js/promise.js @@ -23,6 +23,70 @@ var GlobalPromise = global.Promise; // Combinators. +// ES#sec-promise.all +// Promise.all ( iterable ) +function PromiseAll(iterable) { + if (!IS_RECEIVER(this)) { + throw %make_type_error(kCalledOnNonObject, "Promise.all"); + } + + // false debugEvent so that forwarding the rejection through all does not + // trigger redundant ExceptionEvents + var deferred = %new_promise_capability(this, false); + var resolutions = new InternalArray(); + var count; + + // For catch prediction, don't treat the .then calls as handling it; + // instead, recurse outwards. + var instrumenting = DEBUG_IS_ACTIVE; + if (instrumenting) { + SET_PRIVATE(deferred.reject, promiseForwardingHandlerSymbol, true); + } + + function CreateResolveElementFunction(index, values, promiseCapability) { + var alreadyCalled = false; + return (x) => { + if (alreadyCalled === true) return; + alreadyCalled = true; + values[index] = x; + if (--count === 0) { + var valuesArray = []; + %MoveArrayContents(values, valuesArray); + %_Call(promiseCapability.resolve, UNDEFINED, valuesArray); + } + }; + } + + try { + var i = 0; + count = 1; + for (var value of iterable) { + var nextPromise = this.resolve(value); + ++count; + var throwawayPromise = nextPromise.then( + CreateResolveElementFunction(i, resolutions, deferred), + deferred.reject); + // For catch prediction, mark that rejections here are semantically + // handled by the combined Promise. + if (instrumenting && %is_promise(throwawayPromise)) { + SET_PRIVATE(throwawayPromise, promiseHandledBySymbol, deferred.promise); + } + ++i; + } + + // 6.d + if (--count === 0) { + var valuesArray = []; + %MoveArrayContents(resolutions, valuesArray); + %_Call(deferred.resolve, UNDEFINED, valuesArray); + } + + } catch (e) { + %_Call(deferred.reject, UNDEFINED, e); + } + return deferred.promise; +} + // ES#sec-promise.race // Promise.race ( iterable ) function PromiseRace(iterable) { @@ -61,6 +125,7 @@ function PromiseRace(iterable) { // Install exported functions. utils.InstallFunctions(GlobalPromise, DONT_ENUM, [ + "all", PromiseAll, "race", PromiseRace, ]);