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/api-inl.h"
6#include "src/debug/debug.h"
7#include "src/execution/arguments-inl.h"
8#include "src/execution/microtask-queue.h"
9#include "src/logging/counters.h"
10#include "src/objects/elements.h"
11#include "src/objects/heap-object-inl.h"
12#include "src/objects/js-promise-inl.h"
13#include "src/objects/objects-inl.h"
14#include "src/objects/oddball-inl.h"
15#include "src/runtime/runtime-utils.h"
16
17namespace v8 {
18namespace internal {
19
20RUNTIME_FUNCTION(Runtime_PromiseRejectEventFromStack) {
21  DCHECK_EQ(2, args.length());
22  HandleScope scope(isolate);
23  Handle<JSPromise> promise = args.at<JSPromise>(0);
24  Handle<Object> value = args.at(1);
25
26  Handle<Object> rejected_promise = promise;
27  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    rejected_promise = isolate->GetPromiseOnStackOnThrow();
31  }
32  isolate->RunAllPromiseHooks(PromiseHookType::kResolve, promise,
33                              isolate->factory()->undefined_value());
34  isolate->debug()->OnPromiseReject(rejected_promise, value);
35
36  // Report only if we don't actually have a handler.
37  if (!promise->has_handler()) {
38    isolate->ReportPromiseReject(promise, value,
39                                 v8::kPromiseRejectWithNoHandler);
40  }
41  return ReadOnlyRoots(isolate).undefined_value();
42}
43
44RUNTIME_FUNCTION(Runtime_PromiseRejectAfterResolved) {
45  DCHECK_EQ(2, args.length());
46  HandleScope scope(isolate);
47  Handle<JSPromise> promise = args.at<JSPromise>(0);
48  Handle<Object> reason = args.at(1);
49  isolate->ReportPromiseReject(promise, reason,
50                               v8::kPromiseRejectAfterResolved);
51  return ReadOnlyRoots(isolate).undefined_value();
52}
53
54RUNTIME_FUNCTION(Runtime_PromiseResolveAfterResolved) {
55  DCHECK_EQ(2, args.length());
56  HandleScope scope(isolate);
57  Handle<JSPromise> promise = args.at<JSPromise>(0);
58  Handle<Object> resolution = args.at(1);
59  isolate->ReportPromiseReject(promise, resolution,
60                               v8::kPromiseResolveAfterResolved);
61  return ReadOnlyRoots(isolate).undefined_value();
62}
63
64RUNTIME_FUNCTION(Runtime_PromiseRevokeReject) {
65  DCHECK_EQ(1, args.length());
66  HandleScope scope(isolate);
67  Handle<JSPromise> promise = args.at<JSPromise>(0);
68  // At this point, no revocation has been issued before
69  CHECK(!promise->has_handler());
70  isolate->ReportPromiseReject(promise, Handle<Object>(),
71                               v8::kPromiseHandlerAddedAfterReject);
72  return ReadOnlyRoots(isolate).undefined_value();
73}
74
75RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) {
76  HandleScope scope(isolate);
77  DCHECK_EQ(1, args.length());
78  Handle<JSFunction> function = args.at<JSFunction>(0);
79
80  Handle<CallableTask> microtask = isolate->factory()->NewCallableTask(
81      function, handle(function->native_context(), isolate));
82  MicrotaskQueue* microtask_queue =
83      function->native_context().microtask_queue();
84  if (microtask_queue) microtask_queue->EnqueueMicrotask(*microtask);
85  return ReadOnlyRoots(isolate).undefined_value();
86}
87
88RUNTIME_FUNCTION(Runtime_PerformMicrotaskCheckpoint) {
89  HandleScope scope(isolate);
90  DCHECK_EQ(0, args.length());
91  MicrotasksScope::PerformCheckpoint(reinterpret_cast<v8::Isolate*>(isolate));
92  return ReadOnlyRoots(isolate).undefined_value();
93}
94
95RUNTIME_FUNCTION(Runtime_RunMicrotaskCallback) {
96  HandleScope scope(isolate);
97  DCHECK_EQ(2, args.length());
98  Object microtask_callback = args[0];
99  Object microtask_data = args[1];
100  MicrotaskCallback callback = ToCData<MicrotaskCallback>(microtask_callback);
101  void* data = ToCData<void*>(microtask_data);
102  callback(data);
103  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
104  return ReadOnlyRoots(isolate).undefined_value();
105}
106
107RUNTIME_FUNCTION(Runtime_PromiseStatus) {
108  HandleScope scope(isolate);
109  DCHECK_EQ(1, args.length());
110  Handle<JSPromise> promise = args.at<JSPromise>(0);
111
112  return Smi::FromInt(promise->status());
113}
114
115RUNTIME_FUNCTION(Runtime_PromiseHookInit) {
116  HandleScope scope(isolate);
117  DCHECK_EQ(2, args.length());
118  Handle<JSPromise> promise = args.at<JSPromise>(0);
119  Handle<Object> parent = args.at(1);
120  isolate->RunPromiseHook(PromiseHookType::kInit, promise, parent);
121  return ReadOnlyRoots(isolate).undefined_value();
122}
123
124RUNTIME_FUNCTION(Runtime_PromiseHookBefore) {
125  HandleScope scope(isolate);
126  DCHECK_EQ(1, args.length());
127  Handle<JSReceiver> promise = args.at<JSReceiver>(0);
128  if (promise->IsJSPromise()) {
129    isolate->OnPromiseBefore(Handle<JSPromise>::cast(promise));
130  }
131  return ReadOnlyRoots(isolate).undefined_value();
132}
133
134RUNTIME_FUNCTION(Runtime_PromiseHookAfter) {
135  HandleScope scope(isolate);
136  DCHECK_EQ(1, args.length());
137  Handle<JSReceiver> promise = args.at<JSReceiver>(0);
138  if (promise->IsJSPromise()) {
139    isolate->OnPromiseAfter(Handle<JSPromise>::cast(promise));
140  }
141  return ReadOnlyRoots(isolate).undefined_value();
142}
143
144RUNTIME_FUNCTION(Runtime_RejectPromise) {
145  HandleScope scope(isolate);
146  DCHECK_EQ(3, args.length());
147  Handle<JSPromise> promise = args.at<JSPromise>(0);
148  Handle<Object> reason = args.at(1);
149  Handle<Oddball> debug_event = args.at<Oddball>(2);
150  return *JSPromise::Reject(promise, reason,
151                            debug_event->BooleanValue(isolate));
152}
153
154RUNTIME_FUNCTION(Runtime_ResolvePromise) {
155  HandleScope scope(isolate);
156  DCHECK_EQ(2, args.length());
157  Handle<JSPromise> promise = args.at<JSPromise>(0);
158  Handle<Object> resolution = args.at(1);
159  Handle<Object> result;
160  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
161                                     JSPromise::Resolve(promise, resolution));
162  return *result;
163}
164
165// A helper function to be called when constructing AggregateError objects. This
166// takes care of the Error-related construction, e.g., stack traces.
167RUNTIME_FUNCTION(Runtime_ConstructAggregateErrorHelper) {
168  HandleScope scope(isolate);
169  DCHECK_EQ(4, args.length());
170  Handle<JSFunction> target = args.at<JSFunction>(0);
171  Handle<Object> new_target = args.at(1);
172  Handle<Object> message = args.at(2);
173  Handle<Object> options = args.at(3);
174
175  DCHECK_EQ(*target, *isolate->aggregate_error_function());
176
177  Handle<Object> result;
178  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
179      isolate, result,
180      ErrorUtils::Construct(isolate, target, new_target, message, options));
181  return *result;
182}
183
184// A helper function to be called when constructing AggregateError objects. This
185// takes care of the Error-related construction, e.g., stack traces.
186RUNTIME_FUNCTION(Runtime_ConstructInternalAggregateErrorHelper) {
187  HandleScope scope(isolate);
188  DCHECK_GE(args.length(), 1);
189  int message_template_index = args.smi_value_at(0);
190
191  Handle<Object> arg0;
192  if (args.length() >= 2) {
193    arg0 = args.at<Object>(1);
194  }
195
196  Handle<Object> arg1;
197  if (args.length() >= 3) {
198    arg1 = args.at<Object>(2);
199  }
200
201  Handle<Object> arg2;
202  if (args.length() >= 4) {
203    arg2 = args.at<Object>(3);
204  }
205
206  Handle<Object> options;
207  if (args.length() >= 5) {
208    options = args.at<Object>(4);
209  } else {
210    options = isolate->factory()->undefined_value();
211  }
212
213  Handle<Object> message_string = MessageFormatter::Format(
214      isolate, MessageTemplate(message_template_index), arg0, arg1, arg2);
215
216  Handle<Object> result;
217  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
218      isolate, result,
219      ErrorUtils::Construct(isolate, isolate->aggregate_error_function(),
220                            isolate->aggregate_error_function(), message_string,
221                            options));
222  return *result;
223}
224
225}  // namespace internal
226}  // namespace v8
227