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/objects-inl.h"
11 #include "src/objects/js-promise-inl.h"
12 #include "src/runtime/runtime-utils.h"
13 
14 namespace v8 {
15 namespace internal {
16 
RUNTIME_FUNCTION(Runtime_PromiseRejectEventFromStack)17 RUNTIME_FUNCTION(Runtime_PromiseRejectEventFromStack) {
18   DCHECK_EQ(2, args.length());
19   HandleScope scope(isolate);
20   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
21   CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
22 
23   Handle<Object> rejected_promise = promise;
24   if (isolate->debug()->is_active()) {
25     // If the Promise.reject() call is caught, then this will return
26     // undefined, which we interpret as being a caught exception event.
27     rejected_promise = isolate->GetPromiseOnStackOnThrow();
28   }
29   isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
30                           isolate->factory()->undefined_value());
31   isolate->debug()->OnPromiseReject(rejected_promise, value);
32 
33   // Report only if we don't actually have a handler.
34   if (!promise->has_handler()) {
35     isolate->ReportPromiseReject(promise, value,
36                                  v8::kPromiseRejectWithNoHandler);
37   }
38   return ReadOnlyRoots(isolate).undefined_value();
39 }
40 
RUNTIME_FUNCTION(Runtime_PromiseRejectAfterResolved)41 RUNTIME_FUNCTION(Runtime_PromiseRejectAfterResolved) {
42   DCHECK_EQ(2, args.length());
43   HandleScope scope(isolate);
44   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
45   CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1);
46   isolate->ReportPromiseReject(promise, reason,
47                                v8::kPromiseRejectAfterResolved);
48   return ReadOnlyRoots(isolate).undefined_value();
49 }
50 
RUNTIME_FUNCTION(Runtime_PromiseResolveAfterResolved)51 RUNTIME_FUNCTION(Runtime_PromiseResolveAfterResolved) {
52   DCHECK_EQ(2, args.length());
53   HandleScope scope(isolate);
54   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
55   CONVERT_ARG_HANDLE_CHECKED(Object, resolution, 1);
56   isolate->ReportPromiseReject(promise, resolution,
57                                v8::kPromiseResolveAfterResolved);
58   return ReadOnlyRoots(isolate).undefined_value();
59 }
60 
RUNTIME_FUNCTION(Runtime_PromiseRevokeReject)61 RUNTIME_FUNCTION(Runtime_PromiseRevokeReject) {
62   DCHECK_EQ(1, args.length());
63   HandleScope scope(isolate);
64   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
65   // At this point, no revocation has been issued before
66   CHECK(!promise->has_handler());
67   isolate->ReportPromiseReject(promise, Handle<Object>(),
68                                v8::kPromiseHandlerAddedAfterReject);
69   return ReadOnlyRoots(isolate).undefined_value();
70 }
71 
RUNTIME_FUNCTION(Runtime_EnqueueMicrotask)72 RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) {
73   HandleScope scope(isolate);
74   DCHECK_EQ(1, args.length());
75   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
76   Handle<CallableTask> microtask =
77       isolate->factory()->NewCallableTask(function, isolate->native_context());
78   isolate->EnqueueMicrotask(microtask);
79   return ReadOnlyRoots(isolate).undefined_value();
80 }
81 
RUNTIME_FUNCTION(Runtime_RunMicrotasks)82 RUNTIME_FUNCTION(Runtime_RunMicrotasks) {
83   HandleScope scope(isolate);
84   DCHECK_EQ(0, args.length());
85   isolate->RunMicrotasks();
86   return ReadOnlyRoots(isolate).undefined_value();
87 }
88 
RUNTIME_FUNCTION(Runtime_RunMicrotaskCallback)89 RUNTIME_FUNCTION(Runtime_RunMicrotaskCallback) {
90   HandleScope scope(isolate);
91   DCHECK_EQ(2, args.length());
92   CONVERT_ARG_CHECKED(Object, microtask_callback, 0);
93   CONVERT_ARG_CHECKED(Object, microtask_data, 1);
94   MicrotaskCallback callback = ToCData<MicrotaskCallback>(microtask_callback);
95   void* data = ToCData<void*>(microtask_data);
96   callback(data);
97   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
98   return ReadOnlyRoots(isolate).undefined_value();
99 }
100 
RUNTIME_FUNCTION(Runtime_PromiseStatus)101 RUNTIME_FUNCTION(Runtime_PromiseStatus) {
102   HandleScope scope(isolate);
103   DCHECK_EQ(1, args.length());
104   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
105 
106   return Smi::FromInt(promise->status());
107 }
108 
RUNTIME_FUNCTION(Runtime_PromiseResult)109 RUNTIME_FUNCTION(Runtime_PromiseResult) {
110   HandleScope scope(isolate);
111   DCHECK_EQ(1, args.length());
112   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
113   return promise->result();
114 }
115 
RUNTIME_FUNCTION(Runtime_PromiseMarkAsHandled)116 RUNTIME_FUNCTION(Runtime_PromiseMarkAsHandled) {
117   SealHandleScope shs(isolate);
118   DCHECK_EQ(1, args.length());
119   CONVERT_ARG_CHECKED(JSPromise, promise, 0);
120 
121   promise->set_has_handler(true);
122   return ReadOnlyRoots(isolate).undefined_value();
123 }
124 
RUNTIME_FUNCTION(Runtime_PromiseHookInit)125 RUNTIME_FUNCTION(Runtime_PromiseHookInit) {
126   HandleScope scope(isolate);
127   DCHECK_EQ(2, args.length());
128   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
129   CONVERT_ARG_HANDLE_CHECKED(Object, parent, 1);
130   isolate->RunPromiseHook(PromiseHookType::kInit, promise, parent);
131   return ReadOnlyRoots(isolate).undefined_value();
132 }
133 
RUNTIME_FUNCTION(Runtime_AwaitPromisesInit)134 RUNTIME_FUNCTION(Runtime_AwaitPromisesInit) {
135   DCHECK_EQ(3, args.length());
136   HandleScope scope(isolate);
137   CONVERT_ARG_HANDLE_CHECKED(JSPromise, wrapped_value, 0);
138   CONVERT_ARG_HANDLE_CHECKED(JSPromise, outer_promise, 1);
139   CONVERT_ARG_HANDLE_CHECKED(JSPromise, throwaway, 2);
140   isolate->RunPromiseHook(PromiseHookType::kInit, wrapped_value, outer_promise);
141   isolate->RunPromiseHook(PromiseHookType::kInit, throwaway, wrapped_value);
142   // On inspector side we capture async stack trace and store it by
143   // outer_promise->async_task_id when async function is suspended first time.
144   // To use captured stack trace later throwaway promise should have the same
145   // async_task_id as outer_promise since we generate WillHandle and DidHandle
146   // events using throwaway promise.
147   throwaway->set_async_task_id(outer_promise->async_task_id());
148   return ReadOnlyRoots(isolate).undefined_value();
149 }
150 
RUNTIME_FUNCTION(Runtime_PromiseHookBefore)151 RUNTIME_FUNCTION(Runtime_PromiseHookBefore) {
152   HandleScope scope(isolate);
153   DCHECK_EQ(1, args.length());
154   CONVERT_ARG_HANDLE_CHECKED(JSReceiver, maybe_promise, 0);
155   if (!maybe_promise->IsJSPromise())
156     return ReadOnlyRoots(isolate).undefined_value();
157   Handle<JSPromise> promise = Handle<JSPromise>::cast(maybe_promise);
158   if (isolate->debug()->is_active()) isolate->PushPromise(promise);
159   if (promise->IsJSPromise()) {
160     isolate->RunPromiseHook(PromiseHookType::kBefore, promise,
161                             isolate->factory()->undefined_value());
162   }
163   return ReadOnlyRoots(isolate).undefined_value();
164 }
165 
RUNTIME_FUNCTION(Runtime_PromiseHookAfter)166 RUNTIME_FUNCTION(Runtime_PromiseHookAfter) {
167   HandleScope scope(isolate);
168   DCHECK_EQ(1, args.length());
169   CONVERT_ARG_HANDLE_CHECKED(JSReceiver, maybe_promise, 0);
170   if (!maybe_promise->IsJSPromise())
171     return ReadOnlyRoots(isolate).undefined_value();
172   Handle<JSPromise> promise = Handle<JSPromise>::cast(maybe_promise);
173   if (isolate->debug()->is_active()) isolate->PopPromise();
174   if (promise->IsJSPromise()) {
175     isolate->RunPromiseHook(PromiseHookType::kAfter, promise,
176                             isolate->factory()->undefined_value());
177   }
178   return ReadOnlyRoots(isolate).undefined_value();
179 }
180 
RUNTIME_FUNCTION(Runtime_RejectPromise)181 RUNTIME_FUNCTION(Runtime_RejectPromise) {
182   HandleScope scope(isolate);
183   DCHECK_EQ(3, args.length());
184   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
185   CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1);
186   CONVERT_ARG_HANDLE_CHECKED(Oddball, debug_event, 2);
187   return *JSPromise::Reject(promise, reason,
188                             debug_event->BooleanValue(isolate));
189 }
190 
RUNTIME_FUNCTION(Runtime_ResolvePromise)191 RUNTIME_FUNCTION(Runtime_ResolvePromise) {
192   HandleScope scope(isolate);
193   DCHECK_EQ(2, args.length());
194   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
195   CONVERT_ARG_HANDLE_CHECKED(Object, resolution, 1);
196   Handle<Object> result;
197   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
198                                      JSPromise::Resolve(promise, resolution));
199   return *result;
200 }
201 
202 }  // namespace internal
203 }  // namespace v8
204