OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 #include "src/runtime/runtime-utils.h" | 4 #include "src/runtime/runtime-utils.h" |
5 | 5 |
6 #include "src/debug/debug.h" | 6 #include "src/debug/debug.h" |
7 #include "src/elements.h" | 7 #include "src/elements.h" |
8 #include "src/promise-utils.h" | 8 #include "src/promise-utils.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 HandleScope scope(isolate); | 53 HandleScope scope(isolate); |
54 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); | 54 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); |
55 // At this point, no revocation has been issued before | 55 // At this point, no revocation has been issued before |
56 CHECK(!promise->has_handler()); | 56 CHECK(!promise->has_handler()); |
57 isolate->ReportPromiseReject(promise, Handle<Object>(), | 57 isolate->ReportPromiseReject(promise, Handle<Object>(), |
58 v8::kPromiseHandlerAddedAfterReject); | 58 v8::kPromiseHandlerAddedAfterReject); |
59 return isolate->heap()->undefined_value(); | 59 return isolate->heap()->undefined_value(); |
60 } | 60 } |
61 | 61 |
62 namespace { | 62 namespace { |
| 63 |
| 64 // In an async function, reuse the existing stack related to the outer |
| 65 // Promise. Otherwise, e.g. in a direct call to then, save a new stack. |
| 66 // Promises with multiple reactions with one or more of them being async |
| 67 // functions will not get a good stack trace, as async functions require |
| 68 // different stacks from direct Promise use, but we save and restore a |
| 69 // stack once for all reactions. |
| 70 // |
| 71 // If this isn't a case of async function, we return false, otherwise |
| 72 // we set the correct id and return true. |
| 73 // |
| 74 // TODO(littledan): Improve this case. |
| 75 bool GetDebugIdForAsyncFunction(Isolate* isolate, |
| 76 Handle<PromiseReactionJobInfo> info, |
| 77 int* debug_id) { |
| 78 // deferred_promise can be Undefined, FixedArray or userland promise object. |
| 79 if (!info->deferred_promise()->IsJSPromise()) { |
| 80 return false; |
| 81 } |
| 82 |
| 83 Handle<JSPromise> deferred_promise(JSPromise::cast(info->deferred_promise()), |
| 84 isolate); |
| 85 Handle<Symbol> handled_by_symbol = |
| 86 isolate->factory()->promise_handled_by_symbol(); |
| 87 Handle<Object> handled_by_promise = |
| 88 JSObject::GetDataProperty(deferred_promise, handled_by_symbol); |
| 89 |
| 90 if (!handled_by_promise->IsJSPromise()) { |
| 91 return false; |
| 92 } |
| 93 |
| 94 Handle<JSPromise> handled_by_promise_js = |
| 95 Handle<JSPromise>::cast(handled_by_promise); |
| 96 Handle<Symbol> async_stack_id_symbol = |
| 97 isolate->factory()->promise_async_stack_id_symbol(); |
| 98 Handle<Object> id = |
| 99 JSObject::GetDataProperty(handled_by_promise_js, async_stack_id_symbol); |
| 100 |
| 101 // id can be Undefined or Smi. |
| 102 if (!id->IsSmi()) { |
| 103 return false; |
| 104 } |
| 105 |
| 106 *debug_id = Handle<Smi>::cast(id)->value(); |
| 107 return true; |
| 108 } |
| 109 |
| 110 void SetDebugInfo(Isolate* isolate, Handle<PromiseReactionJobInfo> info, |
| 111 int status) { |
| 112 int id; |
| 113 PromiseDebugActionName name; |
| 114 |
| 115 if (GetDebugIdForAsyncFunction(isolate, info, &id)) { |
| 116 name = kDebugAsyncFunction; |
| 117 } else { |
| 118 id = isolate->GetNextDebugMicrotaskId(); |
| 119 |
| 120 DCHECK(status != v8::Promise::kPending); |
| 121 name = status == v8::Promise::kFulfilled ? kDebugPromiseResolve |
| 122 : kDebugPromiseReject; |
| 123 |
| 124 isolate->debug()->OnAsyncTaskEvent(kDebugEnqueue, id, name); |
| 125 } |
| 126 |
| 127 info->set_debug_id(id); |
| 128 info->set_debug_name(name); |
| 129 } |
| 130 |
63 void EnqueuePromiseReactionJob(Isolate* isolate, | 131 void EnqueuePromiseReactionJob(Isolate* isolate, |
64 Handle<PromiseReactionJobInfo> info, | 132 Handle<PromiseReactionJobInfo> info, |
65 Handle<Object> status) { | 133 int status) { |
66 if (isolate->debug()->is_active()) { | 134 if (isolate->debug()->is_active()) { |
67 MaybeHandle<Object> maybe_result; | 135 SetDebugInfo(isolate, info, status); |
68 Handle<Object> deferred_obj(info->deferred_promise(), isolate); | 136 } |
69 | 137 |
70 if (info->deferred_promise()->IsFixedArray()) { | |
71 deferred_obj = isolate->factory()->undefined_value(); | |
72 } | |
73 | |
74 Handle<Object> argv[] = {deferred_obj, status}; | |
75 maybe_result = Execution::TryCall( | |
76 isolate, isolate->promise_debug_get_info(), | |
77 isolate->factory()->undefined_value(), arraysize(argv), argv); | |
78 | |
79 Handle<Object> result; | |
80 if ((maybe_result).ToHandle(&result)) { | |
81 CHECK(result->IsJSArray()); | |
82 Handle<JSArray> array = Handle<JSArray>::cast(result); | |
83 ElementsAccessor* accessor = array->GetElementsAccessor(); | |
84 DCHECK(accessor->HasElement(array, 0)); | |
85 DCHECK(accessor->HasElement(array, 1)); | |
86 info->set_debug_id(*accessor->Get(array, 0)); | |
87 info->set_debug_name(*accessor->Get(array, 1)); | |
88 } | |
89 } | |
90 isolate->EnqueueMicrotask(info); | 138 isolate->EnqueueMicrotask(info); |
91 } | 139 } |
92 | 140 |
93 void PromiseSet(Isolate* isolate, Handle<JSPromise> promise, int status, | 141 void PromiseSet(Isolate* isolate, Handle<JSPromise> promise, int status, |
94 Handle<Object> result) { | 142 Handle<Object> result) { |
95 promise->set_status(status); | 143 promise->set_status(status); |
96 promise->set_result(*result); | 144 promise->set_result(*result); |
97 promise->set_deferred_promise(isolate->heap()->undefined_value()); | 145 promise->set_deferred_promise(isolate->heap()->undefined_value()); |
98 promise->set_deferred_on_resolve(isolate->heap()->undefined_value()); | 146 promise->set_deferred_on_resolve(isolate->heap()->undefined_value()); |
99 promise->set_deferred_on_reject(isolate->heap()->undefined_value()); | 147 promise->set_deferred_on_reject(isolate->heap()->undefined_value()); |
100 promise->set_fulfill_reactions(isolate->heap()->undefined_value()); | 148 promise->set_fulfill_reactions(isolate->heap()->undefined_value()); |
101 promise->set_reject_reactions(isolate->heap()->undefined_value()); | 149 promise->set_reject_reactions(isolate->heap()->undefined_value()); |
102 } | 150 } |
103 | 151 |
104 void PromiseFulfill(Isolate* isolate, Handle<JSPromise> promise, | 152 void PromiseFulfill(Isolate* isolate, Handle<JSPromise> promise, int status, |
105 Handle<Smi> status, Handle<Object> value) { | 153 Handle<Object> value) { |
106 // Check if there are any callbacks. | 154 // Check if there are any callbacks. |
107 if (!promise->deferred_promise()->IsUndefined(isolate)) { | 155 if (!promise->deferred_promise()->IsUndefined(isolate)) { |
108 Handle<Object> tasks((status->value() == v8::Promise::kFulfilled) | 156 Handle<Object> tasks((status == v8::Promise::kFulfilled) |
109 ? promise->fulfill_reactions() | 157 ? promise->fulfill_reactions() |
110 : promise->reject_reactions(), | 158 : promise->reject_reactions(), |
111 isolate); | 159 isolate); |
112 Handle<PromiseReactionJobInfo> info = | 160 Handle<PromiseReactionJobInfo> info = |
113 isolate->factory()->NewPromiseReactionJobInfo( | 161 isolate->factory()->NewPromiseReactionJobInfo( |
114 promise, value, tasks, handle(promise->deferred_promise(), isolate), | 162 promise, value, tasks, handle(promise->deferred_promise(), isolate), |
115 handle(promise->deferred_on_resolve(), isolate), | 163 handle(promise->deferred_on_resolve(), isolate), |
116 handle(promise->deferred_on_reject(), isolate), | 164 handle(promise->deferred_on_reject(), isolate), |
117 isolate->native_context()); | 165 isolate->native_context()); |
118 EnqueuePromiseReactionJob(isolate, info, status); | 166 EnqueuePromiseReactionJob(isolate, info, status); |
119 } | 167 } |
120 | 168 |
121 PromiseSet(isolate, promise, status->value(), value); | 169 PromiseSet(isolate, promise, status, value); |
122 } | 170 } |
123 | 171 |
124 } // namespace | 172 } // namespace |
125 | 173 |
126 RUNTIME_FUNCTION(Runtime_PromiseReject) { | 174 RUNTIME_FUNCTION(Runtime_PromiseReject) { |
127 DCHECK(args.length() == 3); | 175 DCHECK(args.length() == 3); |
128 HandleScope scope(isolate); | 176 HandleScope scope(isolate); |
129 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); | 177 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); |
130 CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1); | 178 CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1); |
131 CONVERT_BOOLEAN_ARG_CHECKED(debug_event, 2); | 179 CONVERT_BOOLEAN_ARG_CHECKED(debug_event, 2); |
132 | 180 |
133 PromiseRejectEvent(isolate, promise, promise, reason, debug_event); | 181 PromiseRejectEvent(isolate, promise, promise, reason, debug_event); |
| 182 PromiseFulfill(isolate, promise, v8::Promise::kRejected, reason); |
134 | 183 |
135 Handle<Smi> status(Smi::FromInt(v8::Promise::kRejected), isolate); | |
136 PromiseFulfill(isolate, promise, status, reason); | |
137 return isolate->heap()->undefined_value(); | 184 return isolate->heap()->undefined_value(); |
138 } | 185 } |
139 | 186 |
140 RUNTIME_FUNCTION(Runtime_PromiseFulfill) { | 187 RUNTIME_FUNCTION(Runtime_PromiseFulfill) { |
141 DCHECK(args.length() == 3); | 188 DCHECK(args.length() == 3); |
142 HandleScope scope(isolate); | 189 HandleScope scope(isolate); |
143 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); | 190 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); |
144 CONVERT_ARG_HANDLE_CHECKED(Smi, status, 1); | 191 CONVERT_SMI_ARG_CHECKED(status, 1); |
145 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | 192 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); |
146 PromiseFulfill(isolate, promise, status, value); | 193 PromiseFulfill(isolate, promise, status, value); |
147 return isolate->heap()->undefined_value(); | 194 return isolate->heap()->undefined_value(); |
148 } | 195 } |
149 | 196 |
150 RUNTIME_FUNCTION(Runtime_EnqueuePromiseReactionJob) { | 197 RUNTIME_FUNCTION(Runtime_EnqueuePromiseReactionJob) { |
151 HandleScope scope(isolate); | 198 HandleScope scope(isolate); |
152 DCHECK(args.length() == 2); | 199 DCHECK(args.length() == 2); |
153 CONVERT_ARG_HANDLE_CHECKED(PromiseReactionJobInfo, info, 0); | 200 CONVERT_ARG_HANDLE_CHECKED(PromiseReactionJobInfo, info, 0); |
154 CONVERT_ARG_HANDLE_CHECKED(Object, status, 1); | 201 CONVERT_SMI_ARG_CHECKED(status, 1); |
155 EnqueuePromiseReactionJob(isolate, info, status); | 202 EnqueuePromiseReactionJob(isolate, info, status); |
156 return isolate->heap()->undefined_value(); | 203 return isolate->heap()->undefined_value(); |
157 } | 204 } |
158 | 205 |
159 RUNTIME_FUNCTION(Runtime_EnqueuePromiseResolveThenableJob) { | 206 RUNTIME_FUNCTION(Runtime_EnqueuePromiseResolveThenableJob) { |
160 HandleScope scope(isolate); | 207 HandleScope scope(isolate); |
161 DCHECK(args.length() == 3); | 208 DCHECK(args.length() == 3); |
162 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); | 209 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); |
163 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, resolution, 1); | 210 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, resolution, 1); |
164 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, then, 2); | 211 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, then, 2); |
165 | 212 |
166 // TODO(gsathya): Add fast path for native promises with unmodified | 213 // TODO(gsathya): Add fast path for native promises with unmodified |
167 // PromiseThen (which don't need these resolving functions, but | 214 // PromiseThen (which don't need these resolving functions, but |
168 // instead can just call resolve/reject directly). | 215 // instead can just call resolve/reject directly). |
169 Handle<JSFunction> resolve, reject; | 216 Handle<JSFunction> resolve, reject; |
170 PromiseUtils::CreateResolvingFunctions( | 217 PromiseUtils::CreateResolvingFunctions( |
171 isolate, promise, isolate->factory()->false_value(), &resolve, &reject); | 218 isolate, promise, isolate->factory()->false_value(), &resolve, &reject); |
172 | 219 |
173 Handle<Object> debug_id, debug_name; | 220 int debug_id = kDebugPromiseFirstID; |
| 221 PromiseDebugActionName debug_name = kDebugNotActive; |
174 if (isolate->debug()->is_active()) { | 222 if (isolate->debug()->is_active()) { |
175 debug_id = | 223 debug_id = isolate->GetNextDebugMicrotaskId(); |
176 handle(Smi::FromInt(isolate->GetNextDebugMicrotaskId()), isolate); | 224 debug_name = kDebugPromiseResolveThenableJob; |
177 debug_name = isolate->factory()->PromiseResolveThenableJob_string(); | 225 isolate->debug()->OnAsyncTaskEvent(kDebugEnqueue, debug_id, debug_name); |
178 isolate->debug()->OnAsyncTaskEvent(isolate->factory()->enqueue_string(), | |
179 debug_id, | |
180 Handle<String>::cast(debug_name)); | |
181 } else { | |
182 debug_id = isolate->factory()->undefined_value(); | |
183 debug_name = isolate->factory()->undefined_value(); | |
184 } | 226 } |
185 | 227 |
186 Handle<PromiseResolveThenableJobInfo> info = | 228 Handle<PromiseResolveThenableJobInfo> info = |
187 isolate->factory()->NewPromiseResolveThenableJobInfo( | 229 isolate->factory()->NewPromiseResolveThenableJobInfo( |
188 resolution, then, resolve, reject, debug_id, debug_name, | 230 resolution, then, resolve, reject, debug_id, debug_name, |
189 isolate->native_context()); | 231 isolate->native_context()); |
190 isolate->EnqueueMicrotask(info); | 232 isolate->EnqueueMicrotask(info); |
191 | 233 |
192 return isolate->heap()->undefined_value(); | 234 return isolate->heap()->undefined_value(); |
193 } | 235 } |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 HandleScope scope(isolate); | 367 HandleScope scope(isolate); |
326 DCHECK_EQ(1, args.length()); | 368 DCHECK_EQ(1, args.length()); |
327 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); | 369 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); |
328 isolate->RunPromiseHook(PromiseHookType::kAfter, promise, | 370 isolate->RunPromiseHook(PromiseHookType::kAfter, promise, |
329 isolate->factory()->undefined_value()); | 371 isolate->factory()->undefined_value()); |
330 return isolate->heap()->undefined_value(); | 372 return isolate->heap()->undefined_value(); |
331 } | 373 } |
332 | 374 |
333 } // namespace internal | 375 } // namespace internal |
334 } // namespace v8 | 376 } // namespace v8 |
OLD | NEW |