Chromium Code Reviews| 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 void PromiseFulfillDebugInfo(Isolate* isolate, | |
|
adamk
2016/12/30 00:10:04
This doesn't "fulfill" anything...should this be c
gsathya
2016/12/30 01:48:51
Done.
| |
| 65 Handle<PromiseReactionJobInfo> info, int status) { | |
| 66 int id = isolate->GetNextDebugMicrotaskId(); | |
| 67 DCHECK(status != v8::Promise::kPending); | |
| 68 PromiseDebugActionName name = status == v8::Promise::kFulfilled | |
| 69 ? DEBUG_PROMISE_RESOLVE | |
| 70 : DEBUG_PROMISE_REJECT; | |
| 71 | |
| 72 isolate->debug()->OnAsyncTaskEvent(DEBUG_ENQUEUE, id, name); | |
| 73 info->set_debug_id(id); | |
| 74 info->set_debug_name(name); | |
| 75 } | |
| 76 | |
| 77 // In an async function, reuse the existing stack related to the outer | |
| 78 // Promise. Otherwise, e.g. in a direct call to then, save a new stack. | |
| 79 // Promises with multiple reactions with one or more of them being async | |
| 80 // functions will not get a good stack trace, as async functions require | |
| 81 // different stacks from direct Promise use, but we save and restore a | |
| 82 // stack once for all reactions. | |
| 83 // | |
| 84 // If this isn't a case of async function, then we fall back to normal | |
| 85 // promise resolution debug events. | |
| 86 // | |
| 87 // TODO(littledan): Improve this case. | |
| 88 void AsyncFunctionDebugInfo(Isolate* isolate, | |
|
adamk
2016/12/30 00:10:04
This function name reads oddly to me, it seems to
gsathya
2016/12/30 01:48:51
Done.
| |
| 89 Handle<PromiseReactionJobInfo> info, int status) { | |
| 90 // deferred_promise can be Undefined, FixedArray or userland promise object. | |
| 91 if (!info->deferred_promise()->IsJSPromise()) { | |
| 92 PromiseFulfillDebugInfo(isolate, info, status); | |
| 93 return; | |
|
adamk
2016/12/30 00:10:04
I think it would be clearer to factor these multip
gsathya
2016/12/30 01:48:51
Done.
| |
| 94 } | |
| 95 | |
| 96 Handle<JSPromise> deferred_promise(JSPromise::cast(info->deferred_promise()), | |
| 97 isolate); | |
| 98 Handle<Symbol> handled_by_symbol = | |
| 99 isolate->factory()->promise_handled_by_symbol(); | |
| 100 Handle<Object> handled_by_promise = | |
| 101 JSObject::GetDataProperty(deferred_promise, handled_by_symbol); | |
| 102 | |
| 103 if (!handled_by_promise->IsJSPromise()) { | |
| 104 PromiseFulfillDebugInfo(isolate, info, status); | |
| 105 return; | |
| 106 } | |
| 107 | |
| 108 Handle<JSPromise> handled_by_promise_js = | |
| 109 Handle<JSPromise>::cast(handled_by_promise); | |
| 110 Handle<Symbol> async_stack_id_symbol = | |
| 111 isolate->factory()->promise_async_stack_id_symbol(); | |
| 112 Handle<Object> id = | |
| 113 JSObject::GetDataProperty(handled_by_promise_js, async_stack_id_symbol); | |
| 114 | |
| 115 // id can be Undefined or Smi. | |
| 116 if (!id->IsSmi()) { | |
| 117 PromiseFulfillDebugInfo(isolate, info, status); | |
| 118 return; | |
| 119 } | |
| 120 | |
| 121 info->set_debug_id(Handle<Smi>::cast(id)->value()); | |
| 122 info->set_debug_name(DEBUG_ASYNC_FUNCTION); | |
| 123 } | |
| 124 | |
| 63 void EnqueuePromiseReactionJob(Isolate* isolate, | 125 void EnqueuePromiseReactionJob(Isolate* isolate, |
| 64 Handle<PromiseReactionJobInfo> info, | 126 Handle<PromiseReactionJobInfo> info, |
| 65 Handle<Object> status) { | 127 int status) { |
| 66 if (isolate->debug()->is_active()) { | 128 if (isolate->debug()->is_active()) { |
| 67 MaybeHandle<Object> maybe_result; | 129 AsyncFunctionDebugInfo(isolate, info, status); |
| 68 Handle<Object> deferred_obj(info->deferred_promise(), isolate); | 130 } |
| 69 | 131 |
| 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); | 132 isolate->EnqueueMicrotask(info); |
| 91 } | 133 } |
| 92 | 134 |
| 93 void PromiseSet(Isolate* isolate, Handle<JSPromise> promise, int status, | 135 void PromiseSet(Isolate* isolate, Handle<JSPromise> promise, int status, |
| 94 Handle<Object> result) { | 136 Handle<Object> result) { |
| 95 promise->set_status(status); | 137 promise->set_status(status); |
| 96 promise->set_result(*result); | 138 promise->set_result(*result); |
| 97 promise->set_deferred_promise(isolate->heap()->undefined_value()); | 139 promise->set_deferred_promise(isolate->heap()->undefined_value()); |
| 98 promise->set_deferred_on_resolve(isolate->heap()->undefined_value()); | 140 promise->set_deferred_on_resolve(isolate->heap()->undefined_value()); |
| 99 promise->set_deferred_on_reject(isolate->heap()->undefined_value()); | 141 promise->set_deferred_on_reject(isolate->heap()->undefined_value()); |
| 100 promise->set_fulfill_reactions(isolate->heap()->undefined_value()); | 142 promise->set_fulfill_reactions(isolate->heap()->undefined_value()); |
| 101 promise->set_reject_reactions(isolate->heap()->undefined_value()); | 143 promise->set_reject_reactions(isolate->heap()->undefined_value()); |
| 102 } | 144 } |
| 103 | 145 |
| 104 void PromiseFulfill(Isolate* isolate, Handle<JSPromise> promise, | 146 void PromiseFulfill(Isolate* isolate, Handle<JSPromise> promise, int status, |
| 105 Handle<Smi> status, Handle<Object> value) { | 147 Handle<Object> value) { |
| 106 // Check if there are any callbacks. | 148 // Check if there are any callbacks. |
| 107 if (!promise->deferred_promise()->IsUndefined(isolate)) { | 149 if (!promise->deferred_promise()->IsUndefined(isolate)) { |
| 108 Handle<Object> tasks((status->value() == v8::Promise::kFulfilled) | 150 Handle<Object> tasks((status == v8::Promise::kFulfilled) |
| 109 ? promise->fulfill_reactions() | 151 ? promise->fulfill_reactions() |
| 110 : promise->reject_reactions(), | 152 : promise->reject_reactions(), |
| 111 isolate); | 153 isolate); |
| 112 Handle<PromiseReactionJobInfo> info = | 154 Handle<PromiseReactionJobInfo> info = |
| 113 isolate->factory()->NewPromiseReactionJobInfo( | 155 isolate->factory()->NewPromiseReactionJobInfo( |
| 114 promise, value, tasks, handle(promise->deferred_promise(), isolate), | 156 promise, value, tasks, handle(promise->deferred_promise(), isolate), |
| 115 handle(promise->deferred_on_resolve(), isolate), | 157 handle(promise->deferred_on_resolve(), isolate), |
| 116 handle(promise->deferred_on_reject(), isolate), | 158 handle(promise->deferred_on_reject(), isolate), |
| 117 isolate->native_context()); | 159 isolate->native_context()); |
| 118 EnqueuePromiseReactionJob(isolate, info, status); | 160 EnqueuePromiseReactionJob(isolate, info, status); |
| 119 } | 161 } |
| 120 | 162 |
| 121 PromiseSet(isolate, promise, status->value(), value); | 163 PromiseSet(isolate, promise, status, value); |
| 122 } | 164 } |
| 123 | 165 |
| 124 } // namespace | 166 } // namespace |
| 125 | 167 |
| 126 RUNTIME_FUNCTION(Runtime_PromiseReject) { | 168 RUNTIME_FUNCTION(Runtime_PromiseReject) { |
| 127 DCHECK(args.length() == 3); | 169 DCHECK(args.length() == 3); |
| 128 HandleScope scope(isolate); | 170 HandleScope scope(isolate); |
| 129 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); | 171 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); |
| 130 CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1); | 172 CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1); |
| 131 CONVERT_BOOLEAN_ARG_CHECKED(debug_event, 2); | 173 CONVERT_BOOLEAN_ARG_CHECKED(debug_event, 2); |
| 132 | 174 |
| 133 PromiseRejectEvent(isolate, promise, promise, reason, debug_event); | 175 PromiseRejectEvent(isolate, promise, promise, reason, debug_event); |
| 176 PromiseFulfill(isolate, promise, v8::Promise::kRejected, reason); | |
| 134 | 177 |
| 135 Handle<Smi> status(Smi::FromInt(v8::Promise::kRejected), isolate); | |
| 136 PromiseFulfill(isolate, promise, status, reason); | |
| 137 return isolate->heap()->undefined_value(); | 178 return isolate->heap()->undefined_value(); |
| 138 } | 179 } |
| 139 | 180 |
| 140 RUNTIME_FUNCTION(Runtime_PromiseFulfill) { | 181 RUNTIME_FUNCTION(Runtime_PromiseFulfill) { |
| 141 DCHECK(args.length() == 3); | 182 DCHECK(args.length() == 3); |
| 142 HandleScope scope(isolate); | 183 HandleScope scope(isolate); |
| 143 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); | 184 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); |
| 144 CONVERT_ARG_HANDLE_CHECKED(Smi, status, 1); | 185 CONVERT_SMI_ARG_CHECKED(status, 1); |
| 145 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | 186 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); |
| 146 PromiseFulfill(isolate, promise, status, value); | 187 PromiseFulfill(isolate, promise, status, value); |
| 147 return isolate->heap()->undefined_value(); | 188 return isolate->heap()->undefined_value(); |
| 148 } | 189 } |
| 149 | 190 |
| 150 RUNTIME_FUNCTION(Runtime_EnqueuePromiseReactionJob) { | 191 RUNTIME_FUNCTION(Runtime_EnqueuePromiseReactionJob) { |
| 151 HandleScope scope(isolate); | 192 HandleScope scope(isolate); |
| 152 DCHECK(args.length() == 2); | 193 DCHECK(args.length() == 2); |
| 153 CONVERT_ARG_HANDLE_CHECKED(PromiseReactionJobInfo, info, 0); | 194 CONVERT_ARG_HANDLE_CHECKED(PromiseReactionJobInfo, info, 0); |
| 154 CONVERT_ARG_HANDLE_CHECKED(Object, status, 1); | 195 CONVERT_SMI_ARG_CHECKED(status, 1); |
| 155 EnqueuePromiseReactionJob(isolate, info, status); | 196 EnqueuePromiseReactionJob(isolate, info, status); |
| 156 return isolate->heap()->undefined_value(); | 197 return isolate->heap()->undefined_value(); |
| 157 } | 198 } |
| 158 | 199 |
| 159 RUNTIME_FUNCTION(Runtime_EnqueuePromiseResolveThenableJob) { | 200 RUNTIME_FUNCTION(Runtime_EnqueuePromiseResolveThenableJob) { |
| 160 HandleScope scope(isolate); | 201 HandleScope scope(isolate); |
| 161 DCHECK(args.length() == 3); | 202 DCHECK(args.length() == 3); |
| 162 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); | 203 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); |
| 163 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, resolution, 1); | 204 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, resolution, 1); |
| 164 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, then, 2); | 205 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, then, 2); |
| 165 | 206 |
| 166 // TODO(gsathya): Add fast path for native promises with unmodified | 207 // TODO(gsathya): Add fast path for native promises with unmodified |
| 167 // PromiseThen (which don't need these resolving functions, but | 208 // PromiseThen (which don't need these resolving functions, but |
| 168 // instead can just call resolve/reject directly). | 209 // instead can just call resolve/reject directly). |
| 169 Handle<JSFunction> resolve, reject; | 210 Handle<JSFunction> resolve, reject; |
| 170 PromiseUtils::CreateResolvingFunctions( | 211 PromiseUtils::CreateResolvingFunctions( |
| 171 isolate, promise, isolate->factory()->false_value(), &resolve, &reject); | 212 isolate, promise, isolate->factory()->false_value(), &resolve, &reject); |
| 172 | 213 |
| 173 Handle<Object> debug_id, debug_name; | 214 int debug_id = 0; |
|
adamk
2016/12/30 00:10:04
Please define a constant somewhere for this 0, som
gsathya
2016/12/30 01:48:51
Done.
| |
| 215 PromiseDebugActionName debug_name = DEBUG_NOT_ACTIVE; | |
| 174 if (isolate->debug()->is_active()) { | 216 if (isolate->debug()->is_active()) { |
| 175 debug_id = | 217 debug_id = isolate->GetNextDebugMicrotaskId(); |
| 176 handle(Smi::FromInt(isolate->GetNextDebugMicrotaskId()), isolate); | 218 debug_name = DEBUG_PROMISE_RESOLVE_THENABLE_JOB; |
| 177 debug_name = isolate->factory()->PromiseResolveThenableJob_string(); | 219 isolate->debug()->OnAsyncTaskEvent(DEBUG_ENQUEUE, 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 } | 220 } |
| 185 | 221 |
| 186 Handle<PromiseResolveThenableJobInfo> info = | 222 Handle<PromiseResolveThenableJobInfo> info = |
| 187 isolate->factory()->NewPromiseResolveThenableJobInfo( | 223 isolate->factory()->NewPromiseResolveThenableJobInfo( |
| 188 resolution, then, resolve, reject, debug_id, debug_name, | 224 resolution, then, resolve, reject, debug_id, debug_name, |
| 189 isolate->native_context()); | 225 isolate->native_context()); |
| 190 isolate->EnqueueMicrotask(info); | 226 isolate->EnqueueMicrotask(info); |
| 191 | 227 |
| 192 return isolate->heap()->undefined_value(); | 228 return isolate->heap()->undefined_value(); |
| 193 } | 229 } |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 325 HandleScope scope(isolate); | 361 HandleScope scope(isolate); |
| 326 DCHECK_EQ(1, args.length()); | 362 DCHECK_EQ(1, args.length()); |
| 327 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); | 363 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); |
| 328 isolate->RunPromiseHook(PromiseHookType::kAfter, promise, | 364 isolate->RunPromiseHook(PromiseHookType::kAfter, promise, |
| 329 isolate->factory()->undefined_value()); | 365 isolate->factory()->undefined_value()); |
| 330 return isolate->heap()->undefined_value(); | 366 return isolate->heap()->undefined_value(); |
| 331 } | 367 } |
| 332 | 368 |
| 333 } // namespace internal | 369 } // namespace internal |
| 334 } // namespace v8 | 370 } // namespace v8 |
| OLD | NEW |