runtime-promise.cc 9.59 KB
Newer Older
1 2 3
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/api-inl.h"
6
#include "src/arguments-inl.h"
7
#include "src/counters.h"
8 9
#include "src/debug/debug.h"
#include "src/elements.h"
10
#include "src/objects-inl.h"
11
#include "src/objects/heap-object-inl.h"
12
#include "src/objects/js-promise-inl.h"
13
#include "src/runtime/runtime-utils.h"
14 15 16 17 18

namespace v8 {
namespace internal {

RUNTIME_FUNCTION(Runtime_PromiseRejectEventFromStack) {
19
  DCHECK_EQ(2, args.length());
20
  HandleScope scope(isolate);
21
  CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
22 23 24 25
  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);

  Handle<Object> rejected_promise = promise;
  if (isolate->debug()->is_active()) {
26 27
    // If the Promise.reject() call is caught, then this will return
    // undefined, which we interpret as being a caught exception event.
28 29
    rejected_promise = isolate->GetPromiseOnStackOnThrow();
  }
30 31 32
  isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
                          isolate->factory()->undefined_value());
  isolate->debug()->OnPromiseReject(rejected_promise, value);
33

34 35 36 37 38
  // Report only if we don't actually have a handler.
  if (!promise->has_handler()) {
    isolate->ReportPromiseReject(promise, value,
                                 v8::kPromiseRejectWithNoHandler);
  }
39
  return ReadOnlyRoots(isolate).undefined_value();
40 41
}

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
RUNTIME_FUNCTION(Runtime_PromiseRejectAfterResolved) {
  DCHECK_EQ(2, args.length());
  HandleScope scope(isolate);
  CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
  CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1);
  isolate->ReportPromiseReject(promise, reason,
                               v8::kPromiseRejectAfterResolved);
  return ReadOnlyRoots(isolate).undefined_value();
}

RUNTIME_FUNCTION(Runtime_PromiseResolveAfterResolved) {
  DCHECK_EQ(2, args.length());
  HandleScope scope(isolate);
  CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
  CONVERT_ARG_HANDLE_CHECKED(Object, resolution, 1);
  isolate->ReportPromiseReject(promise, resolution,
                               v8::kPromiseResolveAfterResolved);
  return ReadOnlyRoots(isolate).undefined_value();
}

62
RUNTIME_FUNCTION(Runtime_PromiseRevokeReject) {
63
  DCHECK_EQ(1, args.length());
64
  HandleScope scope(isolate);
65
  CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
66
  // At this point, no revocation has been issued before
67
  CHECK(!promise->has_handler());
68 69
  isolate->ReportPromiseReject(promise, Handle<Object>(),
                               v8::kPromiseHandlerAddedAfterReject);
70
  return ReadOnlyRoots(isolate).undefined_value();
71 72 73 74
}

RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) {
  HandleScope scope(isolate);
75
  DCHECK_EQ(1, args.length());
76 77 78
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
  Handle<CallableTask> microtask =
      isolate->factory()->NewCallableTask(function, isolate->native_context());
79
  isolate->EnqueueMicrotask(microtask);
80
  return ReadOnlyRoots(isolate).undefined_value();
81 82 83 84
}

RUNTIME_FUNCTION(Runtime_RunMicrotasks) {
  HandleScope scope(isolate);
85
  DCHECK_EQ(0, args.length());
86
  isolate->RunMicrotasks();
87
  return ReadOnlyRoots(isolate).undefined_value();
88 89
}

90 91 92 93 94 95 96 97
RUNTIME_FUNCTION(Runtime_RunMicrotaskCallback) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_CHECKED(Object, microtask_callback, 0);
  CONVERT_ARG_CHECKED(Object, microtask_data, 1);
  MicrotaskCallback callback = ToCData<MicrotaskCallback>(microtask_callback);
  void* data = ToCData<void*>(microtask_data);
  callback(data);
98
  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
99
  return ReadOnlyRoots(isolate).undefined_value();
100 101
}

102 103
RUNTIME_FUNCTION(Runtime_PromiseStatus) {
  HandleScope scope(isolate);
104
  DCHECK_EQ(1, args.length());
105 106 107 108 109
  CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);

  return Smi::FromInt(promise->status());
}

110
RUNTIME_FUNCTION(Runtime_PromiseMarkAsHandled) {
111
  SealHandleScope shs(isolate);
112
  DCHECK_EQ(1, args.length());
113
  CONVERT_ARG_CHECKED(JSPromise, promise, 0);
114 115

  promise->set_has_handler(true);
116
  return ReadOnlyRoots(isolate).undefined_value();
117 118
}

119 120 121 122 123 124
RUNTIME_FUNCTION(Runtime_PromiseHookInit) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
  CONVERT_ARG_HANDLE_CHECKED(Object, parent, 1);
  isolate->RunPromiseHook(PromiseHookType::kInit, promise, parent);
125
  return ReadOnlyRoots(isolate).undefined_value();
126 127
}

