summaryrefslogtreecommitdiff
path: root/chromium/v8/src/builtins/builtins-async-gen.cc
blob: 073c96a2e0994878653dc82386455cc7d0e9af26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Copyright 2016 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-async-gen.h"

#include "src/builtins/builtins-utils-gen.h"
#include "src/heap/factory-inl.h"
#include "src/objects/shared-function-info.h"

namespace v8 {
namespace internal {

using compiler::Node;

void AsyncBuiltinsAssembler::Await(Node* context, Node* generator, Node* value,
                                   Node* outer_promise,
                                   Builtins::Name fulfill_builtin,
                                   Builtins::Name reject_builtin,
                                   Node* is_predicted_as_caught) {
  CSA_SLOW_ASSERT(this, Word32Or(IsJSAsyncGeneratorObject(generator),
                                 IsJSGeneratorObject(generator)));
  CSA_SLOW_ASSERT(this, IsJSPromise(outer_promise));
  CSA_SLOW_ASSERT(this, IsBoolean(is_predicted_as_caught));

  Node* const native_context = LoadNativeContext(context);

  // TODO(bmeurer): This could be optimized and folded into a single allocation.
  Node* const promise = AllocateAndInitJSPromise(native_context);
  Node* const promise_reactions =
      LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
  Node* const fulfill_handler =
      HeapConstant(Builtins::CallableFor(isolate(), fulfill_builtin).code());
  Node* const reject_handler =
      HeapConstant(Builtins::CallableFor(isolate(), reject_builtin).code());
  Node* const reaction = AllocatePromiseReaction(
      promise_reactions, generator, fulfill_handler, reject_handler);
  StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, reaction);
  PromiseSetHasHandler(promise);

  // Perform ! Call(promiseCapability.[[Resolve]], undefined, « value »).
  CallBuiltin(Builtins::kResolvePromise, native_context, promise, value);

  // When debugging, we need to link from the {generator} to the
  // {outer_promise} of the async function/generator.
  Label done(this);
  GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &done);
  CallRuntime(Runtime::kSetProperty, native_context, generator,
              LoadRoot(Heap::kgenerator_outer_promise_symbolRootIndex),
              outer_promise, SmiConstant(LanguageMode::kStrict));
  GotoIf(IsFalse(is_predicted_as_caught), &done);
  GotoIf(TaggedIsSmi(value), &done);
  GotoIfNot(IsJSPromise(value), &done);
  PromiseSetHandledHint(value);
  Goto(&done);
  BIND(&done);
}

void AsyncBuiltinsAssembler::Await(Node* context, Node* generator, Node* value,
                                   Node* outer_promise,
                                   Builtins::Name fulfill_builtin,
                                   Builtins::Name reject_builtin,
                                   bool is_predicted_as_caught) {
  return Await(context, generator, value, outer_promise, fulfill_builtin,
               reject_builtin, BooleanConstant(is_predicted_as_caught));
}

namespace {
// Describe fields of Context associated with the AsyncIterator unwrap closure.
class ValueUnwrapContext {
 public:
  enum Fields { kDoneSlot = Context::MIN_CONTEXT_SLOTS, kLength };
};

}  // namespace

Node* AsyncBuiltinsAssembler::CreateUnwrapClosure(Node* native_context,
                                                  Node* done) {
  Node* const map = LoadContextElement(
      native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
  Node* const on_fulfilled_shared = LoadContextElement(
      native_context, Context::ASYNC_ITERATOR_VALUE_UNWRAP_SHARED_FUN);
  CSA_ASSERT(this,
             HasInstanceType(on_fulfilled_shared, SHARED_FUNCTION_INFO_TYPE));
  Node* const closure_context =
      AllocateAsyncIteratorValueUnwrapContext(native_context, done);
  return AllocateFunctionWithMapAndContext(map, on_fulfilled_shared,
                                           closure_context);
}

Node* AsyncBuiltinsAssembler::AllocateAsyncIteratorValueUnwrapContext(
    Node* native_context, Node* done) {
  CSA_ASSERT(this, IsNativeContext(native_context));
  CSA_ASSERT(this, IsBoolean(done));

  Node* const context =
      CreatePromiseContext(native_context, ValueUnwrapContext::kLength);
  StoreContextElementNoWriteBarrier(context, ValueUnwrapContext::kDoneSlot,
                                    done);
  return context;
}

TF_BUILTIN(AsyncIteratorValueUnwrap, AsyncBuiltinsAssembler) {
  Node* const value = Parameter(Descriptor::kValue);
  Node* const context = Parameter(Descriptor::kContext);

  Node* const done = LoadContextElement(context, ValueUnwrapContext::kDoneSlot);
  CSA_ASSERT(this, IsBoolean(done));

  Node* const unwrapped_value =
      CallBuiltin(Builtins::kCreateIterResultObject, context, value, done);

  Return(unwrapped_value);
}

}  // namespace internal
}  // namespace v8