Commit d8967c55 authored by littledan's avatar littledan Committed by Commit bot

Renaming cleanup of Promises

The Promise code previously used many names which were gratuitiously
different from the specification. This patch swaps in names from the
ES2015 spec, and inserts crossreferences to the spec. The patch
leaves mirrors over Promises unchanged for now, as these changes
could have compatibility risk.

R=cbruni@chromium.org

Review-Url: https://codereview.chromium.org/1919143004
Cr-Commit-Position: refs/heads/master@{#35962}
parent 8d018a39
......@@ -16,8 +16,8 @@ var MakeError;
var MapEntries;
var MapIteratorNext;
var MathMin = global.Math.min;
var promiseStatusSymbol = utils.ImportNow("promise_status_symbol");
var promiseValueSymbol = utils.ImportNow("promise_value_symbol");
var promiseStateSymbol = utils.ImportNow("promise_state_symbol");
var promiseResultSymbol = utils.ImportNow("promise_result_symbol");
var SetIteratorNext;
var SetValues;
var SymbolToString;
......@@ -115,7 +115,7 @@ function ClearMirrorCache(value) {
function ObjectIsPromise(value) {
return IS_RECEIVER(value) &&
!IS_UNDEFINED(%DebugGetProperty(value, promiseStatusSymbol));
!IS_UNDEFINED(%DebugGetProperty(value, promiseStateSymbol));
}
......@@ -1272,7 +1272,7 @@ inherits(PromiseMirror, ObjectMirror);
function PromiseGetStatus_(value) {
var status = %DebugGetProperty(value, promiseStatusSymbol);
var status = %DebugGetProperty(value, promiseStateSymbol);
if (status == 0) return "pending";
if (status == 1) return "resolved";
return "rejected";
......@@ -1280,7 +1280,7 @@ function PromiseGetStatus_(value) {
function PromiseGetValue_(value) {
return %DebugGetProperty(value, promiseValueSymbol);
return %DebugGetProperty(value, promiseResultSymbol);
}
......
......@@ -166,11 +166,11 @@
V(promise_combined_deferred_symbol) \
V(promise_debug_marker_symbol) \
V(promise_has_handler_symbol) \
V(promise_on_resolve_symbol) \
V(promise_on_reject_symbol) \
V(promise_fulfill_reactions_symbol) \
V(promise_reject_reactions_symbol) \
V(promise_raw_symbol) \
V(promise_status_symbol) \
V(promise_value_symbol) \
V(promise_state_symbol) \
V(promise_result_symbol) \
V(sealed_symbol) \
V(stack_trace_symbol) \
V(strict_function_transition_symbol) \
......
......@@ -196,8 +196,8 @@ function PostNatives(utils) {
"MinSimple",
"NumberIsInteger",
"PromiseChain",
"PromiseDeferred",
"PromiseResolved",
"PromiseDefer",
"PromiseAccept",
"RegExpSubclassExecJS",
"RegExpSubclassMatch",
"RegExpSubclassReplace",
......@@ -212,8 +212,8 @@ function PostNatives(utils) {
// From runtime:
"is_concat_spreadable_symbol",
"iterator_symbol",
"promise_status_symbol",
"promise_value_symbol",
"promise_result_symbol",
"promise_state_symbol",
"object_freeze",
"object_is_frozen",
"object_is_sealed",
......
......@@ -11,16 +11,16 @@
var GlobalPromise = global.Promise;
var PromiseChain = utils.ImportNow("PromiseChain");
var PromiseDeferred = utils.ImportNow("PromiseDeferred");
var PromiseResolved = utils.ImportNow("PromiseResolved");
var PromiseDefer = utils.ImportNow("PromiseDefer");
var PromiseAccept = utils.ImportNow("PromiseAccept");
utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [
"chain", PromiseChain,
]);
utils.InstallFunctions(GlobalPromise, DONT_ENUM, [
"defer", PromiseDeferred,
"accept", PromiseResolved,
"defer", PromiseDefer,
"accept", PromiseAccept,
]);
})
......@@ -17,12 +17,13 @@ var promiseCombinedDeferredSymbol =
utils.ImportNow("promise_combined_deferred_symbol");
var promiseHasHandlerSymbol =
utils.ImportNow("promise_has_handler_symbol");
var promiseOnRejectSymbol = utils.ImportNow("promise_on_reject_symbol");
var promiseOnResolveSymbol =
utils.ImportNow("promise_on_resolve_symbol");
var promiseRejectReactionsSymbol =
utils.ImportNow("promise_reject_reactions_symbol");
var promiseFulfillReactionsSymbol =
utils.ImportNow("promise_fulfill_reactions_symbol");
var promiseRawSymbol = utils.ImportNow("promise_raw_symbol");
var promiseStatusSymbol = utils.ImportNow("promise_status_symbol");
var promiseValueSymbol = utils.ImportNow("promise_value_symbol");
var promiseStateSymbol = utils.ImportNow("promise_state_symbol");
var promiseResultSymbol = utils.ImportNow("promise_result_symbol");
var SpeciesConstructor;
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
......@@ -33,22 +34,32 @@ utils.Import(function(from) {
// -------------------------------------------------------------------
// Status values: 0 = pending, +1 = resolved, -1 = rejected
// [[PromiseState]] values:
const kPending = 0;
const kFulfilled = +1;
const kRejected = -1;
var lastMicrotaskId = 0;
// ES#sec-createresolvingfunctions
// CreateResolvingFunctions ( promise )
function CreateResolvingFunctions(promise) {
var alreadyResolved = false;
// ES#sec-promise-resolve-functions
// Promise Resolve Functions
var resolve = value => {
if (alreadyResolved === true) return;
alreadyResolved = true;
PromiseResolve(promise, value);
FulfillPromise(promise, value);
};
// ES#sec-promise-reject-functions
// Promise Reject Functions
var reject = reason => {
if (alreadyResolved === true) return;
alreadyResolved = true;
PromiseReject(promise, reason);
RejectPromise(promise, reason);
};
return {
......@@ -59,13 +70,16 @@ function CreateResolvingFunctions(promise) {
}
// ES#sec-promise-executor
// Promise ( executor )
var GlobalPromise = function Promise(resolver) {
if (resolver === promiseRawSymbol) {
return %_NewObject(GlobalPromise, new.target);
}
if (IS_UNDEFINED(new.target)) throw MakeTypeError(kNotAPromise, this);
if (!IS_CALLABLE(resolver))
if (!IS_CALLABLE(resolver)) {
throw MakeTypeError(kResolverNotAFunction, resolver);
}
var promise = PromiseInit(%_NewObject(GlobalPromise, new.target));
var callbacks = CreateResolvingFunctions(promise);
......@@ -85,27 +99,27 @@ var GlobalPromise = function Promise(resolver) {
// Core functionality.
function PromiseSet(promise, status, value, onResolve, onReject) {
SET_PRIVATE(promise, promiseStatusSymbol, status);
SET_PRIVATE(promise, promiseValueSymbol, value);
SET_PRIVATE(promise, promiseOnResolveSymbol, onResolve);
SET_PRIVATE(promise, promiseOnRejectSymbol, onReject);
SET_PRIVATE(promise, promiseStateSymbol, status);
SET_PRIVATE(promise, promiseResultSymbol, value);
SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve);
SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject);
return promise;
}
function PromiseCreateAndSet(status, value) {
var promise = new GlobalPromise(promiseRawSymbol);
// If debug is active, notify about the newly created promise first.
if (DEBUG_IS_ACTIVE) PromiseSet(promise, 0, UNDEFINED);
if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED);
return PromiseSet(promise, status, value);
}
function PromiseInit(promise) {
return PromiseSet(
promise, 0, UNDEFINED, new InternalArray, new InternalArray)
promise, kPending, UNDEFINED, new InternalArray, new InternalArray)
}
function PromiseDone(promise, status, value, promiseQueue) {
if (GET_PRIVATE(promise, promiseStatusSymbol) === 0) {
if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) {
var tasks = GET_PRIVATE(promise, promiseQueue);
if (tasks.length) PromiseEnqueue(value, tasks, status);
PromiseSet(promise, status, value);
......@@ -139,7 +153,7 @@ function PromiseEnqueue(value, tasks, status) {
});
if (instrumenting) {
id = ++lastMicrotaskId;
name = status > 0 ? "Promise.resolve" : "Promise.reject";
name = status === kFulfilled ? "Promise.resolve" : "Promise.reject";
%DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
}
}
......@@ -154,24 +168,27 @@ function PromiseNopResolver() {}
// For bootstrapper.
// ES#sec-ispromise IsPromise ( x )
function IsPromise(x) {
return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStatusSymbol);
return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStateSymbol);
}
function PromiseCreate() {
return new GlobalPromise(PromiseNopResolver)
}
function PromiseResolve(promise, x) {
// ES#sec-fulfillpromise
// FulfillPromise ( promise, value)
function FulfillPromise(promise, x) {
if (x === promise) {
return PromiseReject(promise, MakeTypeError(kPromiseCyclic, x));
return RejectPromise(promise, MakeTypeError(kPromiseCyclic, x));
}
if (IS_RECEIVER(x)) {
// 25.4.1.3.2 steps 8-12
try {
var then = x.then;
} catch (e) {
return PromiseReject(promise, e);
return RejectPromise(promise, e);
}
if (IS_CALLABLE(then)) {
// PromiseResolveThenableJob
......@@ -198,22 +215,26 @@ function PromiseResolve(promise, x) {
return;
}
}
PromiseDone(promise, +1, x, promiseOnResolveSymbol);
PromiseDone(promise, kFulfilled, x, promiseFulfillReactionsSymbol);
}
function PromiseReject(promise, r) {
// ES#sec-rejectpromise
// RejectPromise ( promise, reason )
function RejectPromise(promise, r) {
// Check promise status to confirm that this reject has an effect.
// Call runtime for callbacks to the debugger or for unhandled reject.
if (GET_PRIVATE(promise, promiseStatusSymbol) == 0) {
if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) {
var debug_is_active = DEBUG_IS_ACTIVE;
if (debug_is_active ||
!HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) {
%PromiseRejectEvent(promise, r, debug_is_active);
}
}
PromiseDone(promise, -1, r, promiseOnRejectSymbol)
PromiseDone(promise, kRejected, r, promiseRejectReactionsSymbol)
}
// ES#sec-newpromisecapability
// NewPromiseCapability ( C )
function NewPromiseCapability(C) {
if (C === GlobalPromise) {
// Optimized case, avoid extra closure.
......@@ -240,23 +261,27 @@ function NewPromiseCapability(C) {
return result;
}
function PromiseDeferred() {
// Unspecified V8-specific legacy function
function PromiseDefer() {
%IncrementUseCounter(kPromiseDefer);
return NewPromiseCapability(this);
}
function PromiseResolved(x) {
// Unspecified V8-specific legacy function
function PromiseAccept(x) {
%IncrementUseCounter(kPromiseAccept);
return %_Call(PromiseCast, this, x);
return %_Call(PromiseResolve, this, x);
}
function PromiseRejected(r) {
// ES#sec-promise.reject
// Promise.reject ( x )
function PromiseReject(r) {
if (!IS_RECEIVER(this)) {
throw MakeTypeError(kCalledOnNonObject, PromiseRejected);
throw MakeTypeError(kCalledOnNonObject, PromiseResolve);
}
if (this === GlobalPromise) {
// Optimized case, avoid extra closure.
var promise = PromiseCreateAndSet(-1, r);
var promise = PromiseCreateAndSet(kRejected, r);
// The debug event for this would always be an uncaught promise reject,
// which is usually simply noise. Do not trigger that debug event.
%PromiseRejectEvent(promise, r, false);
......@@ -268,10 +293,11 @@ function PromiseRejected(r) {
}
}
// ES#sec-promise.prototype.then
// Promise.prototype.then ( onFulfilled, onRejected )
// Multi-unwrapped chaining with thenable coercion.
function PromiseThen(onResolve, onReject) {
var status = GET_PRIVATE(this, promiseStatusSymbol);
var status = GET_PRIVATE(this, promiseStateSymbol);
if (IS_UNDEFINED(status)) {
throw MakeTypeError(kNotAPromise, this);
}
......@@ -281,24 +307,25 @@ function PromiseThen(onResolve, onReject) {
onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler;
var deferred = NewPromiseCapability(constructor);
switch (status) {
case 0: // Pending
GET_PRIVATE(this, promiseOnResolveSymbol).push(onResolve, deferred);
GET_PRIVATE(this, promiseOnRejectSymbol).push(onReject, deferred);
case kPending:
GET_PRIVATE(this, promiseFulfillReactionsSymbol).push(onResolve,
deferred);
GET_PRIVATE(this, promiseRejectReactionsSymbol).push(onReject, deferred);
break;
case +1: // Resolved
PromiseEnqueue(GET_PRIVATE(this, promiseValueSymbol),
case kFulfilled:
PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol),
[onResolve, deferred],
+1);
kFulfilled);
break;
case -1: // Rejected
case kRejected:
if (!HAS_DEFINED_PRIVATE(this, promiseHasHandlerSymbol)) {
// Promise has already been rejected, but had no handler.
// Revoke previously triggered reject event.
%PromiseRevokeReject(this);
}
PromiseEnqueue(GET_PRIVATE(this, promiseValueSymbol),
PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol),
[onReject, deferred],
-1);
kRejected);
break;
}
// Mark this promise as having handler.
......@@ -306,21 +333,26 @@ function PromiseThen(onResolve, onReject) {
return deferred.promise;
}
// Unspecified V8-specific legacy function
// Chain is left around for now as an alias for then
function PromiseChain(onResolve, onReject) {
%IncrementUseCounter(kPromiseChain);
return %_Call(PromiseThen, this, onResolve, onReject);
}
// ES#sec-promise.prototype.catch
// Promise.prototype.catch ( onRejected )
function PromiseCatch(onReject) {
return this.then(UNDEFINED, onReject);
}
// Combinators.
function PromiseCast(x) {
// ES#sec-promise.resolve
// Promise.resolve ( x )
function PromiseResolve(x) {
if (!IS_RECEIVER(this)) {
throw MakeTypeError(kCalledOnNonObject, PromiseCast);
throw MakeTypeError(kCalledOnNonObject, PromiseResolve);
}
if (IsPromise(x) && x.constructor === this) return x;
......@@ -329,6 +361,8 @@ function PromiseCast(x) {
return promiseCapability.promise;
}
// ES#sec-promise.all
// Promise.all ( iterable )
function PromiseAll(iterable) {
if (!IS_RECEIVER(this)) {
throw MakeTypeError(kCalledOnNonObject, "Promise.all");
......@@ -378,6 +412,8 @@ function PromiseAll(iterable) {
return deferred.promise;
}
// ES#sec-promise.race
// Promise.race ( iterable )
function PromiseRace(iterable) {
if (!IS_RECEIVER(this)) {
throw MakeTypeError(kCalledOnNonObject, PromiseRace);
......@@ -399,7 +435,7 @@ function PromiseRace(iterable) {
// Utility for debugger
function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
var queue = GET_PRIVATE(promise, promiseOnRejectSymbol);
var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol);
if (IS_UNDEFINED(queue)) return false;
for (var i = 0; i < queue.length; i += 2) {
var handler = queue[i];
......@@ -432,10 +468,10 @@ function PromiseHasUserDefinedRejectHandler() {
DONT_ENUM | READ_ONLY);
utils.InstallFunctions(GlobalPromise, DONT_ENUM, [
"reject", PromiseRejected,
"reject", PromiseReject,
"all", PromiseAll,
"race", PromiseRace,
"resolve", PromiseCast
"resolve", PromiseResolve
]);
utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [
......@@ -448,8 +484,8 @@ utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [
"promise_chain", PromiseChain,
"promise_create", PromiseCreate,
"promise_has_user_defined_reject_handler", PromiseHasUserDefinedRejectHandler,
"promise_reject", PromiseReject,
"promise_resolve", PromiseResolve,
"promise_reject", RejectPromise,
"promise_resolve", FulfillPromise,
"promise_then", PromiseThen,
]);
......@@ -458,18 +494,18 @@ utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [
// promise without having to hold on to those closures forever.
utils.InstallFunctions(extrasUtils, 0, [
"createPromise", PromiseCreate,
"resolvePromise", PromiseResolve,
"rejectPromise", PromiseReject
"resolvePromise", FulfillPromise,
"rejectPromise", RejectPromise
]);
// TODO(v8:4567): Allow experimental natives to remove function prototype
[PromiseChain, PromiseDeferred, PromiseResolved].forEach(
[PromiseChain, PromiseDefer, PromiseAccept].forEach(
fn => %FunctionRemovePrototype(fn));
utils.Export(function(to) {
to.PromiseChain = PromiseChain;
to.PromiseDeferred = PromiseDeferred;
to.PromiseResolved = PromiseResolved;
to.PromiseDefer = PromiseDefer;
to.PromiseAccept = PromiseAccept;
});
})
......@@ -595,7 +595,7 @@ bool Object::IsPromise(Handle<Object> object) {
auto isolate = js_object->GetIsolate();
// TODO(dcarney): this should just be read from the symbol registry so as not
// to be context dependent.
auto key = isolate->factory()->promise_status_symbol();
auto key = isolate->factory()->promise_state_symbol();
// Shouldn't be possible to throw here.
return JSObject::HasRealNamedProperty(js_object, key).FromJust();
}
......
......@@ -244,7 +244,7 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
Handle<JSObject> promise = Handle<JSObject>::cast(object);
Handle<Object> status_obj =
DebugGetProperty(promise, isolate->factory()->promise_status_symbol());
DebugGetProperty(promise, isolate->factory()->promise_state_symbol());
RUNTIME_ASSERT_HANDLIFIED(status_obj->IsSmi(), JSArray);
const char* status = "rejected";
int status_val = Handle<Smi>::cast(status_obj)->value();
......@@ -267,7 +267,7 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
result->set(1, *status_str);
Handle<Object> value_obj =
DebugGetProperty(promise, isolate->factory()->promise_value_symbol());
DebugGetProperty(promise, isolate->factory()->promise_result_symbol());
Handle<String> promise_value =
factory->NewStringFromAsciiChecked("[[PromiseValue]]");
result->set(2, *promise_value);
......
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