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 { ...@@ -603,6 +603,14 @@ enum ParseRestriction {
ONLY_SINGLE_FUNCTION_LITERAL // Only a single FunctionLiteral expression. 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 // A CodeDesc describes a buffer holding instructions and relocation
// information. The instructions start at the beginning of the buffer // information. The instructions start at the beginning of the buffer
// and grow forward, the relocation information starts at the end of // and grow forward, the relocation information starts at the end of
......
...@@ -130,7 +130,7 @@ function AsyncFunctionAwaitCaught(generator, awaited, outerPromise) { ...@@ -130,7 +130,7 @@ function AsyncFunctionAwaitCaught(generator, awaited, outerPromise) {
// How the parser rejects promises from async/await desugaring // How the parser rejects promises from async/await desugaring
function RejectPromiseNoDebugEvent(promise, reason) { function RejectPromiseNoDebugEvent(promise, reason) {
return RejectPromise(promise, reason, false); return RejectPromise(promise, reason);
} }
function AsyncFunctionPromiseCreate() { function AsyncFunctionPromiseCreate() {
......
...@@ -44,9 +44,10 @@ utils.Import(function(from) { ...@@ -44,9 +44,10 @@ utils.Import(function(from) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// [[PromiseState]] values: // [[PromiseState]] values:
// These values should be kept in sync with PromiseStatus in globals.h
const kPending = 0; const kPending = 0;
const kFulfilled = +1; const kFulfilled = +1;
const kRejected = -1; const kRejected = +2;
// ES#sec-createresolvingfunctions // ES#sec-createresolvingfunctions
// CreateResolvingFunctions ( promise ) // CreateResolvingFunctions ( promise )
...@@ -66,7 +67,8 @@ function CreateResolvingFunctions(promise, debugEvent) { ...@@ -66,7 +67,8 @@ function CreateResolvingFunctions(promise, debugEvent) {
var reject = reason => { var reject = reason => {
if (alreadyResolved === true) return; if (alreadyResolved === true) return;
alreadyResolved = true; alreadyResolved = true;
RejectPromise(promise, reason, debugEvent); %PromiseReject(promise, reason, debugEvent);
PromiseSet(promise, kRejected, reason);
}; };
return { return {
...@@ -157,7 +159,8 @@ function PromiseHandle(value, handler, deferred) { ...@@ -157,7 +159,8 @@ function PromiseHandle(value, handler, deferred) {
if (IS_UNDEFINED(deferred.reject)) { if (IS_UNDEFINED(deferred.reject)) {
// Pass false for debugEvent so .then chaining does not trigger // Pass false for debugEvent so .then chaining does not trigger
// redundant ExceptionEvents. // redundant ExceptionEvents.
RejectPromise(deferred.promise, exception, false); %PromiseReject(deferred.promise, exception, false);
PromiseSet(deferred.promise, kRejected, exception);
} else { } else {
%_Call(deferred.reject, UNDEFINED, exception); %_Call(deferred.reject, UNDEFINED, exception);
} }
...@@ -243,16 +246,19 @@ function PromiseCreate() { ...@@ -243,16 +246,19 @@ function PromiseCreate() {
// Promise Resolve Functions, steps 6-13 // Promise Resolve Functions, steps 6-13
function ResolvePromise(promise, resolution) { function ResolvePromise(promise, resolution) {
if (resolution === promise) { if (resolution === promise) {
return RejectPromise(promise, var exception = %make_type_error(kPromiseCyclic, resolution);
%make_type_error(kPromiseCyclic, resolution), %PromiseReject(promise, exception, true);
true); PromiseSet(promise, kRejected, exception);
return;
} }
if (IS_RECEIVER(resolution)) { if (IS_RECEIVER(resolution)) {
// 25.4.1.3.2 steps 8-12 // 25.4.1.3.2 steps 8-12
try { try {
var then = resolution.then; var then = resolution.then;
} catch (e) { } 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 // Resolution is a native promise and if it's already resolved or
...@@ -277,7 +283,8 @@ function ResolvePromise(promise, resolution) { ...@@ -277,7 +283,8 @@ function ResolvePromise(promise, resolution) {
%PromiseRevokeReject(resolution); %PromiseRevokeReject(resolution);
} }
// Don't cause a debug event as this case is forwarding a rejection // 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); SET_PRIVATE(resolution, promiseHasHandlerSymbol, true);
return; return;
} }
...@@ -299,26 +306,16 @@ function ResolvePromise(promise, resolution) { ...@@ -299,26 +306,16 @@ function ResolvePromise(promise, resolution) {
PromiseSet(promise, kFulfilled, resolution); PromiseSet(promise, kFulfilled, resolution);
} }
// ES#sec-rejectpromise // Only used by async-await.js
// RejectPromise ( promise, reason ) function RejectPromise(promise, reason) {
function RejectPromise(promise, reason, debugEvent) { %PromiseReject(promise, reason, false);
// 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)
PromiseSet(promise, kRejected, reason); PromiseSet(promise, kRejected, reason);
} }
// Export to bindings // Export to bindings
function DoRejectPromise(promise, reason) { function DoRejectPromise(promise, reason) {
return RejectPromise(promise, reason, true); %PromiseReject(promise, reason, true);
PromiseSet(promise, kRejected, reason);
} }
// ES#sec-newpromisecapability // ES#sec-newpromisecapability
......
...@@ -256,14 +256,14 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate, ...@@ -256,14 +256,14 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
const char* status = "rejected"; const char* status = "rejected";
int status_val = Handle<Smi>::cast(status_obj)->value(); int status_val = Handle<Smi>::cast(status_obj)->value();
switch (status_val) { switch (status_val) {
case +1: case kPromiseFulfilled:
status = "resolved"; status = "resolved";
break; break;
case 0: case kPromisePending:
status = "pending"; status = "pending";
break; break;
default: default:
DCHECK_EQ(-1, status_val); DCHECK_EQ(kPromiseRejected, status_val);
} }
Handle<FixedArray> result = factory->NewFixedArray(2 * 2); Handle<FixedArray> result = factory->NewFixedArray(2 * 2);
......
...@@ -601,8 +601,35 @@ void EnqueuePromiseReactionJob(Isolate* isolate, Handle<Object> value, ...@@ -601,8 +601,35 @@ void EnqueuePromiseReactionJob(Isolate* isolate, Handle<Object> value,
isolate->native_context()); isolate->native_context());
isolate->EnqueueMicrotask(info); 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 } // 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) { RUNTIME_FUNCTION(Runtime_PromiseFulfill) {
DCHECK(args.length() == 4); DCHECK(args.length() == 4);
HandleScope scope(isolate); HandleScope scope(isolate);
...@@ -610,12 +637,7 @@ RUNTIME_FUNCTION(Runtime_PromiseFulfill) { ...@@ -610,12 +637,7 @@ RUNTIME_FUNCTION(Runtime_PromiseFulfill) {
CONVERT_ARG_HANDLE_CHECKED(Smi, status, 1); CONVERT_ARG_HANDLE_CHECKED(Smi, status, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
CONVERT_ARG_HANDLE_CHECKED(Symbol, reaction, 3); CONVERT_ARG_HANDLE_CHECKED(Symbol, reaction, 3);
Handle<Object> tasks = JSReceiver::GetDataProperty(promise, reaction); PromiseFulfill(isolate, promise, status, value, reaction);
if (!tasks->IsUndefined(isolate)) {
Handle<Object> deferred = JSReceiver::GetDataProperty(
promise, isolate->factory()->promise_deferred_reaction_symbol());
EnqueuePromiseReactionJob(isolate, value, tasks, deferred, status);
}
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
......
...@@ -304,6 +304,7 @@ namespace internal { ...@@ -304,6 +304,7 @@ namespace internal {
F(NewSyntaxError, 2, 1) \ F(NewSyntaxError, 2, 1) \
F(NewTypeError, 2, 1) \ F(NewTypeError, 2, 1) \
F(OrdinaryHasInstance, 2, 1) \ F(OrdinaryHasInstance, 2, 1) \
F(PromiseReject, 3, 1) \
F(PromiseFulfill, 4, 1) \ F(PromiseFulfill, 4, 1) \
F(PromiseRejectEvent, 3, 1) \ F(PromiseRejectEvent, 3, 1) \
F(PromiseRejectEventFromStack, 2, 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