Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include "src/api-inl.h"
6 : #include "src/arguments-inl.h"
7 : #include "src/counters.h"
8 : #include "src/debug/debug.h"
9 : #include "src/elements.h"
10 : #include "src/microtask-queue.h"
11 : #include "src/objects-inl.h"
12 : #include "src/objects/heap-object-inl.h"
13 : #include "src/objects/js-promise-inl.h"
14 : #include "src/objects/oddball-inl.h"
15 : #include "src/runtime/runtime-utils.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 :
20 1688 : RUNTIME_FUNCTION(Runtime_PromiseRejectEventFromStack) {
21 : DCHECK_EQ(2, args.length());
22 : HandleScope scope(isolate);
23 844 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
24 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
25 :
26 : Handle<Object> rejected_promise = promise;
27 844 : if (isolate->debug()->is_active()) {
28 : // If the Promise.reject() call is caught, then this will return
29 : // undefined, which we interpret as being a caught exception event.
30 315 : rejected_promise = isolate->GetPromiseOnStackOnThrow();
31 : }
32 844 : isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
33 844 : isolate->factory()->undefined_value());
34 844 : isolate->debug()->OnPromiseReject(rejected_promise, value);
35 :
36 : // Report only if we don't actually have a handler.
37 844 : if (!promise->has_handler()) {
38 : isolate->ReportPromiseReject(promise, value,
39 844 : v8::kPromiseRejectWithNoHandler);
40 : }
41 : return ReadOnlyRoots(isolate).undefined_value();
42 : }
43 :
44 272 : RUNTIME_FUNCTION(Runtime_PromiseRejectAfterResolved) {
45 : DCHECK_EQ(2, args.length());
46 : HandleScope scope(isolate);
47 136 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
48 : CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1);
49 : isolate->ReportPromiseReject(promise, reason,
50 136 : v8::kPromiseRejectAfterResolved);
51 : return ReadOnlyRoots(isolate).undefined_value();
52 : }
53 :
54 2074 : RUNTIME_FUNCTION(Runtime_PromiseResolveAfterResolved) {
55 : DCHECK_EQ(2, args.length());
56 : HandleScope scope(isolate);
57 1037 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
58 : CONVERT_ARG_HANDLE_CHECKED(Object, resolution, 1);
59 : isolate->ReportPromiseReject(promise, resolution,
60 1037 : v8::kPromiseResolveAfterResolved);
61 : return ReadOnlyRoots(isolate).undefined_value();
62 : }
63 :
64 8882 : RUNTIME_FUNCTION(Runtime_PromiseRevokeReject) {
65 : DCHECK_EQ(1, args.length());
66 : HandleScope scope(isolate);
67 4441 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
68 : // At this point, no revocation has been issued before
69 4441 : CHECK(!promise->has_handler());
70 4441 : isolate->ReportPromiseReject(promise, Handle<Object>(),
71 4441 : v8::kPromiseHandlerAddedAfterReject);
72 : return ReadOnlyRoots(isolate).undefined_value();
73 : }
74 :
75 560 : RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) {
76 : HandleScope scope(isolate);
77 : DCHECK_EQ(1, args.length());
78 280 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
79 :
80 : Handle<CallableTask> microtask = isolate->factory()->NewCallableTask(
81 280 : function, handle(function->native_context(), isolate));
82 : MicrotaskQueue* microtask_queue =
83 : function->native_context()->microtask_queue();
84 559 : if (microtask_queue) microtask_queue->EnqueueMicrotask(*microtask);
85 : return ReadOnlyRoots(isolate).undefined_value();
86 : }
87 :
88 16072 : RUNTIME_FUNCTION(Runtime_PerformMicrotaskCheckpoint) {
89 : HandleScope scope(isolate);
90 : DCHECK_EQ(0, args.length());
91 8036 : MicrotasksScope::PerformCheckpoint(reinterpret_cast<v8::Isolate*>(isolate));
92 : return ReadOnlyRoots(isolate).undefined_value();
93 : }
94 :
95 916 : RUNTIME_FUNCTION(Runtime_RunMicrotaskCallback) {
96 : HandleScope scope(isolate);
97 : DCHECK_EQ(2, args.length());
98 : CONVERT_ARG_CHECKED(Object, microtask_callback, 0);
99 : CONVERT_ARG_CHECKED(Object, microtask_data, 1);
100 458 : MicrotaskCallback callback = ToCData<MicrotaskCallback>(microtask_callback);
101 458 : void* data = ToCData<void*>(microtask_data);
102 458 : callback(data);
103 458 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
104 : return ReadOnlyRoots(isolate).undefined_value();
105 : }
106 :
107 30 : RUNTIME_FUNCTION(Runtime_PromiseStatus) {
108 : HandleScope scope(isolate);
109 : DCHECK_EQ(1, args.length());
110 15 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
111 :
112 30 : return Smi::FromInt(promise->status());
113 : }
114 :
115 10 : RUNTIME_FUNCTION(Runtime_PromiseMarkAsHandled) {
116 : SealHandleScope shs(isolate);
117 : DCHECK_EQ(1, args.length());
118 10 : CONVERT_ARG_CHECKED(JSPromise, promise, 0);
119 :
120 5 : promise->set_has_handler(true);
121 : return ReadOnlyRoots(isolate).undefined_value();
122 : }
123 :
124 28092 : RUNTIME_FUNCTION(Runtime_PromiseHookInit) {
125 : HandleScope scope(isolate);
126 : DCHECK_EQ(2, args.length());
127 14046 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
128 : CONVERT_ARG_HANDLE_CHECKED(Object, parent, 1);
129 14046 : isolate->RunPromiseHook(PromiseHookType::kInit, promise, parent);
130 : return ReadOnlyRoots(isolate).undefined_value();
131 : }
132 :
133 : namespace {
134 :
135 4328 : Handle<JSPromise> AwaitPromisesInitCommon(Isolate* isolate,
136 : Handle<Object> value,
137 : Handle<JSPromise> promise,
138 : Handle<JSPromise> outer_promise,
139 : Handle<JSFunction> reject_handler,
140 : bool is_predicted_as_caught) {
141 : // Allocate the throwaway promise and fire the appropriate init
142 : // hook for the throwaway promise (passing the {promise} as its
143 : // parent).
144 4328 : Handle<JSPromise> throwaway = isolate->factory()->NewJSPromiseWithoutHook();
145 4328 : isolate->RunPromiseHook(PromiseHookType::kInit, throwaway, promise);
146 :
147 : // On inspector side we capture async stack trace and store it by
148 : // outer_promise->async_task_id when async function is suspended first time.
149 : // To use captured stack trace later throwaway promise should have the same
150 : // async_task_id as outer_promise since we generate WillHandle and DidHandle
151 : // events using throwaway promise.
152 8656 : throwaway->set_async_task_id(outer_promise->async_task_id());
153 :
154 : // The Promise will be thrown away and not handled, but it
155 : // shouldn't trigger unhandled reject events as its work is done
156 4328 : throwaway->set_has_handler(true);
157 :
158 : // Enable proper debug support for promises.
159 4328 : if (isolate->debug()->is_active()) {
160 4292 : if (value->IsJSPromise()) {
161 6194 : Object::SetProperty(
162 : isolate, reject_handler,
163 : isolate->factory()->promise_forwarding_handler_symbol(),
164 : isolate->factory()->true_value(), StoreOrigin::kMaybeKeyed,
165 3097 : Just(ShouldThrow::kThrowOnError))
166 : .Check();
167 6194 : Handle<JSPromise>::cast(value)->set_handled_hint(is_predicted_as_caught);
168 : }
169 :
170 : // Mark the dependency to {outer_promise} in case the {throwaway}
171 : // Promise is found on the Promise stack
172 8584 : Object::SetProperty(isolate, throwaway,
173 : isolate->factory()->promise_handled_by_symbol(),
174 : outer_promise, StoreOrigin::kMaybeKeyed,
175 4292 : Just(ShouldThrow::kThrowOnError))
176 : .Check();
177 : }
178 :
179 4328 : return throwaway;
180 : }
181 :
182 : } // namespace
183 :
184 6230 : RUNTIME_FUNCTION(Runtime_AwaitPromisesInit) {
185 : DCHECK_EQ(5, args.length());
186 : HandleScope scope(isolate);
187 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
188 3115 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 1);
189 3115 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, outer_promise, 2);
190 3115 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, reject_handler, 3);
191 3115 : CONVERT_BOOLEAN_ARG_CHECKED(is_predicted_as_caught, 4);
192 6230 : return *AwaitPromisesInitCommon(isolate, value, promise, outer_promise,
193 3115 : reject_handler, is_predicted_as_caught);
194 : }
195 :
196 2426 : RUNTIME_FUNCTION(Runtime_AwaitPromisesInitOld) {
197 : DCHECK_EQ(5, args.length());
198 : HandleScope scope(isolate);
199 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
200 1213 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 1);
201 1213 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, outer_promise, 2);
202 1213 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, reject_handler, 3);
203 1213 : CONVERT_BOOLEAN_ARG_CHECKED(is_predicted_as_caught, 4);
204 :
205 : // Fire the init hook for the wrapper promise (that we created for the
206 : // {value} previously).
207 1213 : isolate->RunPromiseHook(PromiseHookType::kInit, promise, outer_promise);
208 2426 : return *AwaitPromisesInitCommon(isolate, value, promise, outer_promise,
209 1213 : reject_handler, is_predicted_as_caught);
210 : }
211 :
212 22314 : RUNTIME_FUNCTION(Runtime_PromiseHookBefore) {
213 : HandleScope scope(isolate);
214 : DCHECK_EQ(1, args.length());
215 11157 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, maybe_promise, 0);
216 22314 : if (!maybe_promise->IsJSPromise())
217 : return ReadOnlyRoots(isolate).undefined_value();
218 11134 : Handle<JSPromise> promise = Handle<JSPromise>::cast(maybe_promise);
219 22092 : if (isolate->debug()->is_active()) isolate->PushPromise(promise);
220 22268 : if (promise->IsJSPromise()) {
221 11134 : isolate->RunPromiseHook(PromiseHookType::kBefore, promise,
222 11134 : isolate->factory()->undefined_value());
223 : }
224 : return ReadOnlyRoots(isolate).undefined_value();
225 : }
226 :
227 22274 : RUNTIME_FUNCTION(Runtime_PromiseHookAfter) {
228 : HandleScope scope(isolate);
229 : DCHECK_EQ(1, args.length());
230 11137 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, maybe_promise, 0);
231 22274 : if (!maybe_promise->IsJSPromise())
232 : return ReadOnlyRoots(isolate).undefined_value();
233 11114 : Handle<JSPromise> promise = Handle<JSPromise>::cast(maybe_promise);
234 11114 : if (isolate->debug()->is_active()) isolate->PopPromise();
235 22228 : if (promise->IsJSPromise()) {
236 11114 : isolate->RunPromiseHook(PromiseHookType::kAfter, promise,
237 11114 : isolate->factory()->undefined_value());
238 : }
239 : return ReadOnlyRoots(isolate).undefined_value();
240 : }
241 :
242 9764 : RUNTIME_FUNCTION(Runtime_RejectPromise) {
243 : HandleScope scope(isolate);
244 : DCHECK_EQ(3, args.length());
245 4882 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
246 : CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1);
247 4882 : CONVERT_ARG_HANDLE_CHECKED(Oddball, debug_event, 2);
248 9764 : return *JSPromise::Reject(promise, reason,
249 9764 : debug_event->BooleanValue(isolate));
250 : }
251 :
252 56116 : RUNTIME_FUNCTION(Runtime_ResolvePromise) {
253 : HandleScope scope(isolate);
254 : DCHECK_EQ(2, args.length());
255 28058 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
256 : CONVERT_ARG_HANDLE_CHECKED(Object, resolution, 1);
257 : Handle<Object> result;
258 56116 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
259 : JSPromise::Resolve(promise, resolution));
260 : return *result;
261 : }
262 :
263 : } // namespace internal
264 122036 : } // namespace v8
|