Commit f80f4509 authored by gsathya's avatar gsathya Committed by Commit bot

[promises] Move PromiseReject to c++

This patch refactors most of FulfillPromise runtime call out to a separate
function so that we can to it from PromiseReject runtime call.

This patch adds a PromiseStatus enum.

BUG=v8:5343

Review-Url: https://codereview.chromium.org/2451163003
Cr-Commit-Position: refs/heads/master@{#40615}
parent 017f48d2
......@@ -603,6 +603,14 @@ enum ParseRestriction {
ONLY_SINGLE_FUNCTION_LITERAL // Only a single FunctionLiteral expression.
};
// TODO(gsathya): Move this to JSPromise once we create it.
// This should be in sync with the constants in promise.js
enum PromiseStatus {
kPromisePending,
kPromiseFulfilled,
kPromiseRejected,
};
// A CodeDesc describes a buffer holding instructions and relocation
// information. The instructions start at the beginning of the buffer
// and grow forward, the relocation information starts at the end of
......
......@@ -130,7 +130,7 @@ function AsyncFunctionAwaitCaught(generator, awaited, outerPromise) {
// How the parser rejects promises from async/await desugaring
function RejectPromiseNoDebugEvent(promise, reason) {
return RejectPromise(promise, reason, false);
return RejectPromise(promise, reason);
}
function AsyncFunctionPromiseCreate() {
......
......@@ -44,9 +44,10 @@ utils.Import(function(from) {
// -------------------------------------------------------------------
// [[PromiseState]] values:
// These values should be kept in sync with PromiseStatus in globals.h
const kPending = 0;
const kFulfilled = +1;
const kRejected = -1;
const kRejected = +2;
// ES#sec-createresolvingfunctions
// CreateResolvingFunctions ( promise )
......@@ -66,7 +67,8 @@ function CreateResolvingFunctions(promise, debugEvent) {
var reject = reason => {
if (alreadyResolved === true) return;
alreadyResolved = true;
RejectPromise(promise, reason, debugEvent);
%PromiseReject(promise, reason, debugEvent);
PromiseSet(promise, kRejected, reason);
};
return {
......@@ -157,7 +159,8 @@ function PromiseHandle(value, handler, deferred) {
if (IS_UNDEFINED(deferred.reject)) {
// Pass false for debugEvent so .then chaining does not trigger
// redundant ExceptionEvents.
RejectPromise(deferred.promise, exception, false);
%PromiseReject(deferred.promise, exception, false);
PromiseSet(deferred.promise, kRejected, exception);
} else {
%_Call(deferred.reject, UNDEFINED, exception);
}
......@@ -243,16 +246,19 @@ function PromiseCreate() {
// Promise Resolve Functions, steps 6-13
function ResolvePromise(promise, resolution) {
if (resolution === promise) {
return RejectPromise(promise,
%make_type_error(kPromiseCyclic, resolution),
true);
var exception = %make_type_error(kPromiseCyclic, resolution);
%PromiseReject(promise, exception, true);
PromiseSet(promise, kRejected, exception);
return;
}
if (IS_RECEIVER(resolution)) {
// 25.4.1.3.2 steps 8-12
try {
var then = resolution.then;
} catch (e) {
return RejectPromise(promise, e, true);
%PromiseReject(promise, e, true);
PromiseSet(promise, kRejected, e);
return;
}
// Resolution is a native promise and if it's already resolved or
......@@ -277,7 +283,8 @@ function ResolvePromise(promise, resolution) {
%PromiseRevokeReject(resolution);
}
// Don't cause a debug event as this case is forwarding a rejection
RejectPromise(promise, thenableValue, false);
%PromiseReject(promise, thenableValue, false);
PromiseSet(promise, kRejected, thenableValue);
SET_PRIVATE(resolution, promiseHasHandlerSymbol, true);
return;
}
......@@ -299,26 +306,16 @@ function ResolvePromise(promise, resolution) {
PromiseSet(promise, kFulfilled, resolution);
}
// ES#sec-rejectpromise
// RejectPromise ( promise, reason )
function RejectPromise(promise, reason, debugEvent) {
// Call runtime for callbacks to the debugger or for unhandled reject.
// The debugEvent parameter sets whether a debug ExceptionEvent should
// be triggered. It should be set to false when forwarding a rejection
// rather than creating a new one.
// This check is redundant with checks in the runtime, but it may help
// avoid unnecessary runtime calls.
if ((debugEvent && DEBUG_IS_ACTIVE) ||
!HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) {
%PromiseRejectEvent(promise, reason, debugEvent);
}
%PromiseFulfill(promise, kRejected, reason, promiseRejectReactionsSymbol)
// Only used by async-await.js
function RejectPromise(promise, reason) {
%PromiseReject(promise, reason, false);
PromiseSet(promise, kRejected, reason);
}
// Export to bindings
function DoRejectPromise(promise, reason) {
return RejectPromise(promise, reason, true);
%PromiseReject(promise, reason, true);
PromiseSet(promise, kRejected, reason);
}
// ES#sec-newpromisecapability
......
......@@ -256,14 +256,14 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
const char* status = "rejected";
int status_val = Handle<Smi>::cast(status_obj)->value();
switch (status_val) {
case +1:
case kPromiseFulfilled:
status = "resolved";
break;
case 0:
case kPromisePending:
status = "pending";
break;
default:
DCHECK_EQ(-1, status_val);
DCHECK_EQ(kPromiseRejected, status_val);
}
Handle<FixedArray> result = factory->NewFixedArray(2 * 2);
......
......@@ -601,8 +601,35 @@ void EnqueuePromiseReactionJob(Isolate* isolate, Handle<Object> value,
isolate->native_context());
isolate->EnqueueMicrotask(info);
}
void PromiseFulfill(Isolate* isolate, Handle<JSReceiver> promise,
Handle<Smi> status, Handle<Object> value,
Handle<Symbol> reaction) {
Handle<Object> tasks = JSReceiver::GetDataProperty(promise, reaction);
if (!tasks->IsUndefined(isolate)) {
Handle<Object> deferred = JSReceiver::GetDataProperty(
promise, isolate->factory()->promise_deferred_reaction_symbol());
EnqueuePromiseReactionJob(isolate, value, tasks, deferred, status);
}
}
} // namespace
RUNTIME_FUNCTION(Runtime_PromiseReject) {
DCHECK(args.length() == 3);
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, reason, 1);
CONVERT_BOOLEAN_ARG_CHECKED(debug_event, 2);
PromiseRejectEvent(isolate, promise, promise, reason, debug_event);
Handle<Smi> status = handle(Smi::FromInt(kPromiseRejected), isolate);
Handle<Symbol> reaction =
isolate->factory()->promise_reject_reactions_symbol();
PromiseFulfill(isolate, promise, status, reason, reaction);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_PromiseFulfill) {
DCHECK(args.length() == 4);
HandleScope scope(isolate);
......@@ -610,12 +637,7 @@ RUNTIME_FUNCTION(Runtime_PromiseFulfill) {
CONVERT_ARG_HANDLE_CHECKED(Smi, status, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
CONVERT_ARG_HANDLE_CHECKED(Symbol, reaction, 3);
Handle<Object> tasks = JSReceiver::GetDataProperty(promise, reaction);
if (!tasks->IsUndefined(isolate)) {
Handle<Object> deferred = JSReceiver::GetDataProperty(
promise, isolate->factory()->promise_deferred_reaction_symbol());
EnqueuePromiseReactionJob(isolate, value, tasks, deferred, status);
}
PromiseFulfill(isolate, promise, status, value, reaction);
return isolate->heap()->undefined_value();
}
......
......@@ -304,6 +304,7 @@ namespace internal {
F(NewSyntaxError, 2, 1) \
F(NewTypeError, 2, 1) \
F(OrdinaryHasInstance, 2, 1) \
F(PromiseReject, 3, 1) \
F(PromiseFulfill, 4, 1) \
F(PromiseRejectEvent, 3, 1) \
F(PromiseRejectEventFromStack, 2, 1) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment