162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// Copyright 2017 the V8 project authors. All rights reserved.
262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// found in the LICENSE file.
462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/builtins/builtins-async.h"
662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/builtins/builtins-utils.h"
762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/builtins/builtins.h"
862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/code-factory.h"
962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/code-stub-assembler.h"
1062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/frames-inl.h"
1162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
1262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochnamespace v8 {
1362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochnamespace internal {
1462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
1562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochnamespace {
1662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
1762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// Describe fields of Context associated with the AsyncIterator unwrap closure.
1862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochclass ValueUnwrapContext {
1962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch public:
2062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  enum Fields { kDoneSlot = Context::MIN_CONTEXT_SLOTS, kLength };
2162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch};
2262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
2362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochclass AsyncFromSyncBuiltinsAssembler : public AsyncBuiltinsAssembler {
2462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch public:
2562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  explicit AsyncFromSyncBuiltinsAssembler(CodeAssemblerState* state)
2662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      : AsyncBuiltinsAssembler(state) {}
2762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
2862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  void ThrowIfNotAsyncFromSyncIterator(Node* const context, Node* const object,
2962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                       Label* if_exception,
3062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                       Variable* var_exception,
3162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                       const char* method_name);
3262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
3362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  typedef std::function<void(Node* const context, Node* const promise,
3462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                             Label* if_exception)>
3562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      UndefinedMethodHandler;
3662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  void Generate_AsyncFromSyncIteratorMethod(
3762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      Node* const context, Node* const iterator, Node* const sent_value,
3862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      Handle<Name> method_name, UndefinedMethodHandler&& if_method_undefined,
3962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      const char* operation_name,
4062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      Label::Type reject_label_type = Label::kDeferred,
4162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      Node* const initial_exception_value = nullptr);
4262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
4362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* AllocateAsyncIteratorValueUnwrapContext(Node* native_context,
4462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                                Node* done);
4562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
4662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Load "value" and "done" from an iterator result object. If an exception
4762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // is thrown at any point, jumps to te `if_exception` label with exception
4862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // stored in `var_exception`.
4962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  //
5062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Returns a Pair of Nodes, whose first element is the value of the "value"
5162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // property, and whose second element is the value of the "done" property,
5262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // converted to a Boolean if needed.
5362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  std::pair<Node*, Node*> LoadIteratorResult(Node* const context,
5462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                             Node* const native_context,
5562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                             Node* const iter_result,
5662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                             Label* if_exception,
5762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                             Variable* var_exception);
5862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
5962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* CreateUnwrapClosure(Node* const native_context, Node* const done);
6062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch};
6162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
6262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochvoid AsyncFromSyncBuiltinsAssembler::ThrowIfNotAsyncFromSyncIterator(
6362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Node* const context, Node* const object, Label* if_exception,
6462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Variable* var_exception, const char* method_name) {
6562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Label if_receiverisincompatible(this, Label::kDeferred), done(this);
6662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
6762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  GotoIf(TaggedIsSmi(object), &if_receiverisincompatible);
6862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Branch(HasInstanceType(object, JS_ASYNC_FROM_SYNC_ITERATOR_TYPE), &done,
6962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch         &if_receiverisincompatible);
7062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
7162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Bind(&if_receiverisincompatible);
7262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  {
7362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // If Type(O) is not Object, or if O does not have a [[SyncIterator]]
7462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // internal slot, then
7562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
7662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Let badIteratorError be a new TypeError exception.
7762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Node* const error =
7862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch        MakeTypeError(MessageTemplate::kIncompatibleMethodReceiver, context,
7962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                      CStringConstant(method_name), object);
8062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
8162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Perform ! Call(promiseCapability.[[Reject]], undefined,
8262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    //                « badIteratorError »).
8362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    var_exception->Bind(error);
8462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Goto(if_exception);
8562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  }
8662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
8762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Bind(&done);
8862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
8962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
9062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochvoid AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
9162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Node* const context, Node* const iterator, Node* const sent_value,
9262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Handle<Name> method_name, UndefinedMethodHandler&& if_method_undefined,
9362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    const char* operation_name, Label::Type reject_label_type,
9462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Node* const initial_exception_value) {
9562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const native_context = LoadNativeContext(context);
9662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const promise = AllocateAndInitJSPromise(context);
9762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
9862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Variable var_exception(this, MachineRepresentation::kTagged,
9962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                         initial_exception_value == nullptr
10062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                             ? UndefinedConstant()
10162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                             : initial_exception_value);
10262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Label reject_promise(this, reject_label_type);
10362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
10462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  ThrowIfNotAsyncFromSyncIterator(context, iterator, &reject_promise,
10562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                  &var_exception, operation_name);
10662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
10762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const sync_iterator =
10862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      LoadObjectField(iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset);
10962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
11062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const method = GetProperty(context, sync_iterator, method_name);
11162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
11262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  if (if_method_undefined) {
11362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Label if_isnotundefined(this);
11462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
11562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    GotoIfNot(IsUndefined(method), &if_isnotundefined);
11662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    if_method_undefined(native_context, promise, &reject_promise);
11762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
11862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Bind(&if_isnotundefined);
11962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  }
12062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
12162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const iter_result = CallJS(CodeFactory::Call(isolate()), context,
12262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                   method, sync_iterator, sent_value);
12362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  GotoIfException(iter_result, &reject_promise, &var_exception);
12462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
12562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* value;
12662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* done;
12762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  std::tie(value, done) = LoadIteratorResult(
12862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      context, native_context, iter_result, &reject_promise, &var_exception);
12962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const wrapper = AllocateAndInitJSPromise(context);
13062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
13162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Perform ! Call(valueWrapperCapability.[[Resolve]], undefined, «
13262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // throwValue »).
13362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  InternalResolvePromise(context, wrapper, value);
13462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
13562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Let onFulfilled be a new built-in function object as defined in
13662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Async Iterator Value Unwrap Functions.
13762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Set onFulfilled.[[Done]] to throwDone.
13862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const on_fulfilled = CreateUnwrapClosure(native_context, done);
13962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
14062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Perform ! PerformPromiseThen(valueWrapperCapability.[[Promise]],
14162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  //     onFulfilled, undefined, promiseCapability).
14262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const undefined = UndefinedConstant();
14362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  InternalPerformPromiseThen(context, wrapper, on_fulfilled, undefined, promise,
14462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                             undefined, undefined);
14562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Return(promise);
14662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
14762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Bind(&reject_promise);
14862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  {
14962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Node* const exception = var_exception.value();
15062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    InternalPromiseReject(context, promise, exception, TrueConstant());
15162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
15262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Return(promise);
15362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  }
15462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
15562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
15662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochstd::pair<Node*, Node*> AsyncFromSyncBuiltinsAssembler::LoadIteratorResult(
15762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Node* const context, Node* const native_context, Node* const iter_result,
15862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Label* if_exception, Variable* var_exception) {
15962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Label if_fastpath(this), if_slowpath(this), merge(this), to_boolean(this),
16062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      done(this), if_notanobject(this, Label::kDeferred);
16162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  GotoIf(TaggedIsSmi(iter_result), &if_notanobject);
16262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
16362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const iter_result_map = LoadMap(iter_result);
16462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  GotoIfNot(IsJSReceiverMap(iter_result_map), &if_notanobject);
16562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
16662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const fast_iter_result_map =
16762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
16862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
16962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Variable var_value(this, MachineRepresentation::kTagged);
17062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Variable var_done(this, MachineRepresentation::kTagged);
17162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Branch(WordEqual(iter_result_map, fast_iter_result_map), &if_fastpath,
17262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch         &if_slowpath);
17362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
17462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Bind(&if_fastpath);
17562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  {
17662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    var_value.Bind(
17762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch        LoadObjectField(iter_result, JSIteratorResult::kValueOffset));
17862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    var_done.Bind(LoadObjectField(iter_result, JSIteratorResult::kDoneOffset));
17962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Goto(&merge);
18062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  }
18162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
18262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Bind(&if_slowpath);
18362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  {
18462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Let nextValue be IteratorValue(nextResult).
18562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // IfAbruptRejectPromise(nextValue, promiseCapability).
18662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Node* const value =
18762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch        GetProperty(context, iter_result, factory()->value_string());
18862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    GotoIfException(value, if_exception, var_exception);
18962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
19062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Let nextDone be IteratorComplete(nextResult).
19162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // IfAbruptRejectPromise(nextDone, promiseCapability).
19262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Node* const done =
19362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch        GetProperty(context, iter_result, factory()->done_string());
19462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    GotoIfException(done, if_exception, var_exception);
19562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
19662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    var_value.Bind(value);
19762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    var_done.Bind(done);
19862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Goto(&merge);
19962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  }
20062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
20162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Bind(&if_notanobject);
20262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  {
20362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Sync iterator result is not an object --- Produce a TypeError and jump
20462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // to the `if_exception` path.
20562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Node* const error = MakeTypeError(
20662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch        MessageTemplate::kIteratorResultNotAnObject, context, iter_result);
20762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    var_exception->Bind(error);
20862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Goto(if_exception);
20962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  }
21062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
21162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Bind(&merge);
21262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // Ensure `iterResult.done` is a Boolean.
21362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  GotoIf(TaggedIsSmi(var_done.value()), &to_boolean);
21462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Branch(IsBoolean(var_done.value()), &done, &to_boolean);
21562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
21662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Bind(&to_boolean);
21762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  {
21862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Node* const result =
21962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch        CallStub(CodeFactory::ToBoolean(isolate()), context, var_done.value());
22062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    var_done.Bind(result);
22162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Goto(&done);
22262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  }
22362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
22462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Bind(&done);
22562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  return std::make_pair(var_value.value(), var_done.value());
22662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
22762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
22862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochNode* AsyncFromSyncBuiltinsAssembler::CreateUnwrapClosure(Node* native_context,
22962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                                          Node* done) {
23062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const map = LoadContextElement(
23162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
23262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const on_fulfilled_shared = LoadContextElement(
23362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      native_context, Context::ASYNC_ITERATOR_VALUE_UNWRAP_SHARED_FUN);
23462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  CSA_ASSERT(this,
23562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch             HasInstanceType(on_fulfilled_shared, SHARED_FUNCTION_INFO_TYPE));
23662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const closure_context =
23762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      AllocateAsyncIteratorValueUnwrapContext(native_context, done);
23862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  return AllocateFunctionWithMapAndContext(map, on_fulfilled_shared,
23962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                           closure_context);
24062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
24162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
24262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochNode* AsyncFromSyncBuiltinsAssembler::AllocateAsyncIteratorValueUnwrapContext(
24362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Node* native_context, Node* done) {
24462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  CSA_ASSERT(this, IsNativeContext(native_context));
24562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  CSA_ASSERT(this, IsBoolean(done));
24662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
24762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const context =
24862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      CreatePromiseContext(native_context, ValueUnwrapContext::kLength);
24962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  StoreContextElementNoWriteBarrier(context, ValueUnwrapContext::kDoneSlot,
25062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                    done);
25162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  return context;
25262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
25362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}  // namespace
25462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
25562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// https://tc39.github.io/proposal-async-iteration/
25662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// Section #sec-%asyncfromsynciteratorprototype%.next
25762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochTF_BUILTIN(AsyncFromSyncIteratorPrototypeNext, AsyncFromSyncBuiltinsAssembler) {
25862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const iterator = Parameter(0);
25962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const value = Parameter(1);
26062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const context = Parameter(4);
26162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
26262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Generate_AsyncFromSyncIteratorMethod(
26362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      context, iterator, value, factory()->next_string(),
26462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      UndefinedMethodHandler(), "[Async-from-Sync Iterator].prototype.next");
26562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
26662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
26762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// https://tc39.github.io/proposal-async-iteration/
26862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// Section #sec-%asyncfromsynciteratorprototype%.return
26962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochTF_BUILTIN(AsyncFromSyncIteratorPrototypeReturn,
27062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch           AsyncFromSyncBuiltinsAssembler) {
27162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const iterator = Parameter(0);
27262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const value = Parameter(1);
27362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const context = Parameter(4);
27462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
27562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  auto if_return_undefined = [=](Node* const native_context,
27662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                 Node* const promise, Label* if_exception) {
27762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // If return is undefined, then
27862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Let iterResult be ! CreateIterResultObject(value, true)
27962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Node* const iter_result =
28062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch        CallStub(CodeFactory::CreateIterResultObject(isolate()), context, value,
28162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                 TrueConstant());
28262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
28362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »).
28462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // IfAbruptRejectPromise(nextDone, promiseCapability).
28562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    // Return promiseCapability.[[Promise]].
28662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    PromiseFulfill(context, promise, iter_result, v8::Promise::kFulfilled);
28762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    Return(promise);
28862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  };
28962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
29062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Generate_AsyncFromSyncIteratorMethod(
29162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      context, iterator, value, factory()->return_string(), if_return_undefined,
29262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      "[Async-from-Sync Iterator].prototype.return");
29362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
29462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
29562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// https://tc39.github.io/proposal-async-iteration/
29662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch// Section #sec-%asyncfromsynciteratorprototype%.throw
29762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochTF_BUILTIN(AsyncFromSyncIteratorPrototypeThrow,
29862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch           AsyncFromSyncBuiltinsAssembler) {
29962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const iterator = Parameter(0);
30062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const reason = Parameter(1);
30162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const context = Parameter(4);
30262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
30362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  auto if_throw_undefined = [=](Node* const native_context, Node* const promise,
30462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                                Label* if_exception) { Goto(if_exception); };
30562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
30662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Generate_AsyncFromSyncIteratorMethod(
30762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      context, iterator, reason, factory()->throw_string(), if_throw_undefined,
30862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      "[Async-from-Sync Iterator].prototype.throw", Label::kNonDeferred,
30962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      reason);
31062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
31162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
31262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen MurdochTF_BUILTIN(AsyncIteratorValueUnwrap, AsyncFromSyncBuiltinsAssembler) {
31362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const value = Parameter(1);
31462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const context = Parameter(4);
31562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
31662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const done = LoadContextElement(context, ValueUnwrapContext::kDoneSlot);
31762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  CSA_ASSERT(this, IsBoolean(done));
31862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
31962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Node* const unwrapped_value = CallStub(
32062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      CodeFactory::CreateIterResultObject(isolate()), context, value, done);
32162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
32262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Return(unwrapped_value);
32362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
32462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
32562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}  // namespace internal
32662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}  // namespace v8
327