128 129 130 131 132 133 134 135 136 137 138
namespace {

Handle<JSPromise> AwaitPromisesInitCommon(Isolate* isolate,
                                          Handle<Object> value,
                                          Handle<JSPromise> promise,
                                          Handle<JSPromise> outer_promise,
                                          Handle<JSFunction> reject_handler,
                                          bool is_predicted_as_caught) {
  // Allocate the throwaway promise and fire the appropriate init
  // hook for the throwaway promise (passing the {promise} as its
  // parent).
139 140 141
  Handle<JSPromise> throwaway = isolate->factory()->NewJSPromiseWithoutHook();
  isolate->RunPromiseHook(PromiseHookType::kInit, throwaway, promise);

142 143 144 145 146 147
  // On inspector side we capture async stack trace and store it by
  // outer_promise->async_task_id when async function is suspended first time.
  // To use captured stack trace later throwaway promise should have the same
  // async_task_id as outer_promise since we generate WillHandle and DidHandle
  // events using throwaway promise.
  throwaway->set_async_task_id(outer_promise->async_task_id());
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171

  // The Promise will be thrown away and not handled, but it
  // shouldn't trigger unhandled reject events as its work is done
  throwaway->set_has_handler(true);

  // Enable proper debug support for promises.
  if (isolate->debug()->is_active()) {
    if (value->IsJSPromise()) {
      Object::SetProperty(
          isolate, reject_handler,
          isolate->factory()->promise_forwarding_handler_symbol(),
          isolate->factory()->true_value(), LanguageMode::kStrict)
          .Check();
      Handle<JSPromise>::cast(value)->set_handled_hint(is_predicted_as_caught);
    }

    // Mark the dependency to {outer_promise} in case the {throwaway}
    // Promise is found on the Promise stack
    Object::SetProperty(isolate, throwaway,
                        isolate->factory()->promise_handled_by_symbol(),
                        outer_promise, LanguageMode::kStrict)
        .Check();
  }

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
  return throwaway;
}

}  // namespace

RUNTIME_FUNCTION(Runtime_AwaitPromisesInit) {
  DCHECK_EQ(5, args.length());
  HandleScope scope(isolate);
  CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 1);
  CONVERT_ARG_HANDLE_CHECKED(JSPromise, outer_promise, 2);
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, reject_handler, 3);
  CONVERT_BOOLEAN_ARG_CHECKED(is_predicted_as_caught, 4);
  return *AwaitPromisesInitCommon(isolate, value, promise, outer_promise,
                                  reject_handler, is_predicted_as_caught);
}

RUNTIME_FUNCTION(Runtime_AwaitPromisesInitOld) {
  DCHECK_EQ(5, args.length());
  HandleScope scope(isolate);
  CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 1);
  CONVERT_ARG_HANDLE_CHECKED(JSPromise, outer_promise, 2);
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, reject_handler, 3);
  CONVERT_BOOLEAN_ARG_CHECKED(is_predicted_as_caught, 4);

  // Fire the init hook for the wrapper promise (that we created for the
  // {value} previously).
  isolate->RunPromiseHook(PromiseHookType::kInit, promise, outer_promise);
  return *AwaitPromisesInitCommon(isolate, value, promise, outer_promise,
                                  reject_handler, is_predicted_as_caught);
203 204
}

205 206 207
RUNTIME_FUNCTION(Runtime_PromiseHookBefore) {
  HandleScope scope(isolate);
  DCHECK_EQ(1, args.length());
208
  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, maybe_promise, 0);
209 210
  if (!maybe_promise->IsJSPromise())
    return ReadOnlyRoots(isolate).undefined_value();
211 212 213 214 215
  Handle<JSPromise> promise = Handle<JSPromise>::cast(maybe_promise);
  if (isolate->debug()->is_active()) isolate->PushPromise(promise);
  if (promise->IsJSPromise()) {
    isolate->RunPromiseHook(PromiseHookType::kBefore, promise,
                            isolate->factory()->undefined_value());
216
  }
217
  return ReadOnlyRoots(isolate).undefined_value();
218 219 220 221 222
}

RUNTIME_FUNCTION(Runtime_PromiseHookAfter) {
  HandleScope scope(isolate);
  DCHECK_EQ(1, args.length());
223
  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, maybe_promise, 0);
224 225
  if (!maybe_promise->IsJSPromise())
    return ReadOnlyRoots(isolate).undefined_value();
226 227 228 229 230
  Handle<JSPromise> promise = Handle<JSPromise>::cast(maybe_promise);
  if (isolate->debug()->is_active()) isolate->PopPromise();
  if (promise->IsJSPromise()) {
    isolate->RunPromiseHook(PromiseHookType::kAfter, promise,
                            isolate->factory()->undefined_value());
231
  }
232
  return ReadOnlyRoots(isolate).undefined_value();
233 234
}

235 236 237 238 239 240
RUNTIME_FUNCTION(Runtime_RejectPromise) {
  HandleScope scope(isolate);
  DCHECK_EQ(3, args.length());
  CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
  CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1);
  CONVERT_ARG_HANDLE_CHECKED(Oddball, debug_event, 2);
241 242
  return *JSPromise::Reject(promise, reason,
                            debug_event->BooleanValue(isolate));
243 244 245 246 247 248 249 250 251 252 253 254 255
}

RUNTIME_FUNCTION(Runtime_ResolvePromise) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
  CONVERT_ARG_HANDLE_CHECKED(Object, resolution, 1);
  Handle<Object> result;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
                                     JSPromise::Resolve(promise, resolution));
  return *result;
}

256 257
}  // namespace internal
}  // namespace v8